Compare commits

...

6 Commits

Author SHA1 Message Date
e407adf6a1 version: 1.0.113 2026-04-14 06:09:14 -04:00
0b4607b7d4 fixed and tested subschema promotions for beat processing 2026-04-14 06:09:00 -04:00
a53e89df52 version: 1.0.112 2026-04-13 22:48:27 -04:00
57bbe11013 version: 1.0.111 2026-04-13 22:48:12 -04:00
386b7ad012 docs(jspg): document scalar tuple routing boundary 2026-04-13 22:47:21 -04:00
a91460b390 cleanup 2026-04-13 22:44:18 -04:00
15 changed files with 621 additions and 25 deletions

2
.gitignore vendored
View File

@ -2,4 +2,4 @@
/package /package
.env .env
/src/tests.rs /src/tests.rs
/pgrx-develop/.test /pgrx-develop

View File

@ -172,6 +172,7 @@ When compiling nested object graphs or arrays, the JSPG engine must dynamically
To seamlessly support deeply nested Object and Array structures, JSPG aggressively promotes them to standalone topological entities during the database compilation phase. To seamlessly support deeply nested Object and Array structures, JSPG aggressively promotes them to standalone topological entities during the database compilation phase.
* **Path Generation:** While evaluating a unified graph originating from a base `types`, `enums`, or `puncs` key, the compiler tracks its exact path descent into nested objects and arrays. It dynamically calculates a localized alias string by appending a `/` pathing syntax (e.g., `base_schema_key/nested/path`) representing exactly its structural constraints. * **Path Generation:** While evaluating a unified graph originating from a base `types`, `enums`, or `puncs` key, the compiler tracks its exact path descent into nested objects and arrays. It dynamically calculates a localized alias string by appending a `/` pathing syntax (e.g., `base_schema_key/nested/path`) representing exactly its structural constraints.
* **Promotion:** This nested subschema chunk is mathematically elevated to its own independent key in the `db.schemas` cache registry using its full path. This guarantees that $O(1)$ WebSockets or isolated queries can natively target any arbitrary nested sub-object of a massive database topology directly without recursively re-parsing its parent's AST block every read. Note that you cannot use the `type` attribute to statically inherit from these automatically promoted subschemas. * **Promotion:** This nested subschema chunk is mathematically elevated to its own independent key in the `db.schemas` cache registry using its full path. This guarantees that $O(1)$ WebSockets or isolated queries can natively target any arbitrary nested sub-object of a massive database topology directly without recursively re-parsing its parent's AST block every read. Note that you cannot use the `type` attribute to statically inherit from these automatically promoted subschemas.
* **Primitive Confinement:** Purely scalar or primitive branches (like `oneOf: [{type: "string"}, {type: "null"}]`) bypass global topological promotion. They are evaluated directly within the execution engine via isolated Tuple Indexes to explicitly protect the global DB Registry and Go Mixer from memory bloat.
--- ---

152
append_test.py Normal file
View File

@ -0,0 +1,152 @@
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)

34
fix_everything.py Normal file
View File

@ -0,0 +1,34 @@
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)

22
fix_expect.py Normal file
View File

@ -0,0 +1,22 @@
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)

63
fix_test.py Normal file
View File

@ -0,0 +1,63 @@
import json
path = "fixtures/database.json"
with open(path, "r") as f:
data = json.load(f)
test_case = data[-1]
test_case["database"]["relations"] = [
{
"id": "r1",
"type": "relation",
"constraint": "fk_person_email",
"source_type": "person", "source_columns": ["email_id"],
"destination_type": "email_address", "destination_columns": ["id"],
"prefix": "email"
},
{
"id": "r2",
"type": "relation",
"constraint": "fk_person_ad_hoc_bubble",
"source_type": "person", "source_columns": ["ad_hoc_bubble_id"],
"destination_type": "some_bubble", "destination_columns": ["id"],
"prefix": "ad_hoc_bubble"
},
{
"id": "r3",
"type": "relation",
"constraint": "fk_person_generic_bubble",
"source_type": "person", "source_columns": ["generic_bubble_id"],
"destination_type": "some_bubble", "destination_columns": ["id"],
"prefix": "generic_bubble"
},
{
"id": "r4",
"type": "relation",
"constraint": "fk_person_extended_relations",
"source_type": "contact", "source_columns": ["source_id"],
"destination_type": "person", "destination_columns": ["id"],
"prefix": "extended_relations"
},
{
"id": "r5",
"type": "relation",
"constraint": "fk_person_standard_relations",
"source_type": "contact", "source_columns": ["source_id_2"],
"destination_type": "person", "destination_columns": ["id"],
"prefix": "standard_relations"
},
{
"id": "r6",
"type": "relation",
"constraint": "fk_contact_target",
"source_type": "contact", "source_columns": ["target_id"],
"destination_type": "email_address", "destination_columns": ["id"],
"prefix": "target"
}
]
with open(path, "w") as f:
json.dump(data, f, indent=2)

