diff --git a/crudkit/api/flask_api.py b/crudkit/api/flask_api.py index ddb77a9..46832c2 100644 --- a/crudkit/api/flask_api.py +++ b/crudkit/api/flask_api.py @@ -10,7 +10,7 @@ def generate_crud_blueprint(model, service): @bp.get('/') def get_item(id): - item = service.get(id) + item = service.get(id, request.args) return jsonify(item.as_dict()) @bp.post('/') diff --git a/crudkit/core/service.py b/crudkit/core/service.py index 23c096e..2e1c400 100644 --- a/crudkit/core/service.py +++ b/crudkit/core/service.py @@ -44,12 +44,63 @@ class CRUDService(Generic[T]): cols.append(col) return cols or [text("1")] - def get(self, id: int, include_deleted: bool = False) -> T | None: + def get(self, id: int, params=None) -> T | None: + print(f"I AM GETTING A THING! A THINGS! {params}") query, root_alias = self.get_query() + + include_deleted = False + root_fields = [] + root_field_names = {} + rel_field_names = {} + + spec = CRUDSpec(self.model, params or {}, root_alias) + if params: + if self.supports_soft_delete: + include_deleted = _is_truthy(params.get('include_deleted')) if self.supports_soft_delete and not include_deleted: query = query.filter(getattr(root_alias, "is_deleted") == False) query = query.filter(getattr(root_alias, "id") == id) + + spec.parse_includes() + + for parent_alias, relationship_attr, target_alias in spec.get_join_paths(): + query = query.join( + target_alias, + relationship_attr.of_type(target_alias), + isouter=True + ) + + if params: + root_fields, rel_field_names, root_field_names = spec.parse_fields() + + only_cols = [c for c in root_fields if isinstance(c, InstrumentedAttribute)] + if only_cols: + query = query.options(Load(root_alias).load_only(*only_cols)) + + for eager in spec.get_eager_loads(root_alias, fields_map=rel_field_names): + query = query.options(eager) + obj = query.first() + + proj = [] + if root_field_names: + proj.extend(root_field_names) + if root_fields: + proj.extend(c.key for c in root_fields) + for path, names in (rel_field_names or {}).items(): + prefix = ".".join(path) + for n in names: + proj.append(f"{prefix}.{n}") + + if proj and "id" not in proj and hasattr(self.model, "id"): + proj.insert(0, "id") + + if proj: + try: + setattr(obj, "__crudkit_projection__", tuple(proj)) + except Exception: + pass + return obj or None def list(self, params=None) -> list[T]: