@jarenjs/db 0.56.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +412 -56
- package/README.md +600 -57
- package/docs/HOSTS.md +269 -0
- package/docs/JOBS-FORMAT.md +293 -45
- package/docs/LIVE-FORMAT.md +169 -20
- package/docs/MIGRATION-FORMAT.md +142 -17
- package/docs/MODEL-FORMAT.md +752 -64
- package/docs/REPLICATION-FORMAT.md +208 -0
- package/package.json +21 -7
- package/schemas/jaren-model.draft-07.schema.json +224 -162
- package/schemas/jaren-model.schema.json +224 -162
- package/schemas/jaren-replication-snapshot.draft-07.schema.json +83 -0
- package/schemas/jaren-replication-snapshot.schema.json +83 -0
- package/schemas/jaren-replication.draft-07.schema.json +82 -0
- package/schemas/jaren-replication.schema.json +82 -0
- package/src/algebra.js +227 -9
- package/src/backup.js +161 -0
- package/src/cancellation.js +48 -0
- package/src/capture.js +230 -47
- package/src/cli.js +165 -59
- package/src/cursor.js +417 -0
- package/src/dag-job.js +154 -21
- package/src/ddl.js +102 -8
- package/src/dialect.js +268 -113
- package/src/dialects/expression-read.js +158 -0
- package/src/dialects/postgres.js +618 -0
- package/src/dialects/rtree-ddl.js +129 -0
- package/src/dialects/sqlite.js +244 -11
- package/src/document-files.js +311 -0
- package/src/document-steps.js +422 -0
- package/src/documents.js +335 -0
- package/src/driver.js +448 -61
- package/src/drivers/bun.js +37 -1
- package/src/drivers/indexeddb-snapshot.js +149 -0
- package/src/drivers/node-pool.js +11 -0
- package/src/drivers/node-worker-endpoint.js +105 -0
- package/src/drivers/node-worker.js +204 -0
- package/src/drivers/node.js +41 -7
- package/src/drivers/postgres.js +331 -0
- package/src/drivers/wasm-oo1.js +97 -0
- package/src/drivers/wasm-session.js +67 -0
- package/src/drivers/wasm.js +17 -83
- package/src/drivers/worker-pool.js +183 -0
- package/src/drivers/worker-protocol.js +79 -0
- package/src/drivers/worker-queue.js +60 -0
- package/src/emit.js +339 -48
- package/src/entity.js +20 -22
- package/src/errors.js +430 -19
- package/src/expression.js +284 -0
- package/src/graph.js +64 -8
- package/src/index.js +48 -17
- package/src/introspect.js +583 -0
- package/src/jobs.js +843 -107
- package/src/json-bytes.js +58 -0
- package/src/live-join.js +250 -0
- package/src/live-nested.js +120 -0
- package/src/live.js +18 -4
- package/src/logical-rows.js +90 -0
- package/src/maintenance.js +175 -0
- package/src/migrate.js +248 -181
- package/src/model.js +68 -0
- package/src/plan.js +1119 -138
- package/src/pragmas.js +314 -0
- package/src/profile.js +151 -3
- package/src/query.js +1634 -323
- package/src/replication-format.js +115 -0
- package/src/replication.js +332 -0
- package/src/residual.js +17 -0
- package/src/series.js +12 -4
- package/src/store.js +1567 -273
- package/src/tracker.js +203 -29
- package/src/udf.js +88 -7
- package/types/index.d.ts +1158 -27
- package/types/node-pool.d.ts +28 -0
- package/types/node-worker.d.ts +54 -0
- package/types/node.d.ts +69 -2
- package/types/postgres.d.ts +46 -0
- package/types/typed.d.ts +27 -4
- package/types/wasm.d.ts +14 -0
package/src/model.js
CHANGED
|
@@ -516,6 +516,12 @@ export function relationTables(entities) {
|
|
|
516
516
|
kind: relation.kind,
|
|
517
517
|
joinTable: relation.joinTable,
|
|
518
518
|
targetKey: entities.get(relation.to).keys[0],
|
|
519
|
+
// the join row's two columns and the key each references, so a
|
|
520
|
+
// hop can lower through the join ROOT (§10.7) rather than
|
|
521
|
+
// refusing for want of one
|
|
522
|
+
ownColumn: `${entity.name}_key`,
|
|
523
|
+
ownKey: entity.keys[0],
|
|
524
|
+
targetColumn: `${relation.to}_key`,
|
|
519
525
|
}
|
|
520
526
|
: {
|
|
521
527
|
to: relation.to,
|
|
@@ -628,6 +634,13 @@ export function explainMapping(model) {
|
|
|
628
634
|
for (const declaring of entity.relations) {
|
|
629
635
|
const relation = declaring.relation;
|
|
630
636
|
if (relation.kind !== 'manyToMany' || seenJoins.has(relation.joinTable)) continue;
|
|
637
|
+
// a join table is a queryable ROOT (§10.7), so its name shares one
|
|
638
|
+
// namespace with the entities: a collision would make `$.X[*]`
|
|
639
|
+
// mean two things
|
|
640
|
+
if (entities.has(relation.joinTable)) {
|
|
641
|
+
throw modelError(`the join table '${relation.joinTable}' has the name of a declared `
|
|
642
|
+
+ 'entity, and both are query roots', declaring.docPath ?? entity.docPath);
|
|
643
|
+
}
|
|
631
644
|
seenJoins.add(relation.joinTable);
|
|
632
645
|
const [a, b] = [entity.name, relation.to].sort();
|
|
633
646
|
mapping.joinTables[relation.joinTable] = {
|
|
@@ -639,3 +652,58 @@ export function explainMapping(model) {
|
|
|
639
652
|
}
|
|
640
653
|
return mapping;
|
|
641
654
|
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* The read-only query ROOTS a model's join tables contribute (§10.7):
|
|
658
|
+
* one pseudo-entity per declared many-to-many join table, carrying
|
|
659
|
+
* exactly its two key columns and no document of its own. They are
|
|
660
|
+
* queryable — `$.<JoinTable>[*]` binds like any entity array — and they
|
|
661
|
+
* are NOT writable: `store.entity(name)` reads the model's own entity
|
|
662
|
+
* map, which these are deliberately not in, so a membership is still
|
|
663
|
+
* written through `link`/`unlink` and the tracker's join rows.
|
|
664
|
+
* @param {Map<string, any>} entities - the normalized entities
|
|
665
|
+
* @param {any} mapping - `explainMapping(...)`
|
|
666
|
+
* @returns {{ entities: Map<string, any>, mappings: Record<string, any> }}
|
|
667
|
+
*/
|
|
668
|
+
export function joinTableRoots(entities, mapping) {
|
|
669
|
+
/** @type {Map<string, any>} */
|
|
670
|
+
const roots = new Map();
|
|
671
|
+
/** @type {any} */
|
|
672
|
+
const mappings = {};
|
|
673
|
+
for (const [name, join] of Object.entries(mapping.joinTables ?? {})) {
|
|
674
|
+
const sides = [join.left, join.right];
|
|
675
|
+
/** @type {any} */
|
|
676
|
+
const properties = new Map();
|
|
677
|
+
/** @type {any} */
|
|
678
|
+
const schemaProperties = {};
|
|
679
|
+
const columns = [];
|
|
680
|
+
for (const side of sides) {
|
|
681
|
+
const referenced = entities.get(side.entity).properties.get(side.referencesKey);
|
|
682
|
+
properties.set(side.column, { name: side.column, type: referenced.type, key: true });
|
|
683
|
+
schemaProperties[side.column] = { type: referenced.type };
|
|
684
|
+
columns.push({ name: side.column, storage: referenced.type, source: 'column' });
|
|
685
|
+
}
|
|
686
|
+
roots.set(name, {
|
|
687
|
+
name,
|
|
688
|
+
docPath: `/entities/${sides[0].entity}` ,
|
|
689
|
+
schema: { type: 'object', required: sides.map((side) => side.column),
|
|
690
|
+
properties: schemaProperties },
|
|
691
|
+
properties,
|
|
692
|
+
keys: sides.map((side) => side.column),
|
|
693
|
+
relations: [],
|
|
694
|
+
version: null,
|
|
695
|
+
joinTable: true,
|
|
696
|
+
});
|
|
697
|
+
mappings[name] = {
|
|
698
|
+
table: name,
|
|
699
|
+
columns,
|
|
700
|
+
foreignKeys: [],
|
|
701
|
+
indexes: [],
|
|
702
|
+
keys: sides.map((side) => side.column),
|
|
703
|
+
// a join row IS its two keys: there is no document column to read,
|
|
704
|
+
// and the merge is handed an empty one
|
|
705
|
+
document: false,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
return { entities: roots, mappings };
|
|
709
|
+
}
|