def update_query(self, model): """ Create the update query """ query = self.UPDATE(self.TABLE_NAME(model.STORE, schema=model.SCHEMA)) if model._action == "retrieve" and model._record._action == "update": self.update_record(model._record, model._record.mass({}), query) elif model._id: if model._mode == "many": raise relations.ModelError(model, "only one update query at a time") self.update_record(model._record, model._record.update({}), query) query.WHERE(**{model._fields._names[model._id].store: model[model._id]}) else: raise relations.ModelError(model, "nothing to update from") self.retrieve_record(model._record, query) return query
def retrieve(self, model, verify=True, query=None): """ Executes the retrieve """ cursor = self.connection.cursor() if query is None: query = self.retrieve_query(model) query.generate() cursor.execute(query.sql, tuple(query.args)) if model._mode == "one" and cursor.rowcount > 1: raise relations.ModelError(model, "more than one retrieved") if model._mode == "one" and model._role != "child": if cursor.rowcount < 1: if verify: raise relations.ModelError(model, "none retrieved") return None model._record = model._build("update", _read=self.values_retrieve( model, cursor.fetchone())) else: model._models = [] while len(model._models) < cursor.rowcount: model._models.append( model.__class__( _read=self.values_retrieve(model, cursor.fetchone()))) if model._limit is not None: model.overflow = model.overflow or len( model._models) >= model._limit model._record = None model._action = "update" cursor.close() return model
def retrieve(self, model, verify=True): """ Executes the retrieve """ model._collate() body = {"filter": {}} self.retrieve_record(model._record, body["filter"]) if model._like: body["filter"]["like"] = model._like if model._sort: body["sort"] = model._sort if model._limit is not None: body["limit"] = {"per_page": model._limit} if model._offset: body["limit"]["start"] = model._offset matches = self.result(model, model.PLURAL, self.session.get(f"{self.url}/{model.ENDPOINT}", json=body)) if model._mode == "one" and len(matches) > 1: raise relations.ModelError(model, "more than one retrieved") if model._mode == "one" and model._role != "child": if len(matches) < 1: if verify: raise relations.ModelError(model, "none retrieved") return None model._record = model._build("update", _read=matches[0]) else: model._models = [] for match in matches: model._models.append(model.__class__(_read=match)) model._record = None model._action = "update" return model
def relative_field(cls, model, relative): """ Returns the name of the relative field, based on the relative name """ # Check for the standard convention standard = f"{model.NAME}_id" if standard in relative._fields: return standard # Check to see if we're using the relative.ID, model.ID, model.relative_ID convention (diffent name for ID) model_id = model._field_name(model.ID) simple = f"{model.NAME}_{model_id}" if simple in relative._fields: return simple # Check to see if we're using the relative.relative_id, model.model_id, model.relative_id patten if model_id in relative._fields and (cls.SAME or model_id != relative._field_name(relative.ID)): return model_id raise relations.ModelError(model, f"cannot determine field for {model.NAME} in {relative.NAME}")
def delete(self, model): """ Executes the delete """ criteria = {} if model._action == "retrieve": self.retrieve_record(model._record, criteria) elif model._id: criterion = f"{model._id}__in" criteria[criterion] = [] for deleting in model._each(): criteria[criterion].append(deleting[model._id]) deleting._action = "create" model._action = "create" else: raise relations.ModelError(model, "nothing to delete from") return self.result(model, "deleted", self.session.delete(f"{self.url}/{model.ENDPOINT}", json={"filter": criteria}))
def result(model, key, response): """ Checks a response and returns the result """ if response.status_code >= 400: raise relations.ModelError( model, response.json().get("message", "API Error")) return response.json()[key]
def model_retrieve(self, model, verify=True): """ Executes the retrieve """ model._collate() criteria = {} self.record_retrieve(model._record, criteria) matches = self.result( model, model.PLURAL, self.session.get(f"{self.url}/{model.ENDPOINT}", json={"filter": criteria})) if model._mode == "one" and len(matches) > 1: raise relations.ModelError(model, "more than one retrieved") if model._mode == "one" and model._role != "child": if len(matches) < 1: if verify: raise relations.ModelError(model, "none retrieved") return None model._record = model._build("update", _read=matches[0]) else: model._models = [] for match in matches: model._models.append(model.__class__(_read=match)) model._record = None model._action = "update" return model
def result(model, key, response): """ Checks a response and returns the result """ if response.status_code >= 400: raise relations.ModelError(model, response.json().get("message", "API Error")) body = response.json() if "overflow" in body: model.overflow = model.overflow or body["overflow"] return body[key]
def model_update(self, model): """ Executes the update """ # If the overall model is retrieving and the record has values set updated = 0 if model._action == "retrieve" and model._record._action == "update": criteria = {} self.record_retrieve(model._record, criteria) values = {} self.record_update(model._record, values, changed=True) updated += self.result( model, "updated", self.session.patch(f"{self.url}/{model.ENDPOINT}", json={ "filter": criteria, model.PLURAL: values })) elif model._id: for updating in model._each("update"): values = {} self.record_update(updating._record, values) updated += self.result( updating, "updated", self.session.patch( f"{self.url}/{model.ENDPOINT}/{updating[model._id]}", json={model.SINGULAR: values})) for parent_child in updating.CHILDREN: if updating._children.get(parent_child): updating._children[parent_child].create().update() else: raise relations.ModelError(model, "nothing to update from") return updated
def create_query(self, model): """ Get query for what's being inserted """ fields = [field.store for field in model._fields._order if not field.auto and not field.inject] query = self.INSERT(self.TABLE_NAME(model.STORE, schema=model.SCHEMA), *fields) if not model._bulk and model._id is not None and model._fields._names[model._id].auto: if model._mode == "many": raise relations.ModelError(model, "only one create query at a time") return copy.deepcopy(query).VALUES(**model._record.create({})).bind(model) for creating in model._each("create"): query.VALUES(**creating._record.create({})) return query
def update(self, model, query=None): """ Executes the update """ cursor = self.connection.cursor() updated = 0 # If the overall model is retrieving and the record has values set if model._action == "retrieve" and model._record._action == "update": update_query = query or self.update_query(model) update_query.generate() cursor.execute(update_query.sql, update_query.args) updated = cursor.rowcount elif model._id: for updating in model._each("update"): update_query = query or self.update_query(updating) if update_query.SET: update_query.generate() cursor.execute(update_query.sql, update_query.args) for parent_child in updating.CHILDREN: if updating._children.get(parent_child): updating._children[parent_child].create().update() updated += cursor.rowcount else: raise relations.ModelError(model, "nothing to update from") return updated
def delete_query(self, model): """ Create the update query """ query = self.DELETE(self.TABLE_NAME(model.STORE, schema=model.SCHEMA)) if model._action == "retrieve": self.retrieve_record(model._record, query) elif model._id: ids = [] store = model._fields._names[model._id].store for deleting in model._each(): ids.append(deleting[model._id]) query.WHERE(**{f"{store}__in": ids}) else: raise relations.ModelError(model, "nothing to delete from") return query
def broken(): raise relations.ModelError(Simple(), "broken query")
def missing(): raise relations.ModelError(Simple(), "none retrieved")
def test___str__(self): error = relations.ModelError(Whoops(), "adaisy") self.assertEqual(str(error), "whoops: adaisy")
def test___init__(self): error = relations.ModelError("unittest", "oops") self.assertEqual(error.model, "unittest") self.assertEqual(error.message, "oops")