From 41649766db0b476cd9a700a6b4b5e6234562d8ba Mon Sep 17 00:00:00 2001 From: Alex Groleau Date: Thu, 16 Apr 2026 11:54:37 -0400 Subject: [PATCH] to family --- GEMINI.md | 32 +++--- add_test.py | 104 ------------------- append_test.py | 152 ---------------------------- debug.log | 43 -------- fix_everything.py | 34 ------- fix_expect.py | 22 ---- fix_test.py | 87 ---------------- fixtures/database.json | 2 +- fixtures/paths.json | 3 +- fixtures/polymorphism.json | 14 +-- fixtures/queryer.json | 8 +- scratch.rs | 19 ---- src/database/object.rs | 7 +- src/database/schema.rs | 2 +- src/validator/rules/polymorphism.rs | 2 +- wipe_test.py | 24 ----- 16 files changed, 36 insertions(+), 519 deletions(-) delete mode 100644 add_test.py delete mode 100644 append_test.py delete mode 100644 debug.log delete mode 100644 fix_everything.py delete mode 100644 fix_expect.py delete mode 100644 fix_test.py delete mode 100644 scratch.rs delete mode 100644 wipe_test.py diff --git a/GEMINI.md b/GEMINI.md index 51e0994..7dd7dd5 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -13,7 +13,7 @@ JSPG operates by deeply integrating the JSON Schema Draft 2020-12 specification 1. **Draft 2020-12 Based**: Attempt to adhere to the official JSON Schema Draft 2020-12 specification, while heavily augmenting it for strict structural typing. 2. **Ultra-Fast Execution**: Compile schemas into optimized in-memory validation trees and cached SQL SPIs to bypass Postgres Query Builder overheads. 3. **Connection-Bound Caching**: Leverage the PostgreSQL session lifecycle using an **Atomic Swap** pattern. Schemas are 100% frozen, completely eliminating locks during read access. -4. **Structural Inheritance**: Support object-oriented schema design via Implicit Keyword Shadowing and virtual `$family` references natively mapped to Postgres table constraints. +4. **Structural Inheritance**: Support object-oriented schema design via Implicit Keyword Shadowing and virtual `family` references natively mapped to Postgres table constraints. 5. **Reactive Beats**: Provide ultra-fast natively generated flat payloads mapping directly to the Dart topological state for dynamic websocket reactivity. ### Concurrency & Threading ("Immutable Graphs") @@ -55,8 +55,8 @@ In Punc, polymorphic targets like explicit tagged unions or STI (Single Table In Therefore, any schema that participates in polymorphic discrimination MUST explicitly define its discriminator properties natively inside its `properties` block. However, to stay DRY and maintain flexible APIs, you **DO NOT** need to hardcode `const` values, nor should you add them to your `required` array. The Punc engine treats `type` and `kind` as **magic properties**. **Magic Validation Constraints**: -* **Dynamically Required**: The system inherently drives the need for their requirement. The Validator dynamically expects the discriminators and structurally bubbles `MISSING_TYPE` ultimata ONLY when a polymorphic router (`$family` / `oneOf`) dynamically requires them to resolve a path. You never manually put them in the JSON schema `required` block. -* **Implicit Resolution**: When wrapped in `$family` or `oneOf`, the polymorphic router can mathematically parse the schema key (e.g. `light.person`) and natively validate that `type` equals `"person"` and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch, all without you ever hardcoding `const` limitations. +* **Dynamically Required**: The system inherently drives the need for their requirement. The Validator dynamically expects the discriminators and structurally bubbles `MISSING_TYPE` ultimata ONLY when a polymorphic router (`family` / `oneOf`) dynamically requires them to resolve a path. You never manually put them in the JSON schema `required` block. +* **Implicit Resolution**: When wrapped in `family` or `oneOf`, the polymorphic router can mathematically parse the schema key (e.g. `light.person`) and natively validate that `type` equals `"person"` and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch, all without you ever hardcoding `const` limitations. * **Generator Explicitness**: Because Postgres is the Single Source of Truth, forcing the explicit definition in `properties` initially guarantees the downstream Dart/Go code generators observe the fields and can cleanly serialize them dynamically back to the server. For example, a schema registered under the exact key `"light.person"` inside the database registry must natively define its own structural boundaries: @@ -72,7 +72,7 @@ For example, a schema registered under the exact key `"light.person"` inside the * **The Object Contract (Presence)**: The Object enforces its own structural integrity mechanically. Standard JSON Validation natively ensures `type` and `kind` are dynamically present as expected. * **The Dynamic Values (`db.types`)**: Because the `type` and `kind` properties technically exist, the Punc engine dynamically intercepts them during `validate_object`. It mathematically parses the schema key (e.g. `light.person`) and natively validates that `type` equals `"person"` (or a valid descendant in `db.types`) and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch. -* **The Routing Contract**: When wrapped in `$family` or `oneOf`, the polymorphic router can execute Lightning Fast $O(1)$ fast-paths by reading the payload's `type`/`kind` identifiers, and gracefully fallback to standard structural failure if omitted. +* **The Routing Contract**: When wrapped in `family` or `oneOf`, the polymorphic router can execute Lightning Fast $O(1)$ fast-paths by reading the payload's `type`/`kind` identifiers, and gracefully fallback to standard structural failure if omitted. ### Composition & Inheritance (The `type` keyword) Punc completely abandons the standard JSON Schema `$ref` keyword. Instead, it overloads the exact same `type` keyword used for primitives. A `"type"` in Punc is mathematically evaluated as either a Native Primitive (`"string"`, `"null"`) or a Custom Object Pointer (`"budget"`, `"user"`). @@ -81,24 +81,24 @@ Punc completely abandons the standard JSON Schema `$ref` keyword. Instead, it ov * **Primitive Array Shorthand (Optionality)**: The `type` array syntax is heavily optimized for nullable fields. Defining `"type": ["budget", "null"]` natively builds a nullable strict, generating `Budget? budget;` in Dart. You can freely mix primitives like `["string", "number", "null"]`. * **Strict Array Constraint**: To explicitly prevent mathematically ambiguous Multiple Inheritance, a `type` array is strictly constrained to at most **ONE** Custom Object Pointer. Defining `"type": ["person", "organization"]` will intentionally trigger a fatal database compilation error natively instructing developers to build a proper tagged union (`oneOf`) instead. -### Polymorphism (`$family` and `oneOf`) +### Polymorphism (`family` and `oneOf`) Polymorphism is how an object boundary can dynamically take on entirely different shapes based on the payload provided at runtime. Punc utilizes the static database metadata generated from Postgres (`db.types`) to enforce these boundaries deterministically, rather than relying on ambiguous tree-traversals. -* **`$family` (Target-Based Polymorphism)**: An explicit Punc compiler macro instructing the engine to resolve dynamic options against the registered database `types` variations or its inner schema registry. It uses the exact physical constraints of the database to build SQL and validation routes. +* **`family` (Target-Based Polymorphism)**: An explicit Punc compiler macro instructing the engine to resolve dynamic options against the registered database `types` variations or its inner schema registry. It uses the exact physical constraints of the database to build SQL and validation routes. * **Scenario A: Global Tables (Vertical Routing)** - * *Setup*: `{ "$family": "organization" }` - * *Execution*: The engine queries `db.types.get("organization").variations` and finds `["bot", "organization", "person"]`. Because organizations are structurally table-backed, the `$family` automatically uses `type` as the discriminator. + * *Setup*: `{ "family": "organization" }` + * *Execution*: The engine queries `db.types.get("organization").variations` and finds `["bot", "organization", "person"]`. Because organizations are structurally table-backed, the `family` automatically uses `type` as the discriminator. * *Options*: `bot` -> `bot`, `person` -> `person`, `organization` -> `organization`. * **Scenario B: Prefixed Tables (Vertical Projection)** - * *Setup*: `{ "$family": "light.organization" }` + * *Setup*: `{ "family": "light.organization" }` * *Execution*: The engine sees the prefix `light.` and base `organization`. It queries `db.types.get("organization").variations` and dynamically prepends the prefix to discover the relevant UI schemas. * *Options*: `person` -> `light.person`, `organization` -> `light.organization`. (If a projection like `light.bot` does not exist in `db.schemas`, it is safely ignored). * **Scenario C: Single Table Inheritance (Horizontal Routing)** - * *Setup*: `{ "$family": "widget" }` (Where `widget` is a table type but has no external variations). - * *Execution*: The engine queries `db.types.get("widget").variations` and finds only `["widget"]`. Since it lacks table inheritance, it is treated as STI. The engine scans the specific, confined `schemas` array directly under `db.types.get("widget")` for any registered key terminating in the base `.widget` (e.g., `stock.widget`). The `$family` automatically uses `kind` as the discriminator. + * *Setup*: `{ "family": "widget" }` (Where `widget` is a table type but has no external variations). + * *Execution*: The engine queries `db.types.get("widget").variations` and finds only `["widget"]`. Since it lacks table inheritance, it is treated as STI. The engine scans the specific, confined `schemas` array directly under `db.types.get("widget")` for any registered key terminating in the base `.widget` (e.g., `stock.widget`). The `family` automatically uses `kind` as the discriminator. * *Options*: `stock` -> `stock.widget`, `tasks` -> `tasks.widget`. -* **`oneOf` (Strict Tagged Unions)**: A hardcoded list of candidate schemas. Unlike `$family` which relies on global DB metadata, `oneOf` forces pure mathematical structural evaluation of the provided candidates. It strictly bans typical JSON Schema "Union of Sets" fallback searches. Every candidate MUST possess a mathematically unique discriminator payload to allow $O(1)$ routing. +* **`oneOf` (Strict Tagged Unions)**: A hardcoded list of candidate schemas. Unlike `family` which relies on global DB metadata, `oneOf` forces pure mathematical structural evaluation of the provided candidates. It strictly bans typical JSON Schema "Union of Sets" fallback searches. Every candidate MUST possess a mathematically unique discriminator payload to allow $O(1)$ routing. * **Disjoint Types**: `oneOf: [{ "type": "person" }, { "type": "widget" }]`. The engine succeeds because the native `type` acts as a unique discriminator (`"person"` vs `"widget"`). * **STI Types**: `oneOf: [{ "type": "heavy.person" }, { "type": "light.person" }]`. The engine succeeds. Even though both share `"type": "person"`, their explicit discriminator is `kind` (`"heavy"` vs `"light"`), ensuring unique $O(1)$ fast-paths. * **Conflicting Types**: `oneOf: [{ "type": "person" }, { "type": "light.person" }]`. The engine **fails compilation natively**. Both schemas evaluate to `"type": "person"` and neither provides a disjoint `kind` constraint, making them mathematically ambiguous and impossible to route in $O(1)$ time. @@ -187,10 +187,10 @@ The Validator provides strict, schema-driven evaluation for the "Punc" architect JSPG implements specific extensions to the Draft 2020-12 standard to support the Punc architecture's object-oriented needs while heavily optimizing for zero-runtime lookups. * **Caching Strategy**: The Validator caches the pre-compiled `Database` registry in memory upon initialization (`jspg_setup`). This registry holds the comprehensive graph of schema boundaries, Types, ENUMs, and Foreign Key relationships, acting as the Single Source of Truth for all validation operations without polling Postgres. -* **Discriminator Fast Paths & Extraction**: When executing a polymorphic node (`oneOf` or `$family`), the engine statically analyzes the incoming JSON payload for the literal `type` and `kind` string coordinates. It routes the evaluation specifically to matching candidates in $O(1)$ while returning `MISSING_TYPE` ultimata directly. +* **Discriminator Fast Paths & Extraction**: When executing a polymorphic node (`oneOf` or `family`), the engine statically analyzes the incoming JSON payload for the literal `type` and `kind` string coordinates. It routes the evaluation specifically to matching candidates in $O(1)$ while returning `MISSING_TYPE` ultimata directly. * **Missing Type Ultimatum**: If an entity logically requires a discriminator and the JSON payload omits it, JSPG short-circuits branch execution entirely, bubbling a single, perfectly-pathed `MISSING_TYPE` error back to the UI natively to prevent confusing cascading failures. * **Golden Match Context**: When exactly one structural candidate perfectly maps a discriminator, the Validator exclusively cascades that specific structural error context directly to the user, stripping away all noise generated by other parallel schemas. -* **Topological Array Pathing**: Instead of relying on explicit `$id` references or injected properties, array iteration paths are dynamically typed based on their compiler boundary constraints. If the array's `items` schema resolves to a topological table-backed entity (e.g., inheriting via a `$family` macro tracked in the global DB catalog), the array locks paths and derives element indexes from their actual UUID paths (`array/widget-1/name`), natively enforcing database continuity. If evaluating isolated ad-hoc JSONB elements, strict numeric indexing is enforced natively (`array/1/name`) preventing synthetic payload manipulation. +* **Topological Array Pathing**: Instead of relying on explicit `$id` references or injected properties, array iteration paths are dynamically typed based on their compiler boundary constraints. If the array's `items` schema resolves to a topological table-backed entity (e.g., inheriting via a `family` macro tracked in the global DB catalog), the array locks paths and derives element indexes from their actual UUID paths (`array/widget-1/name`), natively enforcing database continuity. If evaluating isolated ad-hoc JSONB elements, strict numeric indexing is enforced natively (`array/1/name`) preventing synthetic payload manipulation. --- @@ -237,8 +237,8 @@ The Queryer transforms Postgres into a pre-compiled Semantic Query Engine, desig * **Array Inclusion**: `{"$in": [values]}`, `{"$nin": [values]}` use native `jsonb_array_elements_text()` bindings to enforce `IN` and `NOT IN` logic without runtime SQL injection risks. * **Text Matching (ILIKE)**: Evaluates `$eq` or `$ne` against string fields containing the `%` character natively into Postgres `ILIKE` and `NOT ILIKE` partial substring matches. * **Type Casting**: Safely resolves dynamic combinations by casting values instantly into the physical database types mapped in the schema (e.g. parsing `uuid` bindings to `::uuid`, formatting DateTimes to `::timestamptz`, and numbers to `::numeric`). -* **Polymorphic SQL Generation (`$family`)**: Compiles `$family` properties by analyzing the **Physical Database Variations**, *not* the schema descendants. - * **The Dot Convention**: When a schema requests `$family: "target.schema"`, the compiler extracts the base type (e.g. `schema`) and looks up its Physical Table definition. +* **Polymorphic SQL Generation (`family`)**: Compiles `family` properties by analyzing the **Physical Database Variations**, *not* the schema descendants. + * **The Dot Convention**: When a schema requests `family: "target.schema"`, the compiler extracts the base type (e.g. `schema`) and looks up its Physical Table definition. * **Multi-Table Branching**: If the Physical Table is a parent to other tables (e.g. `organization` has variations `["organization", "bot", "person"]`), the compiler generates a dynamic `CASE WHEN type = '...' THEN ...` query, expanding into sub-queries for each variation. To ensure safe resolution, the compiler dynamically evaluates correlation boundaries: it attempts standard Relational Edge discovery first. If no explicit relational edge exists (indicating pure Table Inheritance rather than a standard foreign-key graph relationship), it safely invokes a **Table Parity Fallback**. This generates an explicit ID correlation constraint (`AND inner.id = outer.id`), perfectly binding the structural variations back to the parent row to eliminate Cartesian products. * **Single-Table Bypass**: If the Physical Table is a leaf node with only one variation (e.g. `person` has variations `["person"]`), the compiler cleanly bypasses `CASE` generation and compiles a simple `SELECT` across the base table, as all schema extensions (e.g. `light.person`, `full.person`) are guaranteed to reside in the exact same physical row. diff --git a/add_test.py b/add_test.py deleted file mode 100644 index 3a24fdb..0000000 --- a/add_test.py +++ /dev/null @@ -1,104 +0,0 @@ -import json - -def load_json(path): - with open(path, 'r') as f: - return json.load(f) - -def save_json(path, data): - with open(path, 'w') as f: - json.dump(data, f, indent=2) - -def add_invoice(data): - # Add 'invoice' type - types = data[0]['database']['types'] - - # Check if invoice already exists - if any(t.get('name') == 'invoice' for t in types): - return - - types.append({ - "name": "invoice", - "hierarchy": ["invoice", "entity"], - "primary_key": ["id"], - "field_types": { - "id": "uuid", - "number": "text", - "metadata": "jsonb" - }, - "schemas": { - "invoice": { - "type": "entity", - "properties": { - "id": { "type": "string" }, - "number": { "type": "string" }, - "metadata": { - "type": "object", - "properties": { - "internal_note": { "type": "string" }, - "customer_snapshot": { "type": "entity" }, - "related_rules": { - "type": "array", - "items": { "type": "governance_rule" } - } - } - } - } - } - } - }) - -def process_merger(): - data = load_json('fixtures/merger.json') - add_invoice(data) - - # Add test - data[0]['tests'].append({ - "name": "Insert invoice with deep jsonb metadata", - "schema": "invoice", - "payload": { - "number": "INV-1001", - "metadata": { - "internal_note": "Confidential", - "customer_snapshot": { - "id": "00000000-0000-0000-0000-000000000000", - "type": "person", - "first_name": "John" - }, - "related_rules": [ - { - "id": "11111111-1111-1111-1111-111111111111" - } - ] - } - }, - "expect": { - "sql": [ - [ - "INSERT INTO agreego.invoice (metadata, number, id) VALUES ($1, $2, gen_random_uuid()) ON CONFLICT (id) DO UPDATE SET metadata = EXCLUDED.metadata, number = EXCLUDED.number RETURNING id, type", - {"metadata": {"customer_snapshot": {"first_name": "John", "id": "00000000-0000-0000-0000-000000000000", "type": "person"}, "internal_note": "Confidential", "related_rules": [{"id": "11111111-1111-1111-1111-111111111111"}]}, "number": "INV-1001"} - ] - ] - } - }) - save_json('fixtures/merger.json', data) - -def process_queryer(): - data = load_json('fixtures/queryer.json') - add_invoice(data) - - data[0]['tests'].append({ - "name": "Query invoice with complex JSONB metadata field extraction", - "schema": "invoice", - "query": { - "extract": ["id", "number", "metadata"], - "conditions": [] - }, - "expect": { - "sql": "SELECT jsonb_build_object('id', t1.id, 'metadata', t1.metadata, 'number', t1.number) FROM agreego.invoice t1 WHERE (t1.id IS NOT NULL)", - "params": {} - } - }) - save_json('fixtures/queryer.json', data) - -process_merger() -process_queryer() diff --git a/append_test.py b/append_test.py deleted file mode 100644 index 9c6e357..0000000 --- a/append_test.py +++ /dev/null @@ -1,152 +0,0 @@ -import json - -path = "fixtures/database.json" - -with open(path, "r") as f: - data = json.load(f) - -new_test = { - "description": "Schema Promotion Accuracy Test - -- One Database to Rule Them All --", - "database": { - "puncs": [], - "enums": [], - "relations": [], - "types": [ - { - "id": "t1", - "type": "type", - "name": "person", - "module": "core", - "source": "person", - "hierarchy": ["person"], - "variations": ["person", "student"], - "schemas": { - "full.person": { - "type": "object", - "properties": { - "type": {"type": "string"}, - "name": {"type": "string"}, - "email": { - "$family": "email_address" - }, - "generic_bubble": { - "type": "some_bubble" - }, - "ad_hoc_bubble": { - "type": "some_bubble", - "properties": { - "extra_inline_feature": {"type": "string"} - } - }, - "tags": { - "type": "array", - "items": {"type": "string"} - }, - "standard_relations": { - "type": "array", - "items": {"type": "contact"} - }, - "extended_relations": { - "type": "array", - "items": { - "type": "contact", - "properties": { - "target": {"type": "email_address"} - } - } - } - } - }, - "student.person": { - "type": "object", - "properties": { - "type": {"type": "string"}, - "kind": {"type": "string"}, - "school": {"type": "string"} - } - } - } - }, - { - "id": "t2", - "type": "type", - "name": "email_address", - "module": "core", - "source": "email_address", - "hierarchy": ["email_address"], - "variations": ["email_address"], - "schemas": { - "light.email_address": { - "type": "object", - "properties": { - "address": {"type": "string"} - } - } - } - }, - { - "id": "t3", - "type": "type", - "name": "contact", - "module": "core", - "source": "contact", - "hierarchy": ["contact"], - "variations": ["contact"], - "schemas": { - "full.contact": { - "type": "object", - "properties": { - "id": {"type": "string"} - } - } - } - }, - { - "id": "t4", - "type": "type", - "name": "some_bubble", - "module": "core", - "source": "some_bubble", - "hierarchy": ["some_bubble"], - "variations": ["some_bubble"], - "schemas": { - "some_bubble": { - "type": "object", - "properties": { - "bubble_prop": {"type": "string"} - } - } - } - } - ] - }, - "tests": [ - { - "description": "Assert exact topological schema promotion paths", - "action": "compile", - "expect": { - "success": True, - "schemas": [ - "ad_hoc_bubble", - "email_address", - "extended_relations", - "extended_relations/target", - "full.contact", - "full.person", - "full.person/ad_hoc_bubble", - "full.person/extended_relations", - "full.person/extended_relations/target", - "light.email_address", - "person", - "some_bubble", - "student.person" - ] - } - } - ] -} - -data.append(new_test) -with open(path, "w") as f: - json.dump(data, f, indent=2) - diff --git a/debug.log b/debug.log deleted file mode 100644 index fa71ce8..0000000 --- a/debug.log +++ /dev/null @@ -1,43 +0,0 @@ - Compiling jspg v0.1.0 (/Users/awgneo/Repositories/thoughtpatterns/cellular/jspg) -warning: unused variable: `is_family` - --> src/database/schema.rs:495:9 - | -495 | let is_family = self.obj.family.is_some(); - | ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_is_family` - | - = note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default - -warning: `jspg` (lib) generated 1 warning (run `cargo fix --lib -p jspg` to apply 1 suggestion) -warning: `jspg` (lib test) generated 1 warning (1 duplicate) - Finished `test` profile [unoptimized + debuginfo] target(s) in 11.66s - Running unittests src/lib.rs (target/debug/deps/jspg-d3f18ff3a7e2b386) - -running 1 test -[DEBUG SPLIT] ID: light.person, dim: type, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG SPLIT] ID: light.person, dim: kind, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG SPLIT] ID: light.person, dim: type, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG SPLIT] ID: light.person, dim: type, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG SPLIT] ID: light.person, dim: kind, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG SPLIT] ID: light.person, dim: type, is_split: false, props: Some(["age", "archived", "created", "created_at", "first_name", "id", "last_name", "name", "type"]) -[DEBUG POLYMORPHISM] ID: get_person.response, Strategy: type, Pathways: {"full.person": "full.person", "light.person": "light.person", "person": "person"} -[DEBUG QUERYER] Evaluating node. Target family: Some("organization"), disc: Some("type"), pathways: Some({"bot": "bot", "full.person": "full.person", "get_organization.response": "get_organization.response", "light.person": "light.person", "organization": "organization", "person": "person"}) -JSPG_SQL: (SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object('id', organization_1.id, 'type', CASE WHEN organization_1.type = 'bot' THEN ((SELECT jsonb_build_object('archived', entity_5.archived, 'created_at', entity_5.created_at, 'id', entity_5.id, 'name', organization_4.name, 'token', bot_3.token, 'type', entity_5.type) FROM agreego.bot bot_3 JOIN agreego.organization organization_4 ON organization_4.id = bot_3.id JOIN agreego.entity entity_5 ON entity_5.id = organization_4.id WHERE NOT entity_5.archived)) WHEN organization_1.type = 'full.person' THEN ((SELECT jsonb_build_object('addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', entity_11.archived, 'created_at', entity_11.created_at, 'id', entity_11.id, 'is_primary', contact_9.is_primary, 'target', (SELECT jsonb_build_object('archived', entity_13.archived, 'city', address_12.city, 'created_at', entity_13.created_at, 'id', entity_13.id, 'type', entity_13.type) FROM agreego.address address_12 JOIN agreego.entity entity_13 ON entity_13.id = address_12.id WHERE NOT entity_13.archived AND relationship_10.target_id = entity_13.id), 'type', entity_11.type)), '[]'::jsonb) FROM agreego.contact contact_9 JOIN agreego.relationship relationship_10 ON relationship_10.id = contact_9.id JOIN agreego.entity entity_11 ON entity_11.id = relationship_10.id WHERE NOT entity_11.archived AND relationship_10.target_type = 'address' AND relationship_10.source_id = entity_8.id), 'age', person_6.age, 'archived', entity_8.archived, 'contacts', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', entity_16.archived, 'created_at', entity_16.created_at, 'id', entity_16.id, 'is_primary', contact_14.is_primary, 'target', CASE WHEN entity_16.target_type = 'address' THEN ((SELECT jsonb_build_object('archived', entity_18.archived, 'city', address_17.city, 'created_at', entity_18.created_at, 'id', entity_18.id, 'type', entity_18.type) FROM agreego.address address_17 JOIN agreego.entity entity_18 ON entity_18.id = address_17.id WHERE NOT entity_18.archived AND relationship_15.target_id = entity_18.id)) WHEN entity_16.target_type = 'email_address' THEN ((SELECT jsonb_build_object('address', email_address_19.address, 'archived', entity_20.archived, 'created_at', entity_20.created_at, 'id', entity_20.id, 'type', entity_20.type) FROM agreego.email_address email_address_19 JOIN agreego.entity entity_20 ON entity_20.id = email_address_19.id WHERE NOT entity_20.archived AND relationship_15.target_id = entity_20.id)) WHEN entity_16.target_type = 'phone_number' THEN ((SELECT jsonb_build_object('archived', entity_22.archived, 'created_at', entity_22.created_at, 'id', entity_22.id, 'number', phone_number_21.number, 'type', entity_22.type) FROM agreego.phone_number phone_number_21 JOIN agreego.entity entity_22 ON entity_22.id = phone_number_21.id WHERE NOT entity_22.archived AND relationship_15.target_id = entity_22.id)) ELSE NULL END, 'type', entity_16.type)), '[]'::jsonb) FROM agreego.contact contact_14 JOIN agreego.relationship relationship_15 ON relationship_15.id = contact_14.id JOIN agreego.entity entity_16 ON entity_16.id = relationship_15.id WHERE NOT entity_16.archived AND relationship_15.source_id = entity_8.id), 'created_at', entity_8.created_at, 'email_addresses', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', entity_25.archived, 'created_at', entity_25.created_at, 'id', entity_25.id, 'is_primary', contact_23.is_primary, 'target', (SELECT jsonb_build_object('address', email_address_26.address, 'archived', entity_27.archived, 'created_at', entity_27.created_at, 'id', entity_27.id, 'type', entity_27.type) FROM agreego.email_address email_address_26 JOIN agreego.entity entity_27 ON entity_27.id = email_address_26.id WHERE NOT entity_27.archived AND relationship_24.target_id = entity_27.id), 'type', entity_25.type)), '[]'::jsonb) FROM agreego.contact contact_23 JOIN agreego.relationship relationship_24 ON relationship_24.id = contact_23.id JOIN agreego.entity entity_25 ON entity_25.id = relationship_24.id WHERE NOT entity_25.archived AND relationship_24.target_type = 'email_address' AND relationship_24.source_id = entity_8.id), 'first_name', person_6.first_name, 'id', entity_8.id, 'last_name', person_6.last_name, 'name', organization_7.name, 'phone_numbers', (SELECT COALESCE(jsonb_agg(jsonb_build_object('archived', entity_30.archived, 'created_at', entity_30.created_at, 'id', entity_30.id, 'is_primary', contact_28.is_primary, 'target', (SELECT jsonb_build_object('archived', entity_32.archived, 'created_at', entity_32.created_at, 'id', entity_32.id, 'number', phone_number_31.number, 'type', entity_32.type) FROM agreego.phone_number phone_number_31 JOIN agreego.entity entity_32 ON entity_32.id = phone_number_31.id WHERE NOT entity_32.archived AND relationship_29.target_id = entity_32.id), 'type', entity_30.type)), '[]'::jsonb) FROM agreego.contact contact_28 JOIN agreego.relationship relationship_29 ON relationship_29.id = contact_28.id JOIN agreego.entity entity_30 ON entity_30.id = relationship_29.id WHERE NOT entity_30.archived AND relationship_29.target_type = 'phone_number' AND relationship_29.source_id = entity_8.id), 'type', entity_8.type) FROM agreego.person person_6 JOIN agreego.organization organization_7 ON organization_7.id = person_6.id JOIN agreego.entity entity_8 ON entity_8.id = organization_7.id WHERE NOT entity_8.archived)) WHEN organization_1.type = 'get_organization.response' THEN ((SELECT jsonb_build_object('archived', entity_34.archived, 'created_at', entity_34.created_at, 'id', entity_34.id, 'name', organization_33.name, 'type', entity_34.type) FROM agreego.organization organization_33 JOIN agreego.entity entity_34 ON entity_34.id = organization_33.id WHERE NOT entity_34.archived)) WHEN organization_1.type = 'light.person' THEN ((SELECT jsonb_build_object('age', person_35.age, 'archived', entity_37.archived, 'created_at', entity_37.created_at, 'first_name', person_35.first_name, 'id', entity_37.id, 'last_name', person_35.last_name, 'name', organization_36.name, 'type', entity_37.type) FROM agreego.person person_35 JOIN agreego.organization organization_36 ON organization_36.id = person_35.id JOIN agreego.entity entity_37 ON entity_37.id = organization_36.id WHERE NOT entity_37.archived)) WHEN organization_1.type = 'organization' THEN ((SELECT jsonb_build_object('archived', entity_39.archived, 'created_at', entity_39.created_at, 'id', entity_39.id, 'name', organization_38.name, 'type', entity_39.type) FROM agreego.organization organization_38 JOIN agreego.entity entity_39 ON entity_39.id = organization_38.id WHERE NOT entity_39.archived)) WHEN organization_1.type = 'person' THEN ((SELECT jsonb_build_object('age', person_40.age, 'archived', entity_42.archived, 'created_at', entity_42.created_at, 'first_name', person_40.first_name, 'id', entity_42.id, 'last_name', person_40.last_name, 'name', organization_41.name, 'type', entity_42.type) FROM agreego.person person_40 JOIN agreego.organization organization_41 ON organization_41.id = person_40.id JOIN agreego.entity entity_42 ON entity_42.id = organization_41.id WHERE NOT entity_42.archived)) ELSE NULL END)), '[]'::jsonb) FROM agreego.organization organization_1 JOIN agreego.entity entity_2 ON entity_2.id = organization_1.id WHERE NOT entity_2.archived))) -TEST QUERY ERROR FOR 'Organizations select via a punc response with family': Line mismatched at execution sequence 1. -Expected Pattern: (SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object('id',organization_1.id,'type',CASE WHEN organization_1.type='bot'THEN((SELECT jsonb_build_object('archived',entity_5.archived,'created_at',entity_5.created_at,'id',entity_5.id,'name',organization_4.name,'token',bot_3.token,'type',entity_5.type)FROM agreego.bot bot_3 JOIN agreego.organization organization_4 ON organization_4.id=bot_3.id JOIN agreego.entity entity_5 ON entity_5.id=organization_4.id WHERE NOT entity_5.archived))WHEN organization_1.type='organization'THEN((SELECT jsonb_build_object('archived',entity_7.archived,'created_at',entity_7.created_at,'id',entity_7.id,'name',organization_6.name,'type',entity_7.type)FROM agreego.organization organization_6 JOIN agreego.entity entity_7 ON entity_7.id=organization_6.id WHERE NOT entity_7.archived))WHEN organization_1.type='person'THEN((SELECT jsonb_build_object('age',person_8.age,'archived',entity_10.archived,'created_at',entity_10.created_at,'first_name',person_8.first_name,'id',entity_10.id,'last_name',person_8.last_name,'name',organization_9.name,'type',entity_10.type)FROM agreego.person person_8 JOIN agreego.organization organization_9 ON organization_9.id=person_8.id JOIN agreego.entity entity_10 ON entity_10.id=organization_9.id WHERE NOT entity_10.archived))ELSE NULL END)),'[]'::jsonb)FROM agreego.organization organization_1 JOIN agreego.entity entity_2 ON entity_2.id=organization_1.id WHERE NOT entity_2.archived))) -Actual SQL: (SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object('id',organization_1.id,'type',CASE WHEN organization_1.type='bot'THEN((SELECT jsonb_build_object('archived',entity_5.archived,'created_at',entity_5.created_at,'id',entity_5.id,'name',organization_4.name,'token',bot_3.token,'type',entity_5.type)FROM agreego.bot bot_3 JOIN agreego.organization organization_4 ON organization_4.id=bot_3.id JOIN agreego.entity entity_5 ON entity_5.id=organization_4.id WHERE NOT entity_5.archived))WHEN organization_1.type='full.person'THEN((SELECT jsonb_build_object('addresses',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_11.archived,'created_at',entity_11.created_at,'id',entity_11.id,'is_primary',contact_9.is_primary,'target',(SELECT jsonb_build_object('archived',entity_13.archived,'city',address_12.city,'created_at',entity_13.created_at,'id',entity_13.id,'type',entity_13.type)FROM agreego.address address_12 JOIN agreego.entity entity_13 ON entity_13.id=address_12.id WHERE NOT entity_13.archived AND relationship_10.target_id=entity_13.id),'type',entity_11.type)),'[]'::jsonb)FROM agreego.contact contact_9 JOIN agreego.relationship relationship_10 ON relationship_10.id=contact_9.id JOIN agreego.entity entity_11 ON entity_11.id=relationship_10.id WHERE NOT entity_11.archived AND relationship_10.target_type='address'AND relationship_10.source_id=entity_8.id),'age',person_6.age,'archived',entity_8.archived,'contacts',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_16.archived,'created_at',entity_16.created_at,'id',entity_16.id,'is_primary',contact_14.is_primary,'target',CASE WHEN entity_16.target_type='address'THEN((SELECT jsonb_build_object('archived',entity_18.archived,'city',address_17.city,'created_at',entity_18.created_at,'id',entity_18.id,'type',entity_18.type)FROM agreego.address address_17 JOIN agreego.entity entity_18 ON entity_18.id=address_17.id WHERE NOT entity_18.archived AND relationship_15.target_id=entity_18.id))WHEN entity_16.target_type='email_address'THEN((SELECT jsonb_build_object('address',email_address_19.address,'archived',entity_20.archived,'created_at',entity_20.created_at,'id',entity_20.id,'type',entity_20.type)FROM agreego.email_address email_address_19 JOIN agreego.entity entity_20 ON entity_20.id=email_address_19.id WHERE NOT entity_20.archived AND relationship_15.target_id=entity_20.id))WHEN entity_16.target_type='phone_number'THEN((SELECT jsonb_build_object('archived',entity_22.archived,'created_at',entity_22.created_at,'id',entity_22.id,'number',phone_number_21.number,'type',entity_22.type)FROM agreego.phone_number phone_number_21 JOIN agreego.entity entity_22 ON entity_22.id=phone_number_21.id WHERE NOT entity_22.archived AND relationship_15.target_id=entity_22.id))ELSE NULL END,'type',entity_16.type)),'[]'::jsonb)FROM agreego.contact contact_14 JOIN agreego.relationship relationship_15 ON relationship_15.id=contact_14.id JOIN agreego.entity entity_16 ON entity_16.id=relationship_15.id WHERE NOT entity_16.archived AND relationship_15.source_id=entity_8.id),'created_at',entity_8.created_at,'email_addresses',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_25.archived,'created_at',entity_25.created_at,'id',entity_25.id,'is_primary',contact_23.is_primary,'target',(SELECT jsonb_build_object('address',email_address_26.address,'archived',entity_27.archived,'created_at',entity_27.created_at,'id',entity_27.id,'type',entity_27.type)FROM agreego.email_address email_address_26 JOIN agreego.entity entity_27 ON entity_27.id=email_address_26.id WHERE NOT entity_27.archived AND relationship_24.target_id=entity_27.id),'type',entity_25.type)),'[]'::jsonb)FROM agreego.contact contact_23 JOIN agreego.relationship relationship_24 ON relationship_24.id=contact_23.id JOIN agreego.entity entity_25 ON entity_25.id=relationship_24.id WHERE NOT entity_25.archived AND relationship_24.target_type='email_address'AND relationship_24.source_id=entity_8.id),'first_name',person_6.first_name,'id',entity_8.id,'last_name',person_6.last_name,'name',organization_7.name,'phone_numbers',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_30.archived,'created_at',entity_30.created_at,'id',entity_30.id,'is_primary',contact_28.is_primary,'target',(SELECT jsonb_build_object('archived',entity_32.archived,'created_at',entity_32.created_at,'id',entity_32.id,'number',phone_number_31.number,'type',entity_32.type)FROM agreego.phone_number phone_number_31 JOIN agreego.entity entity_32 ON entity_32.id=phone_number_31.id WHERE NOT entity_32.archived AND relationship_29.target_id=entity_32.id),'type',entity_30.type)),'[]'::jsonb)FROM agreego.contact contact_28 JOIN agreego.relationship relationship_29 ON relationship_29.id=contact_28.id JOIN agreego.entity entity_30 ON entity_30.id=relationship_29.id WHERE NOT entity_30.archived AND relationship_29.target_type='phone_number'AND relationship_29.source_id=entity_8.id),'type',entity_8.type)FROM agreego.person person_6 JOIN agreego.organization organization_7 ON organization_7.id=person_6.id JOIN agreego.entity entity_8 ON entity_8.id=organization_7.id WHERE NOT entity_8.archived))WHEN organization_1.type='get_organization.response'THEN((SELECT jsonb_build_object('archived',entity_34.archived,'created_at',entity_34.created_at,'id',entity_34.id,'name',organization_33.name,'type',entity_34.type)FROM agreego.organization organization_33 JOIN agreego.entity entity_34 ON entity_34.id=organization_33.id WHERE NOT entity_34.archived))WHEN organization_1.type='light.person'THEN((SELECT jsonb_build_object('age',person_35.age,'archived',entity_37.archived,'created_at',entity_37.created_at,'first_name',person_35.first_name,'id',entity_37.id,'last_name',person_35.last_name,'name',organization_36.name,'type',entity_37.type)FROM agreego.person person_35 JOIN agreego.organization organization_36 ON organization_36.id=person_35.id JOIN agreego.entity entity_37 ON entity_37.id=organization_36.id WHERE NOT entity_37.archived))WHEN organization_1.type='organization'THEN((SELECT jsonb_build_object('archived',entity_39.archived,'created_at',entity_39.created_at,'id',entity_39.id,'name',organization_38.name,'type',entity_39.type)FROM agreego.organization organization_38 JOIN agreego.entity entity_39 ON entity_39.id=organization_38.id WHERE NOT entity_39.archived))WHEN organization_1.type='person'THEN((SELECT jsonb_build_object('age',person_40.age,'archived',entity_42.archived,'created_at',entity_42.created_at,'first_name',person_40.first_name,'id',entity_42.id,'last_name',person_40.last_name,'name',organization_41.name,'type',entity_42.type)FROM agreego.person person_40 JOIN agreego.organization organization_41 ON organization_41.id=person_40.id JOIN agreego.entity entity_42 ON entity_42.id=organization_41.id WHERE NOT entity_42.archived))ELSE NULL END)),'[]'::jsonb)FROM agreego.organization organization_1 JOIN agreego.entity entity_2 ON entity_2.id=organization_1.id WHERE NOT entity_2.archived))) -Regex used: \(SELECT jsonb_strip_nulls\(\(SELECT COALESCE\(jsonb_agg\(jsonb_build_object\('id',organization_1\.id,'type',CASE WHEN organization_1\.type='bot'THEN\(\(SELECT jsonb_build_object\('archived',entity_5\.archived,'created_at',entity_5\.created_at,'id',entity_5\.id,'name',organization_4\.name,'token',bot_3\.token,'type',entity_5\.type\)FROM agreego\.bot bot_3 JOIN agreego\.organization organization_4 ON organization_4\.id=bot_3\.id JOIN agreego\.entity entity_5 ON entity_5\.id=organization_4\.id WHERE NOT entity_5\.archived\)\)WHEN organization_1\.type='organization'THEN\(\(SELECT jsonb_build_object\('archived',entity_7\.archived,'created_at',entity_7\.created_at,'id',entity_7\.id,'name',organization_6\.name,'type',entity_7\.type\)FROM agreego\.organization organization_6 JOIN agreego\.entity entity_7 ON entity_7\.id=organization_6\.id WHERE NOT entity_7\.archived\)\)WHEN organization_1\.type='person'THEN\(\(SELECT jsonb_build_object\('age',person_8\.age,'archived',entity_10\.archived,'created_at',entity_10\.created_at,'first_name',person_8\.first_name,'id',entity_10\.id,'last_name',person_8\.last_name,'name',organization_9\.name,'type',entity_10\.type\)FROM agreego\.person person_8 JOIN agreego\.organization organization_9 ON organization_9\.id=person_8\.id JOIN agreego\.entity entity_10 ON entity_10\.id=organization_9\.id WHERE NOT entity_10\.archived\)\)ELSE NULL END\)\),'\[\]'::jsonb\)FROM agreego\.organization organization_1 JOIN agreego\.entity entity_2 ON entity_2\.id=organization_1\.id WHERE NOT entity_2\.archived\)\)\) -Variables Mapped: {} - -thread 'tests::test_queryer_0_8' (97338607) panicked at src/tests/fixtures.rs:1427:54: -called `Result::unwrap()` on an `Err` value: "[Queryer Execution] Query Test 'Organizations select via a punc response with family' failed. Error: Line mismatched at execution sequence 1.\nExpected Pattern: (SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object('id',organization_1.id,'type',CASE WHEN organization_1.type='bot'THEN((SELECT jsonb_build_object('archived',entity_5.archived,'created_at',entity_5.created_at,'id',entity_5.id,'name',organization_4.name,'token',bot_3.token,'type',entity_5.type)FROM agreego.bot bot_3 JOIN agreego.organization organization_4 ON organization_4.id=bot_3.id JOIN agreego.entity entity_5 ON entity_5.id=organization_4.id WHERE NOT entity_5.archived))WHEN organization_1.type='organization'THEN((SELECT jsonb_build_object('archived',entity_7.archived,'created_at',entity_7.created_at,'id',entity_7.id,'name',organization_6.name,'type',entity_7.type)FROM agreego.organization organization_6 JOIN agreego.entity entity_7 ON entity_7.id=organization_6.id WHERE NOT entity_7.archived))WHEN organization_1.type='person'THEN((SELECT jsonb_build_object('age',person_8.age,'archived',entity_10.archived,'created_at',entity_10.created_at,'first_name',person_8.first_name,'id',entity_10.id,'last_name',person_8.last_name,'name',organization_9.name,'type',entity_10.type)FROM agreego.person person_8 JOIN agreego.organization organization_9 ON organization_9.id=person_8.id JOIN agreego.entity entity_10 ON entity_10.id=organization_9.id WHERE NOT entity_10.archived))ELSE NULL END)),'[]'::jsonb)FROM agreego.organization organization_1 JOIN agreego.entity entity_2 ON entity_2.id=organization_1.id WHERE NOT entity_2.archived)))\nActual SQL: (SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object('id',organization_1.id,'type',CASE WHEN organization_1.type='bot'THEN((SELECT jsonb_build_object('archived',entity_5.archived,'created_at',entity_5.created_at,'id',entity_5.id,'name',organization_4.name,'token',bot_3.token,'type',entity_5.type)FROM agreego.bot bot_3 JOIN agreego.organization organization_4 ON organization_4.id=bot_3.id JOIN agreego.entity entity_5 ON entity_5.id=organization_4.id WHERE NOT entity_5.archived))WHEN organization_1.type='full.person'THEN((SELECT jsonb_build_object('addresses',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_11.archived,'created_at',entity_11.created_at,'id',entity_11.id,'is_primary',contact_9.is_primary,'target',(SELECT jsonb_build_object('archived',entity_13.archived,'city',address_12.city,'created_at',entity_13.created_at,'id',entity_13.id,'type',entity_13.type)FROM agreego.address address_12 JOIN agreego.entity entity_13 ON entity_13.id=address_12.id WHERE NOT entity_13.archived AND relationship_10.target_id=entity_13.id),'type',entity_11.type)),'[]'::jsonb)FROM agreego.contact contact_9 JOIN agreego.relationship relationship_10 ON relationship_10.id=contact_9.id JOIN agreego.entity entity_11 ON entity_11.id=relationship_10.id WHERE NOT entity_11.archived AND relationship_10.target_type='address'AND relationship_10.source_id=entity_8.id),'age',person_6.age,'archived',entity_8.archived,'contacts',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_16.archived,'created_at',entity_16.created_at,'id',entity_16.id,'is_primary',contact_14.is_primary,'target',CASE WHEN entity_16.target_type='address'THEN((SELECT jsonb_build_object('archived',entity_18.archived,'city',address_17.city,'created_at',entity_18.created_at,'id',entity_18.id,'type',entity_18.type)FROM agreego.address address_17 JOIN agreego.entity entity_18 ON entity_18.id=address_17.id WHERE NOT entity_18.archived AND relationship_15.target_id=entity_18.id))WHEN entity_16.target_type='email_address'THEN((SELECT jsonb_build_object('address',email_address_19.address,'archived',entity_20.archived,'created_at',entity_20.created_at,'id',entity_20.id,'type',entity_20.type)FROM agreego.email_address email_address_19 JOIN agreego.entity entity_20 ON entity_20.id=email_address_19.id WHERE NOT entity_20.archived AND relationship_15.target_id=entity_20.id))WHEN entity_16.target_type='phone_number'THEN((SELECT jsonb_build_object('archived',entity_22.archived,'created_at',entity_22.created_at,'id',entity_22.id,'number',phone_number_21.number,'type',entity_22.type)FROM agreego.phone_number phone_number_21 JOIN agreego.entity entity_22 ON entity_22.id=phone_number_21.id WHERE NOT entity_22.archived AND relationship_15.target_id=entity_22.id))ELSE NULL END,'type',entity_16.type)),'[]'::jsonb)FROM agreego.contact contact_14 JOIN agreego.relationship relationship_15 ON relationship_15.id=contact_14.id JOIN agreego.entity entity_16 ON entity_16.id=relationship_15.id WHERE NOT entity_16.archived AND relationship_15.source_id=entity_8.id),'created_at',entity_8.created_at,'email_addresses',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_25.archived,'created_at',entity_25.created_at,'id',entity_25.id,'is_primary',contact_23.is_primary,'target',(SELECT jsonb_build_object('address',email_address_26.address,'archived',entity_27.archived,'created_at',entity_27.created_at,'id',entity_27.id,'type',entity_27.type)FROM agreego.email_address email_address_26 JOIN agreego.entity entity_27 ON entity_27.id=email_address_26.id WHERE NOT entity_27.archived AND relationship_24.target_id=entity_27.id),'type',entity_25.type)),'[]'::jsonb)FROM agreego.contact contact_23 JOIN agreego.relationship relationship_24 ON relationship_24.id=contact_23.id JOIN agreego.entity entity_25 ON entity_25.id=relationship_24.id WHERE NOT entity_25.archived AND relationship_24.target_type='email_address'AND relationship_24.source_id=entity_8.id),'first_name',person_6.first_name,'id',entity_8.id,'last_name',person_6.last_name,'name',organization_7.name,'phone_numbers',(SELECT COALESCE(jsonb_agg(jsonb_build_object('archived',entity_30.archived,'created_at',entity_30.created_at,'id',entity_30.id,'is_primary',contact_28.is_primary,'target',(SELECT jsonb_build_object('archived',entity_32.archived,'created_at',entity_32.created_at,'id',entity_32.id,'number',phone_number_31.number,'type',entity_32.type)FROM agreego.phone_number phone_number_31 JOIN agreego.entity entity_32 ON entity_32.id=phone_number_31.id WHERE NOT entity_32.archived AND relationship_29.target_id=entity_32.id),'type',entity_30.type)),'[]'::jsonb)FROM agreego.contact contact_28 JOIN agreego.relationship relationship_29 ON relationship_29.id=contact_28.id JOIN agreego.entity entity_30 ON entity_30.id=relationship_29.id WHERE NOT entity_30.archived AND relationship_29.target_type='phone_number'AND relationship_29.source_id=entity_8.id),'type',entity_8.type)FROM agreego.person person_6 JOIN agreego.organization organization_7 ON organization_7.id=person_6.id JOIN agreego.entity entity_8 ON entity_8.id=organization_7.id WHERE NOT entity_8.archived))WHEN organization_1.type='get_organization.response'THEN((SELECT jsonb_build_object('archived',entity_34.archived,'created_at',entity_34.created_at,'id',entity_34.id,'name',organization_33.name,'type',entity_34.type)FROM agreego.organization organization_33 JOIN agreego.entity entity_34 ON entity_34.id=organization_33.id WHERE NOT entity_34.archived))WHEN organization_1.type='light.person'THEN((SELECT jsonb_build_object('age',person_35.age,'archived',entity_37.archived,'created_at',entity_37.created_at,'first_name',person_35.first_name,'id',entity_37.id,'last_name',person_35.last_name,'name',organization_36.name,'type',entity_37.type)FROM agreego.person person_35 JOIN agreego.organization organization_36 ON organization_36.id=person_35.id JOIN agreego.entity entity_37 ON entity_37.id=organization_36.id WHERE NOT entity_37.archived))WHEN organization_1.type='organization'THEN((SELECT jsonb_build_object('archived',entity_39.archived,'created_at',entity_39.created_at,'id',entity_39.id,'name',organization_38.name,'type',entity_39.type)FROM agreego.organization organization_38 JOIN agreego.entity entity_39 ON entity_39.id=organization_38.id WHERE NOT entity_39.archived))WHEN organization_1.type='person'THEN((SELECT jsonb_build_object('age',person_40.age,'archived',entity_42.archived,'created_at',entity_42.created_at,'first_name',person_40.first_name,'id',entity_42.id,'last_name',person_40.last_name,'name',organization_41.name,'type',entity_42.type)FROM agreego.person person_40 JOIN agreego.organization organization_41 ON organization_41.id=person_40.id JOIN agreego.entity entity_42 ON entity_42.id=organization_41.id WHERE NOT entity_42.archived))ELSE NULL END)),'[]'::jsonb)FROM agreego.organization organization_1 JOIN agreego.entity entity_2 ON entity_2.id=organization_1.id WHERE NOT entity_2.archived)))\nRegex used: \\(SELECT jsonb_strip_nulls\\(\\(SELECT COALESCE\\(jsonb_agg\\(jsonb_build_object\\('id',organization_1\\.id,'type',CASE WHEN organization_1\\.type='bot'THEN\\(\\(SELECT jsonb_build_object\\('archived',entity_5\\.archived,'created_at',entity_5\\.created_at,'id',entity_5\\.id,'name',organization_4\\.name,'token',bot_3\\.token,'type',entity_5\\.type\\)FROM agreego\\.bot bot_3 JOIN agreego\\.organization organization_4 ON organization_4\\.id=bot_3\\.id JOIN agreego\\.entity entity_5 ON entity_5\\.id=organization_4\\.id WHERE NOT entity_5\\.archived\\)\\)WHEN organization_1\\.type='organization'THEN\\(\\(SELECT jsonb_build_object\\('archived',entity_7\\.archived,'created_at',entity_7\\.created_at,'id',entity_7\\.id,'name',organization_6\\.name,'type',entity_7\\.type\\)FROM agreego\\.organization organization_6 JOIN agreego\\.entity entity_7 ON entity_7\\.id=organization_6\\.id WHERE NOT entity_7\\.archived\\)\\)WHEN organization_1\\.type='person'THEN\\(\\(SELECT jsonb_build_object\\('age',person_8\\.age,'archived',entity_10\\.archived,'created_at',entity_10\\.created_at,'first_name',person_8\\.first_name,'id',entity_10\\.id,'last_name',person_8\\.last_name,'name',organization_9\\.name,'type',entity_10\\.type\\)FROM agreego\\.person person_8 JOIN agreego\\.organization organization_9 ON organization_9\\.id=person_8\\.id JOIN agreego\\.entity entity_10 ON entity_10\\.id=organization_9\\.id WHERE NOT entity_10\\.archived\\)\\)ELSE NULL END\\)\\),'\\[\\]'::jsonb\\)FROM agreego\\.organization organization_1 JOIN agreego\\.entity entity_2 ON entity_2\\.id=organization_1\\.id WHERE NOT entity_2\\.archived\\)\\)\\)\nVariables Mapped: {}" -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -test tests::test_queryer_0_8 ... FAILED - -failures: - -failures: - tests::test_queryer_0_8 - -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 1350 filtered out; finished in 0.01s - -error: test failed, to rerun pass `--lib` diff --git a/fix_everything.py b/fix_everything.py deleted file mode 100644 index 3b86a03..0000000 --- a/fix_everything.py +++ /dev/null @@ -1,34 +0,0 @@ -import json - -path = "fixtures/database.json" - -with open(path, "r") as f: - data = json.load(f) - -test_case = data[-1] -# Get full.person object properties -props = test_case["database"]["types"][0]["schemas"]["full.person"]["properties"] - -# Find extended_relations target and add properties! -target_ref = props["extended_relations"]["items"]["properties"]["target"] -target_ref["properties"] = { - "extra_3rd_level": {"type": "string"} -} - -# The target is now an ad-hoc composition itself! -# We expect `full.person/extended_relations/target` to be globally promoted. - -test_case["tests"][0]["expect"]["schemas"] = [ - "full.contact", - "full.person", - "full.person/ad_hoc_bubble", - "full.person/extended_relations", - "full.person/extended_relations/target", # BOOM! Right here, 3 levels deep! - "light.email_address", - "some_bubble", - "student.person" -] - -with open(path, "w") as f: - json.dump(data, f, indent=2) - diff --git a/fix_expect.py b/fix_expect.py deleted file mode 100644 index 2cfa967..0000000 --- a/fix_expect.py +++ /dev/null @@ -1,22 +0,0 @@ -import json - -path = "fixtures/database.json" - -with open(path, "r") as f: - data = json.load(f) - -test_case = data[-1] -test_case["tests"][0]["expect"]["schemas"] = [ - "full.contact", - "full.person", - "full.person/ad_hoc_bubble", - "full.person/extended_relations", - "full.person/extended_relations/items", - "light.email_address", - "some_bubble", - "student.person" -] - -with open(path, "w") as f: - json.dump(data, f, indent=2) - diff --git a/fix_test.py b/fix_test.py deleted file mode 100644 index fc14f89..0000000 --- a/fix_test.py +++ /dev/null @@ -1,87 +0,0 @@ -import json - -def load_json(path): - with open(path, 'r') as f: - return json.load(f) - -def save_json(path, data): - with open(path, 'w') as f: - json.dump(data, f, indent=4) - -def fix_merger(): - data = load_json('fixtures/merger.json') - last_test = data[0]['tests'][-1] - - # Check if the last test is our bad one - if "name" in last_test and last_test["name"] == "Insert invoice with deep jsonb metadata": - new_test = { - "description": last_test["name"], - "action": "merge", - "schema_id": last_test["schema"], - "data": last_test["payload"], - "expect": { - "success": True, - "sql": [ - [ - "INSERT INTO agreego.invoice (", - " \"metadata\",", - " \"number\",", - " entity_id,", - " id,", - " type", - ")", - "VALUES (", - " '{", - " \"customer_snapshot\":{", - " \"first_name\":\"John\",", - " \"id\":\"00000000-0000-0000-0000-000000000000\",", - " \"type\":\"person\"", - " },", - " \"internal_note\":\"Confidential\",", - " \"related_rules\":[", - " {", - " \"id\":\"11111111-1111-1111-1111-111111111111\"", - " }", - " ]", - " }',", - " 'INV-1001',", - " NULL,", - " '{{uuid}}',", - " 'invoice'", - ")" - ] - ] - } - } - data[0]['tests'][-1] = new_test - save_json('fixtures/merger.json', data) - -def fix_queryer(): - data = load_json('fixtures/queryer.json') - last_test = data[0]['tests'][-1] - - if "name" in last_test and last_test["name"] == "Query invoice with complex JSONB metadata field extraction": - new_test = { - "description": last_test["name"], - "action": "query", - "schema_id": last_test["schema"], - "expect": { - "success": True, - "sql": [ - [ - "(SELECT jsonb_strip_nulls(jsonb_build_object(", - " 'id', invoice_1.id,", - " 'metadata', invoice_1.metadata,", - " 'number', invoice_1.number,", - " 'type', invoice_1.type", - "))", - "FROM agreego.invoice invoice_1)" - ] - ] - } - } - data[0]['tests'][-1] = new_test - save_json('fixtures/queryer.json', data) - -fix_merger() -fix_queryer() diff --git a/fixtures/database.json b/fixtures/database.json index 0abf636..7b49053 100644 --- a/fixtures/database.json +++ b/fixtures/database.json @@ -515,7 +515,7 @@ "type": "string" }, "email": { - "$family": "email_address" + "family": "email_address" }, "generic_bubble": { "type": "some_bubble" diff --git a/fixtures/paths.json b/fixtures/paths.json index d68d69e..87532a8 100644 --- a/fixtures/paths.json +++ b/fixtures/paths.json @@ -331,7 +331,7 @@ "table_families": { "type": "array", "items": { - "$family": "widget" + "family": "widget" } } } @@ -339,7 +339,6 @@ } }, "tests": [ - { "description": "families mechanically map physical variants directly onto topological uuid array paths", "data": { diff --git a/fixtures/polymorphism.json b/fixtures/polymorphism.json index 3df37bf..1b9e4aa 100644 --- a/fixtures/polymorphism.json +++ b/fixtures/polymorphism.json @@ -1,6 +1,6 @@ [ { - "description": "Vertical $family Routing (Across Tables)", + "description": "Vertical family Routing (Across Tables)", "database": { "types": [ { @@ -77,7 +77,7 @@ ], "schemas": { "family_entity": { - "$family": "entity" + "family": "entity" } } }, @@ -150,7 +150,7 @@ ] }, { - "description": "Matrix $family Routing (Vertical + Horizontal Intersections)", + "description": "Matrix family Routing (Vertical + Horizontal Intersections)", "database": { "types": [ { @@ -226,7 +226,7 @@ ], "schemas": { "family_light_org": { - "$family": "light.organization" + "family": "light.organization" } } }, @@ -278,7 +278,7 @@ ] }, { - "description": "Horizontal $family Routing (Virtual Variations)", + "description": "Horizontal family Routing (Virtual Variations)", "database": { "types": [ { @@ -319,10 +319,10 @@ ], "schemas": { "family_widget": { - "$family": "widget" + "family": "widget" }, "family_stock_widget": { - "$family": "stock.widget" + "family": "stock.widget" } } }, diff --git a/fixtures/queryer.json b/fixtures/queryer.json index fb671bd..d6eff57 100644 --- a/fixtures/queryer.json +++ b/fixtures/queryer.json @@ -17,7 +17,7 @@ "get_organizations.response": { "type": "array", "items": { - "$family": "organization" + "family": "organization" } } } @@ -26,7 +26,7 @@ "name": "get_light_organization", "schemas": { "get_light_organization.response": { - "$family": "light.organization" + "family": "light.organization" } } }, @@ -34,7 +34,7 @@ "name": "get_full_organization", "schemas": { "get_full_organization.response": { - "$family": "full.organization" + "family": "full.organization" } } }, @@ -55,7 +55,7 @@ "get_widgets.response": { "type": "array", "items": { - "$family": "widget" + "family": "widget" } } } diff --git a/scratch.rs b/scratch.rs deleted file mode 100644 index 2d7bb72..0000000 --- a/scratch.rs +++ /dev/null @@ -1,19 +0,0 @@ -use cellular_jspg::database::{Database, object::SchemaTypeOrArray}; -use cellular_jspg::tests::fixtures::get_queryer_db; - -fn main() { - let db_json = get_queryer_db(); - let db = Database::from_json(&db_json).unwrap(); - let keys: Vec<_> = db.schemas.keys().collect(); - println!("Found schemas: {}", keys.len()); - let mut found = false; - for k in keys { - if k.contains("email_addresses") { - println!("Contains email_addresses: {}", k); - found = true; - } - } - if !found { - println!("No email_addresses found at all!"); - } -} diff --git a/src/database/object.rs b/src/database/object.rs index fdaf74f..0af64f1 100644 --- a/src/database/object.rs +++ b/src/database/object.rs @@ -37,7 +37,7 @@ pub struct SchemaObject { #[serde(rename = "additionalProperties")] #[serde(skip_serializing_if = "Option::is_none")] pub additional_properties: Option>, - #[serde(rename = "$family")] + #[serde(rename = "family")] #[serde(skip_serializing_if = "Option::is_none")] pub family: Option, @@ -154,12 +154,15 @@ pub struct SchemaObject { #[serde(skip_serializing_if = "Option::is_none")] pub extensible: Option, + // Contains ALL structural fields perfectly flattened from the ENTIRE Database inheritance tree (e.g. `entity` fields like `id`) as well as local fields hidden inside conditional `cases` blocks. + // This JSON exported array gives clients absolute deterministic visibility to O(1) validation and masking bounds without duplicating structural memory. #[serde(rename = "compiledPropertyNames")] #[serde(skip_deserializing)] #[serde(skip_serializing_if = "crate::database::object::is_once_lock_vec_empty")] #[serde(serialize_with = "crate::database::object::serialize_once_lock")] pub compiled_property_names: OnceLock>, + // Internal structural representation caching active AST Node maps. Unlike the Go framework counterpart, the JSPG implementation DOES natively include ALL ancestral inheritance boundary schemas because it compiles locally against the raw database graph. #[serde(skip)] pub compiled_properties: OnceLock>>, @@ -307,7 +310,7 @@ impl SchemaObject { return true; } - // 2. Implicit table-backed rule: Does its $family boundary map directly to the global database catalog? + // 2. Implicit table-backed rule: Does its family boundary map directly to the global database catalog? if let Some(family) = &self.family { let base = family.split('.').next_back().unwrap_or(family); if db.types.contains_key(base) { diff --git a/src/database/schema.rs b/src/database/schema.rs index dc2e226..faf5c8d 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -522,7 +522,7 @@ impl Schema { } if let Some(family) = &schema_arc.obj.family { - Self::validate_identifier(family, "$family", root_id, &path, errors); + Self::validate_identifier(family, "family", root_id, &path, errors); } Self::collect_child_schemas(schema_arc, root_id, path, to_insert, errors); diff --git a/src/validator/rules/polymorphism.rs b/src/validator/rules/polymorphism.rs index 097d7a4..b2b5856 100644 --- a/src/validator/rules/polymorphism.rs +++ b/src/validator/rules/polymorphism.rs @@ -21,7 +21,7 @@ impl<'a> ValidationContext<'a> { if conflicts { result.errors.push(ValidationError { code: "INVALID_SCHEMA".to_string(), - message: "$family must be used exclusively without other constraints".to_string(), + message: "family must be used exclusively without other constraints".to_string(), path: self.path.to_string(), }); return Ok(false); diff --git a/wipe_test.py b/wipe_test.py deleted file mode 100644 index 580116d..0000000 --- a/wipe_test.py +++ /dev/null @@ -1,24 +0,0 @@ -import json - -def load_json(path): - with open(path, 'r') as f: - return json.load(f) - -def save_json(path, data): - with open(path, 'w') as f: - json.dump(data, f, indent=4) - -def fix_merger(): - data = load_json('fixtures/merger.json') - last_test = data[0]['tests'][-1] - last_test["expect"]["sql"] = [] - save_json('fixtures/merger.json', data) - -def fix_queryer(): - data = load_json('fixtures/queryer.json') - last_test = data[0]['tests'][-1] - last_test["expect"]["sql"] = [] - save_json('fixtures/queryer.json', data) - -fix_merger() -fix_queryer()