from peewee import TextField from playhouse.shortcuts import model_to_dict from . import db, models_reference class Crud_DB: def __init__(self, table_name, select=None, filters=None, pagination=250): self.table_model = models_reference[table_name] self.table_pk = self.table_model._meta.primary_key self.table_fields = list(self.table_model._meta.fields.keys()) self.pagination = pagination self.default_filters = {} self.sorting = {} self.filters = {} if filters is None: filters = {} for column_name, filter in filters.items(): self.filter(column_name, filter, filter_storage=self.default_filters) @db.connection_context() @db.atomic() def commit(self, data, deleted_rows=None): if deleted_rows is not None: if hasattr(self.table_model, "crud_delete"): deleted = self.table_model.crud_delete(deleted_rows) else: deleted = self.table_model.delete().where(self.table_pk << deleted_rows).execute() if deleted != len(deleted_rows): raise AssertionError(f"deleted {deleted} rows instead of the expected {len(deleted_rows)}") # SQLITE DOES NOT SUPPORT UPDATE, ONLY REPLACE complete_data = [] for rn, row in enumerate(data): pk = row[self.table_pk.name] try: if pk is not None: raise self.table_model.DoesNotExist() db_row.update(model_to_dict(self.table_model.get_by_id(pk))) except self.table_model.DoesNotExist: db_row = row complete_data.append(db_row) if hasattr(self.table_model, "crud_update"): self.table_model.crud_update(complete_data) else: self.table_model.insert_many(complete_data).on_conflict_replace().execute() def revert(self): self.sorting.clear() self.filters.clear() @db.connection_context() def get(self, page=0): if self.table_model._meta.composite_key: raise NotImplementedError("need to implement composite_key") if hasattr(self.table_model, "crud_select"): query = self.table_model.crud_select() else: query = self.table_model.select() if len(self.default_filters) + len(self.filters) > 0: query = query.where(*self.default_filters.values(), *self.filters.values()) if len(self.sorting) > 0: query = query.order_by(*self.sorting.values()) total_count = query.count() last_page = int(total_count / self.pagination) if page < 0: page = last_page - page + 1 page = min(max(page, 0), last_page) self.page = page if self.pagination is not False: query = query.paginate(self.page + 1, self.pagination) self.data = query.dicts().execute() self.shown_keys = [r[self.table_pk.name] for r in self.data] return self.data, total_count, self.page, last_page def sort(self, column_name, is_ascending=None, sorting_storage=None): if sorting_storage is None: sorting_storage = self.sorting if column_name is not None: if is_ascending is None: sorting_storage.pop(column_name, None) else: field = self.table_model._meta.fields[column_name] if not is_ascending: field = -field sorting_storage[column_name] = field else: sorting_storage.clear() def filter(self, column_name, filter, filter_storage=None): # only contains/equality filter if filter_storage is None: filter_storage = self.filters if filter is None or filter == "": if column_name in self.filters: filter_storage.pop(column_name, None) else: field = self.table_model._meta.fields[column_name] if type(field) is TextField: filter_storage[column_name] = field.contains(filter) else: filter_storage[column_name] = field == filter