@rebasepro/server-postgresql 0.0.1-canary.4d4fb3e
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/LICENSE +6 -0
- package/README.md +106 -0
- package/build-errors.txt +37 -0
- package/dist/common/src/collections/CollectionRegistry.d.ts +48 -0
- package/dist/common/src/collections/index.d.ts +1 -0
- package/dist/common/src/data/buildRebaseData.d.ts +14 -0
- package/dist/common/src/index.d.ts +3 -0
- package/dist/common/src/util/builders.d.ts +57 -0
- package/dist/common/src/util/callbacks.d.ts +6 -0
- package/dist/common/src/util/collections.d.ts +11 -0
- package/dist/common/src/util/common.d.ts +2 -0
- package/dist/common/src/util/conditions.d.ts +26 -0
- package/dist/common/src/util/entities.d.ts +36 -0
- package/dist/common/src/util/enums.d.ts +3 -0
- package/dist/common/src/util/index.d.ts +16 -0
- package/dist/common/src/util/navigation_from_path.d.ts +34 -0
- package/dist/common/src/util/navigation_utils.d.ts +20 -0
- package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
- package/dist/common/src/util/paths.d.ts +14 -0
- package/dist/common/src/util/permissions.d.ts +5 -0
- package/dist/common/src/util/references.d.ts +2 -0
- package/dist/common/src/util/relations.d.ts +12 -0
- package/dist/common/src/util/resolutions.d.ts +72 -0
- package/dist/common/src/util/storage.d.ts +24 -0
- package/dist/index.es.js +10635 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +10643 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +112 -0
- package/dist/server-postgresql/src/PostgresBootstrapper.d.ts +40 -0
- package/dist/server-postgresql/src/auth/ensure-tables.d.ts +6 -0
- package/dist/server-postgresql/src/auth/services.d.ts +188 -0
- package/dist/server-postgresql/src/cli.d.ts +1 -0
- package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +43 -0
- package/dist/server-postgresql/src/connection.d.ts +7 -0
- package/dist/server-postgresql/src/data-transformer.d.ts +36 -0
- package/dist/server-postgresql/src/databasePoolManager.d.ts +20 -0
- package/dist/server-postgresql/src/history/HistoryService.d.ts +71 -0
- package/dist/server-postgresql/src/history/ensure-history-table.d.ts +7 -0
- package/dist/server-postgresql/src/index.d.ts +13 -0
- package/dist/server-postgresql/src/interfaces.d.ts +18 -0
- package/dist/server-postgresql/src/schema/auth-schema.d.ts +767 -0
- package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +2 -0
- package/dist/server-postgresql/src/schema/generate-drizzle-schema.d.ts +1 -0
- package/dist/server-postgresql/src/services/BranchService.d.ts +47 -0
- package/dist/server-postgresql/src/services/EntityFetchService.d.ts +195 -0
- package/dist/server-postgresql/src/services/EntityPersistService.d.ts +41 -0
- package/dist/server-postgresql/src/services/RelationService.d.ts +92 -0
- package/dist/server-postgresql/src/services/entity-helpers.d.ts +24 -0
- package/dist/server-postgresql/src/services/entityService.d.ts +102 -0
- package/dist/server-postgresql/src/services/index.d.ts +4 -0
- package/dist/server-postgresql/src/services/realtimeService.d.ts +186 -0
- package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +116 -0
- package/dist/server-postgresql/src/websocket.d.ts +5 -0
- package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
- package/dist/types/src/controllers/auth.d.ts +117 -0
- package/dist/types/src/controllers/client.d.ts +58 -0
- package/dist/types/src/controllers/collection_registry.d.ts +44 -0
- package/dist/types/src/controllers/customization_controller.d.ts +54 -0
- package/dist/types/src/controllers/data.d.ts +141 -0
- package/dist/types/src/controllers/data_driver.d.ts +168 -0
- package/dist/types/src/controllers/database_admin.d.ts +11 -0
- package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
- package/dist/types/src/controllers/effective_role.d.ts +4 -0
- package/dist/types/src/controllers/index.d.ts +17 -0
- package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
- package/dist/types/src/controllers/navigation.d.ts +213 -0
- package/dist/types/src/controllers/registry.d.ts +51 -0
- package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
- package/dist/types/src/controllers/side_entity_controller.d.ts +89 -0
- package/dist/types/src/controllers/snackbar.d.ts +24 -0
- package/dist/types/src/controllers/storage.d.ts +173 -0
- package/dist/types/src/index.d.ts +4 -0
- package/dist/types/src/rebase_context.d.ts +101 -0
- package/dist/types/src/types/backend.d.ts +533 -0
- package/dist/types/src/types/builders.d.ts +14 -0
- package/dist/types/src/types/chips.d.ts +5 -0
- package/dist/types/src/types/collections.d.ts +812 -0
- package/dist/types/src/types/data_source.d.ts +64 -0
- package/dist/types/src/types/entities.d.ts +145 -0
- package/dist/types/src/types/entity_actions.d.ts +98 -0
- package/dist/types/src/types/entity_callbacks.d.ts +173 -0
- package/dist/types/src/types/entity_link_builder.d.ts +7 -0
- package/dist/types/src/types/entity_overrides.d.ts +9 -0
- package/dist/types/src/types/entity_views.d.ts +61 -0
- package/dist/types/src/types/export_import.d.ts +21 -0
- package/dist/types/src/types/index.d.ts +22 -0
- package/dist/types/src/types/locales.d.ts +4 -0
- package/dist/types/src/types/modify_collections.d.ts +5 -0
- package/dist/types/src/types/plugins.d.ts +225 -0
- package/dist/types/src/types/properties.d.ts +1091 -0
- package/dist/types/src/types/property_config.d.ts +70 -0
- package/dist/types/src/types/relations.d.ts +336 -0
- package/dist/types/src/types/slots.d.ts +228 -0
- package/dist/types/src/types/translations.d.ts +826 -0
- package/dist/types/src/types/user_management_delegate.d.ts +120 -0
- package/dist/types/src/types/websockets.d.ts +78 -0
- package/dist/types/src/users/index.d.ts +2 -0
- package/dist/types/src/users/roles.d.ts +22 -0
- package/dist/types/src/users/user.d.ts +46 -0
- package/jest-all.log +3128 -0
- package/jest.log +49 -0
- package/package.json +93 -0
- package/src/PostgresBackendDriver.ts +1024 -0
- package/src/PostgresBootstrapper.ts +232 -0
- package/src/auth/ensure-tables.ts +309 -0
- package/src/auth/services.ts +740 -0
- package/src/cli.ts +347 -0
- package/src/collections/PostgresCollectionRegistry.ts +96 -0
- package/src/connection.ts +62 -0
- package/src/data-transformer.ts +569 -0
- package/src/databasePoolManager.ts +84 -0
- package/src/history/HistoryService.ts +257 -0
- package/src/history/ensure-history-table.ts +45 -0
- package/src/index.ts +13 -0
- package/src/interfaces.ts +60 -0
- package/src/schema/auth-schema.ts +146 -0
- package/src/schema/generate-drizzle-schema-logic.ts +618 -0
- package/src/schema/generate-drizzle-schema.ts +151 -0
- package/src/services/BranchService.ts +237 -0
- package/src/services/EntityFetchService.ts +1447 -0
- package/src/services/EntityPersistService.ts +351 -0
- package/src/services/RelationService.ts +1012 -0
- package/src/services/entity-helpers.ts +121 -0
- package/src/services/entityService.ts +209 -0
- package/src/services/index.ts +13 -0
- package/src/services/realtimeService.ts +1005 -0
- package/src/utils/drizzle-conditions.ts +999 -0
- package/src/websocket.ts +487 -0
- package/test/auth-services.test.ts +569 -0
- package/test/branchService.test.ts +357 -0
- package/test/drizzle-conditions.test.ts +895 -0
- package/test/entityService.errors.test.ts +352 -0
- package/test/entityService.relations.test.ts +912 -0
- package/test/entityService.subcollection-search.test.ts +516 -0
- package/test/entityService.test.ts +977 -0
- package/test/generate-drizzle-schema.test.ts +795 -0
- package/test/historyService.test.ts +126 -0
- package/test/postgresDataDriver.test.ts +556 -0
- package/test/realtimeService.test.ts +276 -0
- package/test/relations.test.ts +662 -0
- package/test_drizzle_mock.js +3 -0
- package/test_find_changed.mjs +30 -0
- package/test_output.txt +3145 -0
- package/tsconfig.json +49 -0
- package/tsconfig.prod.json +20 -0
- package/vite.config.ts +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BranchService
|
|
3
|
+
*
|
|
4
|
+
* Manages database branching by creating/deleting PostgreSQL databases
|
|
5
|
+
* using `CREATE DATABASE ... TEMPLATE`. Branch metadata is stored in the
|
|
6
|
+
* `rebase.branches` table in the default (main) database, following the
|
|
7
|
+
* same `rebase` schema convention used by entity_history, auth, etc.
|
|
8
|
+
*/
|
|
9
|
+
import { BranchInfo } from "@rebasepro/types";
|
|
10
|
+
import { DrizzleClient } from "../interfaces";
|
|
11
|
+
import { DatabasePoolManager } from "../databasePoolManager";
|
|
12
|
+
export declare class BranchService {
|
|
13
|
+
private db;
|
|
14
|
+
private poolManager;
|
|
15
|
+
constructor(db: DrizzleClient, poolManager: DatabasePoolManager);
|
|
16
|
+
/**
|
|
17
|
+
* Ensure the `rebase.branches` metadata table exists in the default database.
|
|
18
|
+
* Idempotent — safe to call on every startup.
|
|
19
|
+
*/
|
|
20
|
+
ensureBranchMetadataTable(): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a new branch database by templating the source database.
|
|
23
|
+
*
|
|
24
|
+
* Uses `CREATE DATABASE ... TEMPLATE` for an instant, full-fidelity copy
|
|
25
|
+
* of both schema and data.
|
|
26
|
+
*
|
|
27
|
+
* @param name User-facing branch name (e.g., "feature_auth")
|
|
28
|
+
* @param options.source Source database to clone; defaults to the main database.
|
|
29
|
+
*/
|
|
30
|
+
createBranch(name: string, options?: {
|
|
31
|
+
source?: string;
|
|
32
|
+
}): Promise<BranchInfo>;
|
|
33
|
+
/**
|
|
34
|
+
* Delete a branch database and remove its metadata.
|
|
35
|
+
* Cannot delete the main/default database.
|
|
36
|
+
*/
|
|
37
|
+
deleteBranch(name: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* List all branches recorded in the metadata table.
|
|
40
|
+
* Optionally fetches database sizes from pg_database.
|
|
41
|
+
*/
|
|
42
|
+
listBranches(): Promise<BranchInfo[]>;
|
|
43
|
+
/**
|
|
44
|
+
* Get info about a specific branch.
|
|
45
|
+
*/
|
|
46
|
+
getBranchInfo(name: string): Promise<BranchInfo | undefined>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { SQL } from "drizzle-orm";
|
|
2
|
+
import { PgTable } from "drizzle-orm/pg-core";
|
|
3
|
+
import { Entity, FilterValues } from "@rebasepro/types";
|
|
4
|
+
import { RelationService } from "./RelationService";
|
|
5
|
+
import { DrizzleClient } from "../interfaces";
|
|
6
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
7
|
+
/**
|
|
8
|
+
* Service for handling all entity read operations.
|
|
9
|
+
* Handles fetching, searching, counting, and filtering entities.
|
|
10
|
+
*/
|
|
11
|
+
export declare class EntityFetchService {
|
|
12
|
+
private db;
|
|
13
|
+
private registry;
|
|
14
|
+
private relationService;
|
|
15
|
+
constructor(db: DrizzleClient, registry: PostgresCollectionRegistry);
|
|
16
|
+
/**
|
|
17
|
+
* Get the relational query builder for a given table name.
|
|
18
|
+
* Safely narrows the DrizzleClient union type to access db.query[tableName].
|
|
19
|
+
*/
|
|
20
|
+
private getQueryBuilder;
|
|
21
|
+
/**
|
|
22
|
+
* Build filter conditions from FilterValues
|
|
23
|
+
* Delegates to DrizzleConditionBuilder.buildFilterConditions
|
|
24
|
+
*/
|
|
25
|
+
buildFilterConditions<M extends Record<string, any>>(filter: FilterValues<Extract<keyof M, string>>, table: PgTable<any>, collectionPath: string): SQL[];
|
|
26
|
+
/**
|
|
27
|
+
* Build the `with` config for Drizzle's relational query API.
|
|
28
|
+
* Converts collection relations to a Drizzle-compatible `with` object.
|
|
29
|
+
*
|
|
30
|
+
* When `include` is provided, only those relations are loaded.
|
|
31
|
+
* When `include` is absent, ALL relations are loaded (CMS path).
|
|
32
|
+
*
|
|
33
|
+
* Automatically detects many-to-many junction tables and nests
|
|
34
|
+
* the target relation so actual entity data is returned.
|
|
35
|
+
*/
|
|
36
|
+
private buildWithConfig;
|
|
37
|
+
/**
|
|
38
|
+
* Detect if a many-to-many relation uses a junction table in the Drizzle schema.
|
|
39
|
+
*/
|
|
40
|
+
private isJunctionRelation;
|
|
41
|
+
/**
|
|
42
|
+
* Get the Drizzle relation name on the junction table that points to the actual target entity.
|
|
43
|
+
* For example, for posts_tags junction, this returns "tag_id" (the relation pointing to tags).
|
|
44
|
+
*/
|
|
45
|
+
private getJunctionTargetRelationName;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a db.query result row (with nested relation objects) to an Entity<M>.
|
|
48
|
+
* Handles:
|
|
49
|
+
* - The { id, path, values } wrapping
|
|
50
|
+
* - Type normalization (dates, numbers, NaN) via normalizeDbValues
|
|
51
|
+
* - Converting nested relation objects to { id, path, __type: "relation" } for CMS
|
|
52
|
+
* - Flattening junction-table many-to-many results
|
|
53
|
+
*/
|
|
54
|
+
private drizzleResultToEntity;
|
|
55
|
+
/**
|
|
56
|
+
* Post-fetch joinPath relations for a single entity.
|
|
57
|
+
* joinPath relations cannot be expressed via Drizzle's `with` config,
|
|
58
|
+
* so they must be loaded separately after the primary query.
|
|
59
|
+
*/
|
|
60
|
+
private resolveJoinPathRelations;
|
|
61
|
+
/**
|
|
62
|
+
* Post-fetch joinPath relations for a batch of entities.
|
|
63
|
+
* Uses batch fetching to avoid N+1 queries for list views.
|
|
64
|
+
*/
|
|
65
|
+
private resolveJoinPathRelationsBatch;
|
|
66
|
+
/**
|
|
67
|
+
* Convert a db.query result row to a flat REST-style object with populated relations.
|
|
68
|
+
*/
|
|
69
|
+
private drizzleResultToRestRow;
|
|
70
|
+
/**
|
|
71
|
+
* Build db.query-compatible options from standard fetch options.
|
|
72
|
+
* Handles filter, search, orderBy, limit, and cursor-based pagination.
|
|
73
|
+
*/
|
|
74
|
+
private buildDrizzleQueryOptions;
|
|
75
|
+
/**
|
|
76
|
+
* Extract cursor pagination conditions from startAfter options.
|
|
77
|
+
*/
|
|
78
|
+
private buildCursorConditions;
|
|
79
|
+
/**
|
|
80
|
+
* Fetch a single entity by ID
|
|
81
|
+
*/
|
|
82
|
+
fetchEntity<M extends Record<string, any>>(collectionPath: string, entityId: string | number, databaseId?: string): Promise<Entity<M> | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* Unified method to fetch entities with optional search functionality
|
|
85
|
+
*/
|
|
86
|
+
fetchEntitiesWithConditions<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
87
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
88
|
+
orderBy?: string;
|
|
89
|
+
order?: "desc" | "asc";
|
|
90
|
+
limit?: number;
|
|
91
|
+
startAfter?: Record<string, unknown>;
|
|
92
|
+
searchString?: string;
|
|
93
|
+
databaseId?: string;
|
|
94
|
+
}): Promise<Entity<M>[]>;
|
|
95
|
+
/**
|
|
96
|
+
* Fallback path used when db.query is unavailable.
|
|
97
|
+
* The primary path uses drizzleResultToEntity which handles relation
|
|
98
|
+
* mapping without N+1 queries.
|
|
99
|
+
*
|
|
100
|
+
* Process raw database results into Entity objects with relations.
|
|
101
|
+
*/
|
|
102
|
+
private processEntityResults;
|
|
103
|
+
/**
|
|
104
|
+
* Fetch a collection of entities
|
|
105
|
+
*/
|
|
106
|
+
fetchCollection<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
107
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
108
|
+
orderBy?: string;
|
|
109
|
+
order?: "desc" | "asc";
|
|
110
|
+
limit?: number;
|
|
111
|
+
startAfter?: Record<string, unknown>;
|
|
112
|
+
searchString?: string;
|
|
113
|
+
databaseId?: string;
|
|
114
|
+
}): Promise<Entity<M>[]>;
|
|
115
|
+
/**
|
|
116
|
+
* Search entities by text
|
|
117
|
+
*/
|
|
118
|
+
searchEntities<M extends Record<string, any>>(collectionPath: string, searchString: string, options?: {
|
|
119
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
120
|
+
orderBy?: string;
|
|
121
|
+
order?: "desc" | "asc";
|
|
122
|
+
limit?: number;
|
|
123
|
+
databaseId?: string;
|
|
124
|
+
}): Promise<Entity<M>[]>;
|
|
125
|
+
/**
|
|
126
|
+
* Fetch collection from multi-segment path
|
|
127
|
+
*/
|
|
128
|
+
private fetchCollectionFromPath;
|
|
129
|
+
/**
|
|
130
|
+
* Count entities in a collection
|
|
131
|
+
*/
|
|
132
|
+
countEntities<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
133
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
134
|
+
databaseId?: string;
|
|
135
|
+
}): Promise<number>;
|
|
136
|
+
/**
|
|
137
|
+
* Count entities from multi-segment path
|
|
138
|
+
*/
|
|
139
|
+
private countEntitiesFromPath;
|
|
140
|
+
/**
|
|
141
|
+
* Check if a field value is unique
|
|
142
|
+
*/
|
|
143
|
+
checkUniqueField(collectionPath: string, fieldName: string, value: unknown, excludeEntityId?: string, _databaseId?: string): Promise<boolean>;
|
|
144
|
+
/**
|
|
145
|
+
* Get the RelationService instance for external use
|
|
146
|
+
*/
|
|
147
|
+
getRelationService(): RelationService;
|
|
148
|
+
/**
|
|
149
|
+
* Fetch a collection of entities with optional relation includes.
|
|
150
|
+
* When `include` is provided, only the specified relations are populated
|
|
151
|
+
* with full entity data (not just { id, path, __type }).
|
|
152
|
+
* When `include` is absent, no relation queries are made (fast path).
|
|
153
|
+
*
|
|
154
|
+
* @param include - Array of relation keys to populate, or ["*"] for all
|
|
155
|
+
*/
|
|
156
|
+
fetchCollectionForRest<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
157
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
158
|
+
orderBy?: string;
|
|
159
|
+
order?: "desc" | "asc";
|
|
160
|
+
limit?: number;
|
|
161
|
+
startAfter?: Record<string, unknown>;
|
|
162
|
+
searchString?: string;
|
|
163
|
+
databaseId?: string;
|
|
164
|
+
}, include?: string[]): Promise<Record<string, unknown>[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Fetch a single entity with optional relation includes for REST API.
|
|
167
|
+
*/
|
|
168
|
+
fetchEntityForRest<M extends Record<string, any>>(collectionPath: string, entityId: string | number, include?: string[], databaseId?: string): Promise<Record<string, unknown> | null>;
|
|
169
|
+
/**
|
|
170
|
+
* Fetch raw rows without any relation processing (for REST fast path)
|
|
171
|
+
*/
|
|
172
|
+
private fetchEntitiesWithConditionsRaw;
|
|
173
|
+
/**
|
|
174
|
+
* Check if the Drizzle instance has the relational query API available
|
|
175
|
+
* for a given collection path.
|
|
176
|
+
* Note: Primary path now uses inline `getQueryBuilder()` checks.
|
|
177
|
+
*/
|
|
178
|
+
private hasDrizzleQueryAPI;
|
|
179
|
+
/**
|
|
180
|
+
* Attempt to use Drizzle's relational query API (db.query.<table>.findMany)
|
|
181
|
+
* for efficient JOIN-based relation loading.
|
|
182
|
+
* Returns null if the API is not available or the query fails.
|
|
183
|
+
* Note: Primary path now uses `buildWithConfig` + `buildDrizzleQueryOptions`.
|
|
184
|
+
*/
|
|
185
|
+
private fetchWithDrizzleQuery;
|
|
186
|
+
/**
|
|
187
|
+
* Fallback path used when db.query is unavailable.
|
|
188
|
+
* The primary path uses db.query.findMany with `with` config, which
|
|
189
|
+
* loads all relations in a single query.
|
|
190
|
+
*
|
|
191
|
+
* Batch fetch many-to-many related entities for multiple parent IDs.
|
|
192
|
+
* Groups results by parent ID to avoid N+1.
|
|
193
|
+
*/
|
|
194
|
+
private batchFetchManyRelatedEntities;
|
|
195
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Entity } from "@rebasepro/types";
|
|
2
|
+
import { RelationService } from "./RelationService";
|
|
3
|
+
import { EntityFetchService } from "./EntityFetchService";
|
|
4
|
+
import { DrizzleClient } from "../interfaces";
|
|
5
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
6
|
+
/**
|
|
7
|
+
* Service for handling all entity write operations.
|
|
8
|
+
* Handles saving, deleting, and updating entities.
|
|
9
|
+
*/
|
|
10
|
+
export declare class EntityPersistService {
|
|
11
|
+
private db;
|
|
12
|
+
private registry;
|
|
13
|
+
private relationService;
|
|
14
|
+
private fetchService;
|
|
15
|
+
constructor(db: DrizzleClient, registry: PostgresCollectionRegistry);
|
|
16
|
+
/**
|
|
17
|
+
* Delete an entity by ID
|
|
18
|
+
*/
|
|
19
|
+
deleteEntity(collectionPath: string, entityId: string | number, _databaseId?: string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Save an entity (create or update)
|
|
22
|
+
*/
|
|
23
|
+
saveEntity<M extends Record<string, any>>(collectionPath: string, values: Partial<M>, entityId?: string | number, databaseId?: string): Promise<Entity<M>>;
|
|
24
|
+
/**
|
|
25
|
+
* Get the RelationService instance for external use
|
|
26
|
+
*/
|
|
27
|
+
getRelationService(): RelationService;
|
|
28
|
+
/**
|
|
29
|
+
* Get the FetchService instance for external use
|
|
30
|
+
*/
|
|
31
|
+
getFetchService(): EntityFetchService;
|
|
32
|
+
/**
|
|
33
|
+
* Translate raw PostgreSQL / Drizzle errors into user-friendly messages.
|
|
34
|
+
*/
|
|
35
|
+
private toUserFriendlyError;
|
|
36
|
+
/**
|
|
37
|
+
* Extract the underlying PostgreSQL error from a Drizzle wrapper.
|
|
38
|
+
* Drizzle wraps PG errors in a `cause` property.
|
|
39
|
+
*/
|
|
40
|
+
private extractPgError;
|
|
41
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { DrizzleClient } from "../interfaces";
|
|
2
|
+
import { Entity, EntityCollection, FilterValues, Relation } from "@rebasepro/types";
|
|
3
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
+
/**
|
|
5
|
+
* Service for handling all relation-related operations.
|
|
6
|
+
* Handles fetching, updating, and managing entity relations.
|
|
7
|
+
*/
|
|
8
|
+
export declare class RelationService {
|
|
9
|
+
private db;
|
|
10
|
+
private registry;
|
|
11
|
+
constructor(db: DrizzleClient, registry: PostgresCollectionRegistry);
|
|
12
|
+
/**
|
|
13
|
+
* Fetch entities related to a parent entity through a specific relation
|
|
14
|
+
*/
|
|
15
|
+
fetchRelatedEntities<M extends Record<string, any>>(parentCollectionPath: string, parentEntityId: string | number, relationKey: string, options?: {
|
|
16
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
17
|
+
orderBy?: string;
|
|
18
|
+
order?: "desc" | "asc";
|
|
19
|
+
limit?: number;
|
|
20
|
+
startAfter?: Record<string, unknown>;
|
|
21
|
+
searchString?: string;
|
|
22
|
+
databaseId?: string;
|
|
23
|
+
}): Promise<Entity<M>[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Fetch entities using join paths for complex relations
|
|
26
|
+
*/
|
|
27
|
+
fetchEntitiesUsingJoins<M extends Record<string, any>>(parentCollection: EntityCollection, parentEntityId: string | number, relation: Relation, options?: {
|
|
28
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
29
|
+
orderBy?: string;
|
|
30
|
+
order?: "desc" | "asc";
|
|
31
|
+
limit?: number;
|
|
32
|
+
startAfter?: Record<string, unknown>;
|
|
33
|
+
searchString?: string;
|
|
34
|
+
databaseId?: string;
|
|
35
|
+
}): Promise<Entity<M>[]>;
|
|
36
|
+
/**
|
|
37
|
+
* Count related entities for a parent entity
|
|
38
|
+
*/
|
|
39
|
+
countRelatedEntities<M extends Record<string, any>>(parentCollectionPath: string, parentEntityId: string | number, relationKey: string, options?: {
|
|
40
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
41
|
+
databaseId?: string;
|
|
42
|
+
}): Promise<number>;
|
|
43
|
+
/**
|
|
44
|
+
* Batch fetch related entities for multiple parent entities to avoid N+1 queries
|
|
45
|
+
*/
|
|
46
|
+
batchFetchRelatedEntities(parentCollectionPath: string, parentEntityIds: (string | number)[], _relationKey: string, relation: Relation): Promise<Map<string | number, Entity<Record<string, unknown>>>>;
|
|
47
|
+
/**
|
|
48
|
+
* Update many-to-many and junction relations
|
|
49
|
+
*/
|
|
50
|
+
updateRelationsUsingJoins<M extends Record<string, any>>(tx: DrizzleClient, collection: EntityCollection, entityId: string | number, relationValues: Partial<M>): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Update inverse relations (where FK is on the target table)
|
|
53
|
+
*/
|
|
54
|
+
updateInverseRelations(tx: DrizzleClient, sourceCollection: EntityCollection, sourceEntityId: string | number, inverseRelationUpdates: Array<{
|
|
55
|
+
relationKey: string;
|
|
56
|
+
relation: Relation;
|
|
57
|
+
newValue: unknown;
|
|
58
|
+
currentEntityId?: string | number;
|
|
59
|
+
}>): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Handle inverse relations with joinPath
|
|
62
|
+
*/
|
|
63
|
+
private updateInverseJoinPathRelation;
|
|
64
|
+
/**
|
|
65
|
+
* Handle many-to-many inverse relation updates using junction tables
|
|
66
|
+
*/
|
|
67
|
+
private updateManyToManyInverseRelation;
|
|
68
|
+
/**
|
|
69
|
+
* Update one-to-one relations that use joinPath
|
|
70
|
+
*/
|
|
71
|
+
updateJoinPathOneToOneRelations(tx: DrizzleClient, parentCollection: EntityCollection, parentEntityId: string | number, updates: Array<{
|
|
72
|
+
relationKey: string;
|
|
73
|
+
relation: Relation;
|
|
74
|
+
newTargetId: string | number | null;
|
|
75
|
+
}>): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Resolve joinPath write mapping for one-to-one relations
|
|
78
|
+
*/
|
|
79
|
+
resolveJoinPathWriteMapping(parentCollection: EntityCollection, relation: Relation): {
|
|
80
|
+
targetFKColName: string;
|
|
81
|
+
parentSourceColName: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Handle junction table creation for many-to-many path-based saves
|
|
85
|
+
*/
|
|
86
|
+
handleJunctionTableCreation(tx: DrizzleClient, newEntityId: string | number, junctionTableInfo: {
|
|
87
|
+
parentCollection: EntityCollection;
|
|
88
|
+
parentId: string | number;
|
|
89
|
+
relation: Relation;
|
|
90
|
+
relationKey: string;
|
|
91
|
+
}): Promise<void>;
|
|
92
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PgTable } from "drizzle-orm/pg-core";
|
|
2
|
+
import { EntityCollection } from "@rebasepro/types";
|
|
3
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
4
|
+
/**
|
|
5
|
+
* Shared helper functions for entity operations.
|
|
6
|
+
* These are used by EntityFetchService, EntityPersistService, and RelationService.
|
|
7
|
+
*
|
|
8
|
+
* All functions that need collection/table lookups require an explicit
|
|
9
|
+
* `PostgresCollectionRegistry` instance — there is no global singleton.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getCollectionByPath(collectionPath: string, registry: PostgresCollectionRegistry): EntityCollection;
|
|
12
|
+
export declare function getTableForCollection(collection: EntityCollection, registry: PostgresCollectionRegistry): PgTable<any>;
|
|
13
|
+
export declare function getPrimaryKeys(collection: EntityCollection, registry: PostgresCollectionRegistry): {
|
|
14
|
+
fieldName: string;
|
|
15
|
+
type: "string" | "number";
|
|
16
|
+
}[];
|
|
17
|
+
export declare function parseIdValues(idValue: string | number, primaryKeys: {
|
|
18
|
+
fieldName: string;
|
|
19
|
+
type: "string" | "number";
|
|
20
|
+
}[]): Record<string, string | number>;
|
|
21
|
+
export declare function buildCompositeId(values: Record<string, any>, primaryKeys: {
|
|
22
|
+
fieldName: string;
|
|
23
|
+
type: "string" | "number";
|
|
24
|
+
}[]): string;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Entity, FilterValues } from "@rebasepro/types";
|
|
2
|
+
import { EntityFetchService } from "./EntityFetchService";
|
|
3
|
+
import { EntityPersistService } from "./EntityPersistService";
|
|
4
|
+
import { RelationService } from "./RelationService";
|
|
5
|
+
import { EntityRepository, DrizzleClient } from "../interfaces";
|
|
6
|
+
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
7
|
+
export { sanitizeAndConvertDates, serializeDataToServer, parseDataFromServer } from "../data-transformer";
|
|
8
|
+
export { EntityFetchService } from "./EntityFetchService";
|
|
9
|
+
export { EntityPersistService } from "./EntityPersistService";
|
|
10
|
+
export { RelationService } from "./RelationService";
|
|
11
|
+
export * from "../interfaces";
|
|
12
|
+
/**
|
|
13
|
+
* EntityService - Facade for entity operations.
|
|
14
|
+
*
|
|
15
|
+
* This class provides a unified API for entity CRUD operations by delegating
|
|
16
|
+
* to specialized services:
|
|
17
|
+
* - EntityFetchService: Read operations (fetch, search, count)
|
|
18
|
+
* - EntityPersistService: Write operations (save, delete)
|
|
19
|
+
* - RelationService: Relation operations (fetch related, update relations)
|
|
20
|
+
*
|
|
21
|
+
* Implements the EntityRepository interface for database abstraction.
|
|
22
|
+
*/
|
|
23
|
+
export declare class EntityService implements EntityRepository {
|
|
24
|
+
private db;
|
|
25
|
+
private registry;
|
|
26
|
+
private fetchService;
|
|
27
|
+
private persistService;
|
|
28
|
+
constructor(db: DrizzleClient, registry: PostgresCollectionRegistry);
|
|
29
|
+
/**
|
|
30
|
+
* Fetch a single entity by ID
|
|
31
|
+
*/
|
|
32
|
+
fetchEntity<M extends Record<string, any>>(collectionPath: string, entityId: string | number, databaseId?: string): Promise<Entity<M> | undefined>;
|
|
33
|
+
/**
|
|
34
|
+
* Fetch a collection of entities with optional filtering, ordering, and pagination
|
|
35
|
+
*/
|
|
36
|
+
fetchCollection<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
37
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
38
|
+
orderBy?: string;
|
|
39
|
+
order?: "desc" | "asc";
|
|
40
|
+
limit?: number;
|
|
41
|
+
startAfter?: Record<string, unknown>;
|
|
42
|
+
searchString?: string;
|
|
43
|
+
databaseId?: string;
|
|
44
|
+
}): Promise<Entity<M>[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Search entities by text
|
|
47
|
+
*/
|
|
48
|
+
searchEntities<M extends Record<string, any>>(collectionPath: string, searchString: string, options?: {
|
|
49
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
50
|
+
orderBy?: string;
|
|
51
|
+
order?: "desc" | "asc";
|
|
52
|
+
limit?: number;
|
|
53
|
+
databaseId?: string;
|
|
54
|
+
}): Promise<Entity<M>[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Count entities in a collection
|
|
57
|
+
*/
|
|
58
|
+
countEntities<M extends Record<string, any>>(collectionPath: string, options?: {
|
|
59
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
60
|
+
databaseId?: string;
|
|
61
|
+
}): Promise<number>;
|
|
62
|
+
/**
|
|
63
|
+
* Check if a field value is unique in a collection
|
|
64
|
+
*/
|
|
65
|
+
checkUniqueField(collectionPath: string, fieldName: string, value: unknown, excludeEntityId?: string, databaseId?: string): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* Fetch entities related to a parent entity
|
|
68
|
+
*/
|
|
69
|
+
fetchRelatedEntities<M extends Record<string, any>>(parentCollectionPath: string, parentEntityId: string | number, relationKey: string, options?: {
|
|
70
|
+
filter?: FilterValues<Extract<keyof M, string>>;
|
|
71
|
+
orderBy?: string;
|
|
72
|
+
order?: "desc" | "asc";
|
|
73
|
+
limit?: number;
|
|
74
|
+
startAfter?: Record<string, unknown>;
|
|
75
|
+
searchString?: string;
|
|
76
|
+
databaseId?: string;
|
|
77
|
+
}): Promise<Entity<M>[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Save an entity (create or update)
|
|
80
|
+
*/
|
|
81
|
+
saveEntity<M extends Record<string, any>>(collectionPath: string, values: Partial<M>, entityId?: string | number, databaseId?: string): Promise<Entity<M>>;
|
|
82
|
+
/**
|
|
83
|
+
* Delete an entity by ID
|
|
84
|
+
*/
|
|
85
|
+
deleteEntity(collectionPath: string, entityId: string | number, databaseId?: string): Promise<void>;
|
|
86
|
+
/**
|
|
87
|
+
* Execute raw SQL
|
|
88
|
+
*/
|
|
89
|
+
executeSql(sqlText: string): Promise<Record<string, unknown>[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Get the underlying EntityFetchService for advanced use
|
|
92
|
+
*/
|
|
93
|
+
getFetchService(): EntityFetchService;
|
|
94
|
+
/**
|
|
95
|
+
* Get the underlying EntityPersistService for advanced use
|
|
96
|
+
*/
|
|
97
|
+
getPersistService(): EntityPersistService;
|
|
98
|
+
/**
|
|
99
|
+
* Get the underlying RelationService for advanced use
|
|
100
|
+
*/
|
|
101
|
+
getRelationService(): RelationService;
|
|
102
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { EntityFetchService } from "./EntityFetchService";
|
|
2
|
+
export { EntityPersistService } from "./EntityPersistService";
|
|
3
|
+
export { RelationService } from "./RelationService";
|
|
4
|
+
export { getCollectionByPath, getTableForCollection, getPrimaryKeys, parseIdValues, buildCompositeId } from "./entity-helpers";
|