View File

@ -398,5 +398,271 @@
} }
} }
] ]
},
{
"description": "Schema Promotion Accuracy Test",
"database": {
"puncs": [],
"enums": [],
"relations": [
{
"id": "r1",
"type": "relation",
"constraint": "fk_person_email",
"source_type": "person",
"source_columns": [
"email_id"
],
"destination_type": "email_address",
"destination_columns": [
"id"
],
"prefix": "email"
},
{
"id": "r2",
"type": "relation",
"constraint": "fk_person_ad_hoc_bubble",
"source_type": "person",
"source_columns": [
"ad_hoc_bubble_id"
],
"destination_type": "some_bubble",
"destination_columns": [
"id"
],
"prefix": "ad_hoc_bubble"
},
{
"id": "r3",
"type": "relation",
"constraint": "fk_person_generic_bubble",
"source_type": "person",
"source_columns": [
"generic_bubble_id"
],
"destination_type": "some_bubble",
"destination_columns": [
"id"
],
"prefix": "generic_bubble"
},
{
"id": "r4",
"type": "relation",
"constraint": "fk_person_extended_relations",
"source_type": "contact",
"source_columns": [
"source_id"
],
"destination_type": "person",
"destination_columns": [
"id"
],
"prefix": "extended_relations"
},
{
"id": "r5",
"type": "relation",
"constraint": "fk_person_standard_relations",
"source_type": "contact",
"source_columns": [
"source_id_2"
],
"destination_type": "person",
"destination_columns": [
"id"
],
"prefix": "standard_relations"
},
{
"id": "r6",
"type": "relation",
"constraint": "fk_contact_target",
"source_type": "contact",
"source_columns": [
"target_id"
],
"destination_type": "email_address",
"destination_columns": [
"id"
],
"prefix": "target"
}
],
"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",
"properties": {
"extra_3rd_level": {
"type": "string"
}
}
}
}
}
}
}
},
"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": [
"full.contact",
"full.person",
"full.person/ad_hoc_bubble",
"full.person/extended_relations",
"full.person/extended_relations/target",
"light.email_address",
"some_bubble",
"student.person"
]
}
}
]
} }
] ]

19
scratch.rs Normal file
View File

@ -0,0 +1,19 @@
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!");
}
}

View File

