def test_source(self): source = unittest.mock.MagicMock() relations.SOURCES["a"] = source self.assertEqual(relations.source("a"), source)
def load(self, name, file_name): """ Load a file from a source """ source = relations.source(name) return source.load( f"{self.directory}/{source.name}/{source.KIND}/{file_name}")
def update(self, *args, **kwargs): """ update the model """ if self._action not in ["update", "retrieve"]: raise ModelError(self, f"cannot update during {self._action}") return relations.source(self.SOURCE).update(self, *args, **kwargs)
def retrieve(self, verify=True, *args, **kwargs): """ retrieve the model """ if self._action != "retrieve": raise ModelError(self, f"cannot retrieve during {self._action}") return relations.source(self.SOURCE).retrieve(self, verify, *args, **kwargs)
def count(self, *args, **kwargs): """ count the models """ if self._action not in ["update", "retrieve"]: raise ModelError(self, f"cannot count during {self._action}") return relations.source(self.SOURCE).count(self, *args, **kwargs)
def apply(self, name): """ Applies source definitions and migrations based on a source name """ source = relations.source(name) source_path = f"{self.directory}/{source.name}/{source.KIND}" return source.migrate(source_path)
def list(self, name): """ List out the migrations pairs for a source """ source = relations.source(name) source_path = f"{self.directory}/{source.name}/{source.KIND}" return source.list(source_path)
def delete(self, *args, **kwargs): """ delete the model """ if self._action not in ["update", "retrieve"]: raise ModelError(self, f"cannot delete during {self._action}") if self._action == "retrieve" and self._mode == "one": self.retrieve() return relations.source(self.SOURCE).delete(self, *args, **kwargs)
def convert(self, name): """ Converts definitions and migrations to source definitions and migrations based on a source name """ source = relations.source(name) source_path = f"{self.directory}/{source.name}/{source.KIND}" os.makedirs(source_path, exist_ok=True) for file_path in glob.glob(f"{self.directory}/*.json"): file_name = file_path.split("/")[-1] if file_name.startswith("definition"): source.definition(file_path, source_path) elif file_name.startswith("migration"): source.migration(file_path, source_path)
def query(self, action=None, *args, **kwargs): """ get the current query for the model """ if self._action == "create": return relations.source(self.SOURCE).create_query(self, *args, **kwargs).bind(self) if self._action == "retrieve" and action == "count": return relations.source(self.SOURCE).count_query(self, *args, **kwargs).bind(self) if self._action == "retrieve" and action == "titles": return relations.source(self.SOURCE).titles_query(self, *args, **kwargs).bind(self) if action == "update" or (action is None and self._action == "update"): return relations.source(self.SOURCE).update_query(self, *args, **kwargs).bind(self) if action == "delete": return relations.source(self.SOURCE).delete_query(self, *args, **kwargs).bind(self) return relations.source(self.SOURCE).retrieve_query(self, *args, **kwargs).bind(self)
def thy(cls, self=None): """ Base identity to be known without instantiating the class """ # If self wasn't sent, we're just providing a shell of an instance if self is None: self = ModelIdentity() self.__dict__.update(cls.__dict__) # Use TITLE, NAME if set, else use class name setattr(self, 'TITLE', cls.TITLE or cls.__name__) setattr(self, 'NAME', cls.NAME or cls.underscore(self.TITLE)) # Derive all the fields fields = relations.Record() for name, attribute in cls.__dict__.items(): if name.startswith('_') or name != name.lower(): continue # pragma: no cover if attribute in [bool, int, float, str, set, list, dict]: field = relations.Field(attribute) elif callable(attribute): field = relations.Field(type(attribute()), default=attribute) elif isinstance(attribute, set): field = relations.Field(set, options=sorted(attribute)) elif isinstance(attribute, tuple) and attribute and isinstance(attribute[0], str): field = relations.Field(set, options=list(attribute)) elif isinstance(attribute, list): field = relations.Field(type(attribute[0]), default=attribute[0], options=attribute) elif isinstance(attribute, tuple): field = relations.Field(*attribute) elif isinstance(attribute, dict): field = relations.Field(**attribute) elif isinstance(attribute, relations.Field): field = attribute else: continue # pragma: no cover field.name = name fields.append(field) setattr(self, '_fields', fields) # Determine the _id field name if cls.ID is not None: setattr(self, '_id', self._field_name(cls.ID)) # Figure out the titles titles = self.TITLES if not titles: titles = [] for field in self._fields._order: if self._id == field.name: continue if field.kind in (int, str): titles.append(field.name) if field.kind == str and field._none is None: field.none = False if field.kind == str: break if isinstance(titles, str): titles = [titles] self._titles = titles for field in self._titles: if field.split('__', 1)[0] not in self._fields: raise ModelError(self, f"cannot find field {field} from titles") # Figure out the list if self.LIST: self._list = self.LIST else: self._list = list(self._titles) if self._id and self._id not in self._list: self._list.insert(0, self._id) if isinstance(self._list, str): self._list = [self._list] # Make sure all the list checks out for field in self._list: if field.split('__', 1)[0] not in self._fields: raise ModelError(self, f"cannot find field {field} from list") # Figure out unique indexes unique = self.UNIQUE if unique is None: unique = self._titles elif not unique: unique = {} if isinstance(unique, str): unique = [unique] if isinstance(unique, list): unique = { "-".join(unique): unique } if isinstance(unique, dict): self._unique = unique # Make sure all the unique indexes check out for unique in self._unique: for field in self._unique[unique]: if field.split('__')[0] not in self._fields: raise ModelError(self, f"cannot find field {field} from unique {unique}") index = self.INDEX or {} if isinstance(index, str): index = [index] if isinstance(index, list): index = { "-".join(index): index } if isinstance(index, dict): self._index = index # Make sure all the indexes check out for index in self._index: for field in self._index[index]: if field.split('__')[0] not in self._fields: raise ModelError(self, f"cannot find field {field} from index {index}") # Make sure all inject fields reference actual fields that are lists or dicts for field, inject in [(field, field.inject.split('__')[0]) for field in self._fields._order if field.inject]: if inject not in self._fields: raise relations.FieldError(field, f"cannot find field {inject} from inject {field.inject}") if self._fields._names[inject].kind not in [list, dict]: raise relations.FieldError(self, f"field {inject} not list or dict from inject {field.inject}") # Determine default sort order (if desired) if self.ORDER: self._order = self._ordering(self.ORDER) elif self.ORDER is None and len(self._unique) == 1: self._order = self._ordering(list(self._unique.values())[0]) else: self._order = [] # Initialize relation models self.PARENTS = cls.PARENTS or {} self.CHILDREN = cls.CHILDREN or {} self.SISTERS = cls.SISTERS or {} self.BROTHERS = cls.BROTHERS or {} # Have the the source do whatever it needs to self.SOURCE = cls.SOURCE if relations.source(self.SOURCE) is not None: relations.source(self.SOURCE).init(self) return self
def define(cls, *args, **kwargs): """ define the model """ return relations.source(cls.SOURCE).define(cls.thy().define(), *args, **kwargs)
def test___new__(self): source = relations.Source("testunit", reverse=True) self.assertEqual(relations.source("testunit"), source) self.assertTrue(source.reverse)