@rebasepro/server-postgres 0.10.1-canary.ed8caed → 0.10.1-canary.gdaf6ba4
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/dist/auth/schema-version.d.ts +106 -0
- package/dist/collections/validate-relations.d.ts +53 -0
- package/dist/data-transformer.d.ts +3 -3
- package/dist/{ensure-collection-tables-BVvtkkRm.js → ensure-collection-tables-DGMYK0fr.js} +5 -5
- package/dist/ensure-collection-tables-DGMYK0fr.js.map +1 -0
- package/dist/index.es.js +610 -313
- package/dist/index.es.js.map +1 -1
- package/dist/services/RelationService.d.ts +9 -8
- package/dist/services/cdc/junction-tables.d.ts +38 -0
- package/dist/services/nested-path.d.ts +3 -3
- package/dist/services/realtimeService.d.ts +19 -0
- package/dist/services/row-pipeline.d.ts +2 -2
- package/dist/{src-lcfUP4xg.js → src-3VmUJ8Xn.js} +135 -247
- package/dist/src-3VmUJ8Xn.js.map +1 -0
- package/dist/{src-CBgtrPhJ.js → src-D5xBTl32.js} +12 -2
- package/dist/src-D5xBTl32.js.map +1 -0
- package/dist/utils/drizzle-conditions.d.ts +35 -23
- package/package.json +6 -6
- package/src/PostgresBootstrapper.ts +15 -2
- package/src/auth/ensure-tables.ts +23 -0
- package/src/auth/schema-version.ts +260 -0
- package/src/cli-errors.ts +1 -1
- package/src/cli-helpers.ts +4 -3
- package/src/collections/PostgresCollectionRegistry.ts +9 -4
- package/src/collections/buildRegistry.ts +7 -0
- package/src/collections/validate-relations.ts +280 -0
- package/src/data-transformer.ts +28 -38
- package/src/schema/doctor.ts +8 -8
- package/src/schema/generate-drizzle-schema-logic.ts +49 -101
- package/src/schema/generate-postgres-ddl-logic.ts +9 -9
- package/src/schema/introspect-db-logic.ts +19 -23
- package/src/services/FetchService.ts +12 -12
- package/src/services/PersistService.ts +23 -27
- package/src/services/RelationService.ts +65 -83
- package/src/services/cdc/junction-tables.ts +91 -0
- package/src/services/nested-path.ts +24 -9
- package/src/services/realtimeService.ts +60 -0
- package/src/services/row-pipeline.ts +5 -6
- package/src/utils/drizzle-conditions.ts +177 -382
- package/dist/ensure-collection-tables-BVvtkkRm.js.map +0 -1
- package/dist/src-CBgtrPhJ.js.map +0 -1
- package/dist/src-lcfUP4xg.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DrizzleClient } from "../interfaces";
|
|
2
|
-
import { CollectionConfig, FilterValues,
|
|
2
|
+
import { CollectionConfig, FilterValues, ResolvedRelation, ResolvedManyToMany } from "@rebasepro/types";
|
|
3
|
+
import { type ResolvedVia } from "@rebasepro/types";
|
|
3
4
|
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
5
|
import type { NestedPathHop } from "./nested-path";
|
|
5
6
|
/**
|
|
@@ -70,7 +71,7 @@ export declare class RelationService {
|
|
|
70
71
|
/**
|
|
71
72
|
* Fetch rows using join paths for complex relations
|
|
72
73
|
*/
|
|
73
|
-
fetchEntitiesUsingJoins<M extends Record<string, unknown>>(parentCollection: CollectionConfig, parentId: string | number, relation:
|
|
74
|
+
fetchEntitiesUsingJoins<M extends Record<string, unknown>>(parentCollection: CollectionConfig, parentId: string | number, relation: ResolvedRelation, options?: {
|
|
74
75
|
filter?: FilterValues<Extract<keyof M, string>>;
|
|
75
76
|
orderBy?: string;
|
|
76
77
|
order?: "desc" | "asc";
|
|
@@ -118,13 +119,13 @@ export declare class RelationService {
|
|
|
118
119
|
/**
|
|
119
120
|
* Batch fetch related rows for multiple parent rows to avoid N+1 queries
|
|
120
121
|
*/
|
|
121
|
-
batchFetchRelatedEntities(parentCollectionPath: string, parentIds: (string | number)[], _relationKey: string, relation:
|
|
122
|
+
batchFetchRelatedEntities(parentCollectionPath: string, parentIds: (string | number)[], _relationKey: string, relation: ResolvedRelation): Promise<Map<string, RelatedRow<Record<string, unknown>>>>;
|
|
122
123
|
/**
|
|
123
124
|
* Batch fetch many-cardinality related rows for multiple parent rows.
|
|
124
125
|
* Returns a Map<parentId, RelatedRow[]> instead of Map<parentId, RelatedRow>.
|
|
125
126
|
* Uses a single SQL query with IN clause to avoid N+1.
|
|
126
127
|
*/
|
|
127
|
-
batchFetchRelatedEntitiesMany(parentCollectionPath: string, parentIds: (string | number)[], _relationKey: string, relation:
|
|
128
|
+
batchFetchRelatedEntitiesMany(parentCollectionPath: string, parentIds: (string | number)[], _relationKey: string, relation: ResolvedRelation): Promise<Map<string, RelatedRow<Record<string, unknown>>[]>>;
|
|
128
129
|
/**
|
|
129
130
|
* Update many-to-many and junction relations
|
|
130
131
|
*/
|
|
@@ -134,7 +135,7 @@ export declare class RelationService {
|
|
|
134
135
|
*/
|
|
135
136
|
updateInverseRelations(tx: DrizzleClient, sourceCollection: CollectionConfig, sourceEntityId: string | number, inverseRelationUpdates: Array<{
|
|
136
137
|
relationKey: string;
|
|
137
|
-
relation:
|
|
138
|
+
relation: ResolvedRelation;
|
|
138
139
|
newValue: unknown;
|
|
139
140
|
}>): Promise<void>;
|
|
140
141
|
/**
|
|
@@ -150,13 +151,13 @@ export declare class RelationService {
|
|
|
150
151
|
*/
|
|
151
152
|
updateJoinPathOneToOneRelations(tx: DrizzleClient, parentCollection: CollectionConfig, parentId: string | number, updates: Array<{
|
|
152
153
|
relationKey: string;
|
|
153
|
-
relation:
|
|
154
|
+
relation: ResolvedVia;
|
|
154
155
|
newTargetId: string | number | null;
|
|
155
156
|
}>): Promise<void>;
|
|
156
157
|
/**
|
|
157
158
|
* Resolve joinPath write mapping for one-to-one relations
|
|
158
159
|
*/
|
|
159
|
-
resolveJoinPathWriteMapping(parentCollection: CollectionConfig, relation:
|
|
160
|
+
resolveJoinPathWriteMapping(parentCollection: CollectionConfig, relation: ResolvedVia): {
|
|
160
161
|
targetFKColName: string;
|
|
161
162
|
parentSourceColName: string;
|
|
162
163
|
};
|
|
@@ -166,7 +167,7 @@ export declare class RelationService {
|
|
|
166
167
|
handleJunctionTableCreation(tx: DrizzleClient, newEntityId: string | number, junctionTableInfo: {
|
|
167
168
|
parentCollection: CollectionConfig;
|
|
168
169
|
parentId: string | number;
|
|
169
|
-
relation:
|
|
170
|
+
relation: ResolvedManyToMany;
|
|
170
171
|
relationKey: string;
|
|
171
172
|
}): Promise<void>;
|
|
172
173
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { CollectionConfig } from "@rebasepro/types";
|
|
2
|
+
import { PostgresCollectionRegistry } from "../../collections/PostgresCollectionRegistry";
|
|
3
|
+
/**
|
|
4
|
+
* One end of a many-to-many, as seen from the junction table.
|
|
5
|
+
*
|
|
6
|
+
* A junction table is not a collection, so nothing in the registry maps it to
|
|
7
|
+
* one — which is why a change to it was invisible to change capture. But its
|
|
8
|
+
* rows are exactly the contents of a parent's child list, so a write to it is a
|
|
9
|
+
* change to `<parentSlug>/<sourceId>/<relationKey>` and to nothing else.
|
|
10
|
+
*/
|
|
11
|
+
export interface JunctionLink {
|
|
12
|
+
schema: string;
|
|
13
|
+
/** The junction table itself, e.g. `posts_tags`. */
|
|
14
|
+
table: string;
|
|
15
|
+
/** The collection whose relation this is, e.g. `posts`. */
|
|
16
|
+
parentCollection: CollectionConfig;
|
|
17
|
+
/** The relation's key — the path segment a child list is addressed by. */
|
|
18
|
+
relationKey: string;
|
|
19
|
+
/** Junction column holding the parent's id. */
|
|
20
|
+
sourceColumn: string;
|
|
21
|
+
/** Junction column holding the target's id. */
|
|
22
|
+
targetColumn: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Every junction table reachable from a registered collection, once per
|
|
26
|
+
* relation that uses it.
|
|
27
|
+
*
|
|
28
|
+
* A junction is listed once per *direction* when both sides declare it, because
|
|
29
|
+
* each direction addresses a different child list: `posts/1/tags` and
|
|
30
|
+
* `tags/t/posts` both change when one link is written.
|
|
31
|
+
*/
|
|
32
|
+
export declare function collectJunctionLinks(registry: PostgresCollectionRegistry): JunctionLink[];
|
|
33
|
+
/**
|
|
34
|
+
* Index {@link collectJunctionLinks} by table, under both the qualified and the
|
|
35
|
+
* bare name — a change event carries whatever the trigger reports, and a
|
|
36
|
+
* collection need not declare a schema.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildJunctionLinkMap(registry: PostgresCollectionRegistry): Map<string, JunctionLink[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CollectionConfig,
|
|
1
|
+
import { CollectionConfig, ResolvedRelation } from "@rebasepro/types";
|
|
2
2
|
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
3
3
|
/**
|
|
4
4
|
* The last hop of a nested collection path, e.g. `authors/1/posts`.
|
|
@@ -16,7 +16,7 @@ export interface NestedPathHop {
|
|
|
16
16
|
parentId: string;
|
|
17
17
|
/** The path segment that named the relation (e.g. `posts`). */
|
|
18
18
|
relationKey: string;
|
|
19
|
-
relation:
|
|
19
|
+
relation: ResolvedRelation;
|
|
20
20
|
/** `relation.target()`, resolved once. */
|
|
21
21
|
targetCollection: CollectionConfig;
|
|
22
22
|
}
|
|
@@ -45,7 +45,7 @@ export declare function resolveNestedPath(path: string, registry: PostgresCollec
|
|
|
45
45
|
* `joinPath`. The target row is shared with other parents, so writing "through"
|
|
46
46
|
* such a path addresses the *link*, not the row.
|
|
47
47
|
*/
|
|
48
|
-
export declare function isJunctionBackedRelation(relation:
|
|
48
|
+
export declare function isJunctionBackedRelation(relation: ResolvedRelation): boolean;
|
|
49
49
|
/**
|
|
50
50
|
* Reject a nested write whose final segment is a to-one relation.
|
|
51
51
|
*
|
|
@@ -95,6 +95,8 @@ export declare class RealtimeService extends EventEmitter implements RealtimePro
|
|
|
95
95
|
private cdcListener?;
|
|
96
96
|
/** Whether database-level CDC is the active cross-instance change source. */
|
|
97
97
|
private cdcActive;
|
|
98
|
+
/** Junction table → the child lists its rows belong to, built when CDC starts. */
|
|
99
|
+
private junctionLinkMap?;
|
|
98
100
|
/** Reverse lookup: `schema.table` (and bare `table`) → collection, built when CDC starts. */
|
|
99
101
|
private cdcTableMap?;
|
|
100
102
|
/**
|
|
@@ -437,6 +439,23 @@ export declare class RealtimeService extends EventEmitter implements RealtimePro
|
|
|
437
439
|
* subscriber, never per publisher.
|
|
438
440
|
*/
|
|
439
441
|
private handleCdcEvent;
|
|
442
|
+
/**
|
|
443
|
+
* Deliver a change on a many-to-many junction table as a change to the child
|
|
444
|
+
* lists it belongs to.
|
|
445
|
+
*
|
|
446
|
+
* Linking a tag to a post writes only `posts_tags`. That table backs no
|
|
447
|
+
* collection, so change capture dropped the event as unmapped and the
|
|
448
|
+
* subscribers of `posts/1/tags` never heard about it — every other write in
|
|
449
|
+
* the system was realtime, and this one silently was not. The junction row
|
|
450
|
+
* carries both ids, so it names its own paths exactly.
|
|
451
|
+
*
|
|
452
|
+
* Notifies the nested path rather than either endpoint collection, because
|
|
453
|
+
* invalidation walks *parent* paths and never child ones: telling `tags` it
|
|
454
|
+
* changed would not reach a subscription on `posts/1/tags`.
|
|
455
|
+
*
|
|
456
|
+
* Returns whether the table was recognised as a junction.
|
|
457
|
+
*/
|
|
458
|
+
private handleJunctionCdcEvent;
|
|
440
459
|
/** Compute the canonical (possibly composite) id string from a captured row. */
|
|
441
460
|
private extractIdFromCdcRow;
|
|
442
461
|
private dedupKey;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CollectionConfig,
|
|
1
|
+
import { CollectionConfig, ResolvedRelation } from "@rebasepro/types";
|
|
2
2
|
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
3
3
|
/**
|
|
4
4
|
* Turning a drizzle result into a row we serve.
|
|
@@ -26,7 +26,7 @@ export type RelationStyle = "ref" | "inline";
|
|
|
26
26
|
* the query has to nest one level deeper for a junction, and the row walk has
|
|
27
27
|
* to unwrap that same level back out.
|
|
28
28
|
*/
|
|
29
|
-
export declare function isJunctionRelation(relation:
|
|
29
|
+
export declare function isJunctionRelation(relation: ResolvedRelation): boolean;
|
|
30
30
|
/**
|
|
31
31
|
* The address a relation ref points at.
|
|
32
32
|
*
|