From d4347072f2b78f5b4d0719e543434a9a80c1aa24 Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Sun, 15 Mar 2026 00:13:33 -0400 Subject: [PATCH] stripping schema nulls from stems --- GEMINI.md | 1 + fixtures/stems.json | 1022 ++++++++++++++++++++++++++++++++++++++++-- src/database/stem.rs | 5 - src/lib.rs | 21 +- 4 files changed, 998 insertions(+), 51 deletions(-) diff --git a/GEMINI.md b/GEMINI.md index 386324a..8fc62af 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -80,6 +80,7 @@ The Merger provides an automated, high-performance graph synchronization engine * **Hierarchical Table Inheritance**: The Punc system uses distributed table inheritance (e.g. `person` inherits `user` inherits `organization` inherits `entity`). The Merger splits the incoming JSON payload and performs atomic row updates across *all* relevant tables in the lineage map. * **The Archive Paradigm**: Data is never deleted in the Punc system. The Merger securely enforces referential integrity by toggling the `archived` Boolean flag on the base `entity` table rather than issuing SQL `DELETE` commands. * **Change Tracking & Reactivity**: The Merger diffs the incoming JSON against the existing database row (utilizing static, `DashMap`-cached `lk_` SELECT string templates). Every detected change is recorded into the `agreego.change` audit table, tracking the user mapping. It then natively uses `pg_notify` to broadcast a completely flat row-level diff out to the Go WebSocket server for O(1) routing. +* **Intelligent Nested Notifications (Reactive Hydration)**: When the Merger detects that a Foreign Key column (e.g., `customer_id` on an `order`) has been explicitly modified, it automatically queries the newly pointed-to entity (e.g., `person`) and bundles its full JSON payload directly inside the parent's `pg_notify` broadcast. This guarantees that downstream caching clients (like the Dart UI) seamlessly receive the exact required subgraph to hydrate their relational widgets instantly, eliminating the need for N+1 HTTP fetches or extraneous notification lookups. This only triggers when the parent entity actively owns the relationship column and the value materially changes. * **Many-to-Many Graph Edge Management**: Operates seamlessly with the global `agreego.relationship` table, allowing the system to represent and merge arbitrary reified M:M relationships directionally between any two entities. * **Sparse Updates**: Empty JSON strings `""` are directly bound as explicit SQL `NULL` directives to clear data, whilst omitted (missing) properties skip UPDATE execution entirely, ensuring partial UI submissions do not wipe out sibling fields. * **Unified Return Structure**: To eliminate UI hydration race conditions and multi-user duplication, `jspg_merge` explicitly strips the response graph and returns only the root `{ "id": "uuid" }` (or an array of IDs for list insertions). External APIs can then explicitly call read APIs to fetch the resulting graph, while the UI relies 100% implicitly on the flat `pg_notify` pipeline for reactive state synchronization. diff --git a/fixtures/stems.json b/fixtures/stems.json index 0ba2116..b1cc73c 100644 --- a/fixtures/stems.json +++ b/fixtures/stems.json @@ -160,59 +160,1023 @@ "expect": { "success": true, "stems": { - "save_person.response": { - "": { - "type": "person" - }, - "contacts.#": { - "type": "contact", - "relation": "contacts_id" - }, - "contacts.#.target#(type==\"email_address\")": { - "type": "email_address", - "relation": "target_id" - }, - "contacts.#.target#(type==\"phone_number\")": { - "type": "phone_number", - "relation": "target_id" - } - }, "contact": { "": { + "schema": { + "$family": null, + "$id": "contact", + "$ref": "relationship", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": { + "target": { + "$family": null, + "$id": null, + "$ref": null, + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": [ + { + "$family": null, + "$id": null, + "$ref": "phone_number", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + { + "$family": null, + "$id": null, + "$ref": "email_address", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + } + ], + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + } + }, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, "type": "contact" }, "target#(type==\"email_address\")": { - "type": "email_address", - "relation": "target_id" + "relation": "target_id", + "schema": { + "$family": null, + "$id": "email_address", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "email_address" }, "target#(type==\"phone_number\")": { - "type": "phone_number", - "relation": "target_id" - } - }, - "person": { - "": { - "type": "person" + "relation": "target_id", + "schema": { + "$family": null, + "$id": "phone_number", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "phone_number" } }, "email_address": { "": { + "schema": { + "$family": null, + "$id": "email_address", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, "type": "email_address" } }, + "entity": { + "": { + "schema": { + "$family": null, + "$id": "entity", + "$ref": null, + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": "object", + "uniqueItems": null + }, + "type": "entity" + } + }, + "person": { + "": { + "schema": { + "$family": null, + "$id": "person", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "person" + } + }, "phone_number": { "": { + "schema": { + "$family": null, + "$id": "phone_number", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, "type": "phone_number" } }, "relationship": { "": { + "schema": { + "$family": null, + "$id": "relationship", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, "type": "relationship" } }, - "entity": { + "save_person.response": { "": { - "type": "entity" + "schema": { + "$family": null, + "$id": "save_person.response", + "$ref": "person", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": { + "contacts": { + "$family": null, + "$id": null, + "$ref": null, + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": { + "$family": null, + "$id": null, + "$ref": "contact", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": "array", + "uniqueItems": null + } + }, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "person" + }, + "contacts.#": { + "relation": "contacts_id", + "schema": { + "$family": null, + "$id": "contact", + "$ref": "relationship", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": { + "target": { + "$family": null, + "$id": null, + "$ref": null, + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": [ + { + "$family": null, + "$id": null, + "$ref": "phone_number", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + { + "$family": null, + "$id": null, + "$ref": "email_address", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + } + ], + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": null, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + } + }, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "contact" + }, + "contacts.#.target#(type==\"email_address\")": { + "relation": "target_id", + "schema": { + "$family": null, + "$id": "email_address", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "email_address" + }, + "contacts.#.target#(type==\"phone_number\")": { + "relation": "target_id", + "schema": { + "$family": null, + "$id": "phone_number", + "$ref": "entity", + "actions": null, + "additionalProperties": null, + "allOf": null, + "computer": null, + "const": null, + "contains": null, + "control": null, + "dependencies": null, + "description": null, + "display": null, + "else": null, + "enum": null, + "enumNames": null, + "exclusiveMaximum": null, + "exclusiveMinimum": null, + "extensible": null, + "form": null, + "format": null, + "if": null, + "items": null, + "maxContains": null, + "maxItems": null, + "maxLength": null, + "maxProperties": null, + "maximum": null, + "minContains": null, + "minItems": null, + "minLength": null, + "minProperties": null, + "minimum": null, + "multipleOf": null, + "not": null, + "oneOf": null, + "pattern": null, + "patternProperties": null, + "prefixItems": null, + "properties": {}, + "propertyNames": null, + "required": null, + "then": null, + "title": null, + "type": null, + "uniqueItems": null + }, + "type": "phone_number" } } } @@ -220,4 +1184,4 @@ } ] } -] \ No newline at end of file +] diff --git a/src/database/stem.rs b/src/database/stem.rs index 9611edb..26fe4c8 100644 --- a/src/database/stem.rs +++ b/src/database/stem.rs @@ -8,10 +8,5 @@ pub struct Stem { #[serde(skip_serializing_if = "Option::is_none")] pub relation: Option, - // The actual database schema node mapping for - // O(1) jump table execution for queryer. - // - // Automatically skipped from `jspg_stems()` JSON payload output. - #[serde(skip)] pub schema: Arc, } diff --git a/src/lib.rs b/src/lib.rs index 5ed0ecf..397a4dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,24 +121,11 @@ pub fn jspg_stems() -> JsonB { match engine_opt { Some(engine) => { - let mut result_arr = Vec::new(); - for (schema_name, stems_map) in &engine.database.stems { - let mut stems_arr = Vec::new(); - for (path_key, stem_arc) in stems_map { - stems_arr.push(serde_json::json!({ - "path": path_key, - "type": stem_arc.r#type, - "relation": stem_arc.relation - })); - } - result_arr.push(serde_json::json!({ - "schema": schema_name, - "stems": stems_arr - })); - } - JsonB(serde_json::to_value(result_arr).unwrap_or(Value::Array(Vec::new()))) + let stems_json = serde_json::to_value(&engine.database.stems) + .unwrap_or(serde_json::Value::Object(serde_json::Map::new())); + JsonB(stems_json) } - None => JsonB(Value::Array(Vec::new())), + None => JsonB(serde_json::Value::Object(serde_json::Map::new())), } }