from flask import Blueprint, request, jsonify, abort from sqlalchemy.orm import scoped_session from .dsl import QuerySpec from .service import CrudService from .eager import default_eager_policy from .serialize import serialize def make_blueprint(db_session_factory, registry): bp = Blueprint("crud", __name__) def session(): return scoped_session(db_session_factory)() @bp.get("//list") def list_items(model): Model = registry.get(model) or abort(404) spec = QuerySpec( filters=_parse_filters(request.args), order_by=request.args.getlist("sort"), page=request.args.get("page", type=int), per_page=request.args.get("per_page", type=int), expand=request.args.getlist("expand"), fields=request.args.get("fields", type=lambda s: [x.strip() for x in s.split(",")] if s else None), ) s = session(); svc = CrudService(s, default_eager_policy) rows, total = svc.list(Model, spec) data = [serialize(r, fields=spec.fields, expand=spec.expand) for r in rows] return jsonify({"data": data, "total": total}) @bp.post("/") def create_item(model): Model = registry.get(model) or abort(404) payload = request.get_json() or {} s = session(); svc = CrudService(s, default_eager_policy) obj = svc.create(Model, payload) s.commit() return jsonify(serialize(obj)), 201 @bp.get("//") def read_item(model, id): Model = registry.get(model) or abort(404) spec = QuerySpec(expand=request.args.getlist("expand"), fields=request.args.get("fields", type=lambda s: s.split(","))) s = session(); svc = CrudService(s, default_eager_policy) obj = svc.get(Model, id, spec) or abort(404) return jsonify(serialize(obj, fields=spec.fields, expand=spec.expand)) @bp.patch("//") def update_item(model, id): Model = registry.get(model) or abort(404) s = session(); svc = CrudService(s, default_eager_policy) obj = svc.get(Model, id, QuerySpec()) or abort(404) payload = request.get_json() or {} svc.update(obj, payload) s.commit() return jsonify(serialize(obj)) @bp.delete("//") def delete_item(model, id): Model = registry.get(model) or abort(404) s = session(); svc = CrudService(s, default_eager_policy) obj = svc.get(Model, id, QuerySpec()) or abort(404) svc.soft_delete(obj) s.commit() return jsonify({"status": "deleted"}) @bp.post("///undelete") def undelete_item(model, id): Model = registry.get(model) or abort(404) s = session(); svc = CrudService(s, default_eager_policy) obj = svc.get(Model, id, QuerySpec()) or abort(404) svc.undelete(obj) s.commit() return jsonify({"status": "restored"}) return bp def _parse_filters(args): out = {} for k, v in args.items(): if k in {"page", "per_page", "sort", "expand", "fields"}: continue out[k] = v return out