Skip to main content

KORM Protocol v2 — JSON request/response protocol for dynamic database operations (reference implementation)

Project description

korm

Reference Python implementation of the KORM Protocol v2 — a JSON request/response protocol for dynamic database operations against PostgreSQL, MySQL/MariaDB, and SQLite.

A KORM server receives a JSON request naming a model and an action, executes it via SQLAlchemy Core 2.x, and returns a uniform response envelope. The protocol is fully describable by JSON Schema, so MCP tools, OpenAPI docs, and typed clients can be generated from one source.

import korm

db = korm.initialize_korm(url="postgresql+asyncpg://...", schema="korm.schema.json")

result = await db.process({          # async, v2-native
    "korm": 2,
    "action": "list",
    "model": "users",
    "where": {
        "is_active": True,
        "age": {"gte": 18, "lt": 65},
        "email": {"endsWith": "@example.com"},
    },
    "include": {"profile": True, "posts": {"limit": 5, "orderBy": "-created_at"}},
    "orderBy": "-created_at",
    "limit": 20,
})

result = db.process_sync(request_dict)   # sync engines

Every action returns the same envelope:

{
  "ok": true, "action": "list", "model": "users",
  "data": [ ... ],
  "meta": { "protocol": 2, "count": 20, "limit": 20, "offset": 0, "durationMs": 4 },
  "error": null
}

Features (spec v2.0)

  • Actions: create, list, show, update, delete, restore, upsert, replace, sync, aggregate, batch (optionally atomic, with $ref chaining).
  • Structured where grammar — no stringly-typed operator DSL: eq ne gt gte lt lte in notIn between notBetween like ilike contains startsWith endsWith is not, plus nestable and / or / not boolean trees with fully parenthesized SQL.
  • Safe by construction — no raw SQL fragments anywhere; all identifiers validated against the schema; contains/startsWith/endsWith escape % and _.
  • Pagination — offset mode and opaque keyset cursors (send "cursor": null for the first page, follow meta.nextCursor); optional HMAC-signed cursors via cursor_secret.
  • RelationshasOne / hasMany / belongsTo includes with per-relation select/where/orderBy/limit, nested dotted paths, and validated explicit joins. manyToMany is accepted in schemas (syntax v2.0) and executes from v2.1.
  • Aggregatescount sum avg min max, groupBy, having, and JSON expression trees ({"add": ["salary", "bonus"]}) replacing v1's sumFormula strings.
  • Soft delete — automatic deleted_at IS NULL filtering, withDeleted / onlyDeleted / hardDelete options, first-class restore.
  • HooksbeforeValidate, afterValidate, before<Action>, after<Action>, onError; sync or async; may mutate the request, short-circuit, or raise.
  • Policy layer — per-role model/action allowlists, default_deny production mode, mandatory where-scopes for tenant isolation ({"org_id": "$ctx.orgId"}).
  • v1 compatibility — a deterministic up-converter (on by default, compat_v1) accepts v1 operator strings (">=18", "><18,65", "[]a,b", "!x", "%like%", Or: keys, count/sum actions, string join conditions) and down-converts responses (bare count numbers, bare show objects) for v1 clients. strict_v2: true turns it off.
  • Errors are codes, not prose: VALIDATION_FAILED, UNKNOWN_MODEL, UNKNOWN_COLUMN, UNKNOWN_RELATION, UNKNOWN_ACTION, NOT_FOUND, CONFLICT, FK_VIOLATION, POLICY_DENIED, LIMIT_EXCEEDED, TRANSACTION_FAILED, BATCH_ROLLED_BACK, UNSUPPORTED_ON_ENGINE, INTERNAL — with structured per-field details.

Install

pip install korm                 # SQLite via stdlib driver
pip install korm[postgres]       # psycopg + asyncpg
pip install korm[mysql]          # PyMySQL + aiomysql
pip install korm[fastapi]        # HTTP router
pip install korm[mcp]            # MCP server

Schema (korm.schema.json)

One file drives DDL sync, request validation, and generated types:

{
  "kormSchema": 2,
  "models": {
    "users": {
      "table": "users",
      "primaryKey": ["id"],
      "softDelete": { "column": "deleted_at" },
      "timestamps": { "createdAt": "created_at", "updatedAt": "updated_at" },
      "columns": {
        "id":       { "type": "increments" },
        "username": { "type": "string", "length": 80, "unique": true, "required": true },
        "email":    { "type": "string", "format": "email", "required": true }
      },
      "relations": {
        "profile": { "type": "hasOne", "model": "user_profiles", "foreignKey": "user_id" },
        "posts":   { "type": "hasMany", "model": "posts", "foreignKey": "author_id" }
      }
    }
  }
}

FastAPI

from fastapi import FastAPI
from korm.fastapi import crud_router

app = FastAPI()
app.include_router(crud_router(db), prefix="/api")
# POST /api/{model}/crud

CLI

korm init                    # scaffold korm.schema.json
korm generate-schema --url sqlite:///app.db      # introspect a live database
korm sync  --url ... --schema korm.schema.json   # dev-time DDL sync
korm diff  --url ... --schema korm.schema.json   # migration skeleton
korm serve-mcp --url ... --schema ...            # per-model MCP tools over stdio

sync is a dev/prototyping tool; for production use migration tools (Alembic/Knex) generated from korm diff output.

Development

pip install -e ".[dev]"
pytest

Status

Implements KORM Protocol v2 draft 0.2 (including v2.1 features: manyToMany include execution and column-level policy allowlists). meta.prevCursor is currently always null (forward-only keyset).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

korm-2.0.0a4.tar.gz (4.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

korm-2.0.0a4-py3-none-any.whl (49.1 kB view details)

Uploaded Python 3

File details

Details for the file korm-2.0.0a4.tar.gz.

File metadata

  • Download URL: korm-2.0.0a4.tar.gz
  • Upload date:
  • Size: 4.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for korm-2.0.0a4.tar.gz
Algorithm Hash digest
SHA256 b9cc63acd92264fa66a1c1038c75e80dae96cc7a0764cefde3e2d05f1bfc8df6
MD5 2934f7ad9bbaf2e01fd9ca44cf8a9778
BLAKE2b-256 86e8020778702d6acd79d213122e159c6b81d7f601ebe8ae30eee033b83bdb71

See more details on using hashes here.

File details

Details for the file korm-2.0.0a4-py3-none-any.whl.

File metadata

  • Download URL: korm-2.0.0a4-py3-none-any.whl
  • Upload date:
  • Size: 49.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for korm-2.0.0a4-py3-none-any.whl
Algorithm Hash digest
SHA256 f004403c2dcce1c27b34b73927b459e64689518a41d6fde5cc2f25f59f8de135
MD5 21059830e61a3df4d230a320284eb0c1
BLAKE2b-256 a1c3ccb165e3166c19892fec1edcf2cbe22a3bc220480e98e8fe2c76df937076

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page