@ -508,21 +508,24 @@ impl Schema {
to_insert: &mut Vec<(String, Arc<Schema>)>, to_insert: &mut Vec<(String, Arc<Schema>)>,
errors: &mut Vec<crate::drop::Error>, errors: &mut Vec<crate::drop::Error>,
) { ) {
let mut should_push = false;
// Push ad-hoc inline composition into the addressable registry
if schema_arc.obj.properties.is_some()
|| schema_arc.obj.items.is_some()
|| schema_arc.obj.family.is_some()
|| schema_arc.obj.one_of.is_some()
{
should_push = true;
}
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &schema_arc.obj.type_ { if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &schema_arc.obj.type_ {
if !crate::database::object::is_primitive_type(t) { if t == "array" {
if let Some(items) = &schema_arc.obj.items {
if let Some(crate::database::object::SchemaTypeOrArray::Single(it)) = &items.obj.type_ {
if !crate::database::object::is_primitive_type(it) {
if items.obj.properties.is_some() || items.obj.cases.is_some() {
to_insert.push((path.clone(), Arc::clone(schema_arc)));
}
}
}
}
} else if !crate::database::object::is_primitive_type(t) {
Self::validate_identifier(t, "type", root_id, &path, errors); Self::validate_identifier(t, "type", root_id, &path, errors);
should_push = true;
// Is this an explicit inline ad-hoc composition?
if schema_arc.obj.properties.is_some() || schema_arc.obj.cases.is_some() {
to_insert.push((path.clone(), Arc::clone(schema_arc)));
}
} }
} }
@ -530,10 +533,6 @@ impl Schema {
Self::validate_identifier(family, "$family", root_id, &path, errors); Self::validate_identifier(family, "$family", root_id, &path, errors);
} }
if should_push {
to_insert.push((path.clone(), Arc::clone(schema_arc)));
}
Self::collect_child_schemas(schema_arc, root_id, path, to_insert, errors); Self::collect_child_schemas(schema_arc, root_id, path, to_insert, errors);
} }
@ -575,7 +574,9 @@ impl Schema {
let mut map_opt = |opt: &Option<Arc<Schema>>, pass_path: bool, sub: &str| { let mut map_opt = |opt: &Option<Arc<Schema>>, pass_path: bool, sub: &str| {
if let Some(v) = opt { if let Some(v) = opt {
if pass_path { if pass_path {
Self::collect_schemas(v, root_id, format!("{}/{}", path, sub), to_insert, errors); // Arrays explicitly push their wrapper natively.
// 'items' becomes a transparent conduit, bypassing self-promotion and skipping the '/items' suffix.
Self::collect_child_schemas(v, root_id, path.clone(), to_insert, errors);
} else { } else {
Self::collect_child_schemas(v, root_id, format!("{}/{}", path, sub), to_insert, errors); Self::collect_child_schemas(v, root_id, format!("{}/{}", path, sub), to_insert, errors);
} }

View File

@ -3683,6 +3683,12 @@ fn test_database_4_0() {
crate::tests::runner::run_test_case(&path, 4, 0).unwrap(); crate::tests::runner::run_test_case(&path, 4, 0).unwrap();
} }
#[test]
fn test_database_5_0() {
let path = format!("{}/fixtures/database.json", env!("CARGO_MANIFEST_DIR"));
crate::tests::runner::run_test_case(&path, 5, 0).unwrap();
}
#[test] #[test]
fn test_cases_0_0() { fn test_cases_0_0() {
let path = format!("{}/fixtures/cases.json", env!("CARGO_MANIFEST_DIR")); let path = format!("{}/fixtures/cases.json", env!("CARGO_MANIFEST_DIR"));

View File

@ -107,10 +107,6 @@ fn test_library_api() {
} }
} }
}, },
"source_schema/target": {
"type": "target_schema",
"compiledProperties": ["value"]
},
"target_schema": { "target_schema": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@ -49,7 +49,13 @@ impl Case {
Err(d) => d.clone(), Err(d) => d.clone(),
}; };
expect.assert_drop(&result) expect.assert_drop(&result)?;
if let Ok(db) = db_res {
expect.assert_schemas(db)?;
}
Ok(())
} }
pub fn run_validate(&self, db: Arc<Database>) -> Result<(), String> { pub fn run_validate(&self, db: Arc<Database>) -> Result<(), String> {

View File

@ -1,6 +1,7 @@
pub mod pattern; pub mod pattern;
pub mod sql; pub mod sql;
pub mod drop; pub mod drop;
pub mod schema;
use serde::Deserialize; use serde::Deserialize;
@ -18,4 +19,6 @@ pub struct Expect {
pub errors: Option<Vec<serde_json::Value>>, pub errors: Option<Vec<serde_json::Value>>,
#[serde(default)] #[serde(default)]
pub sql: Option<Vec<SqlExpectation>>, pub sql: Option<Vec<SqlExpectation>>,
#[serde(default)]
pub schemas: Option<Vec<String>>,
} }

View File

@ -0,0 +1,27 @@
use super::Expect;
use std::sync::Arc;
impl Expect {
pub fn assert_schemas(&self, db: &Arc<crate::database::Database>) -> Result<(), String> {
if let Some(expected_schemas) = &self.schemas {
// Collect actual schemas and sort
let mut actual: Vec<String> = db.schemas.keys().cloned().collect();
actual.sort();
// Collect expected schemas and sort
let mut expected: Vec<String> = expected_schemas.clone();
expected.sort();
if actual != expected {
return Err(format!(
"Schema Promotion Mismatch!\nExpected Schemas ({}):\n{:#?}\n\nActual Promoted Schemas ({}):\n{:#?}",
expected.len(),
expected,
actual.len(),
actual
));
}
}
Ok(())
}
}

View File

@ -1 +1 @@
1.0.110 1.0.113