@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.
Files changed (147) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +106 -0
  3. package/build-errors.txt +37 -0
  4. package/dist/common/src/collections/CollectionRegistry.d.ts +48 -0
  5. package/dist/common/src/collections/index.d.ts +1 -0
  6. package/dist/common/src/data/buildRebaseData.d.ts +14 -0
  7. package/dist/common/src/index.d.ts +3 -0
  8. package/dist/common/src/util/builders.d.ts +57 -0
  9. package/dist/common/src/util/callbacks.d.ts +6 -0
  10. package/dist/common/src/util/collections.d.ts +11 -0
  11. package/dist/common/src/util/common.d.ts +2 -0
  12. package/dist/common/src/util/conditions.d.ts +26 -0
  13. package/dist/common/src/util/entities.d.ts +36 -0
  14. package/dist/common/src/util/enums.d.ts +3 -0
  15. package/dist/common/src/util/index.d.ts +16 -0
  16. package/dist/common/src/util/navigation_from_path.d.ts +34 -0
  17. package/dist/common/src/util/navigation_utils.d.ts +20 -0
  18. package/dist/common/src/util/parent_references_from_path.d.ts +6 -0
  19. package/dist/common/src/util/paths.d.ts +14 -0
  20. package/dist/common/src/util/permissions.d.ts +5 -0
  21. package/dist/common/src/util/references.d.ts +2 -0
  22. package/dist/common/src/util/relations.d.ts +12 -0
  23. package/dist/common/src/util/resolutions.d.ts +72 -0
  24. package/dist/common/src/util/storage.d.ts +24 -0
  25. package/dist/index.es.js +10635 -0
  26. package/dist/index.es.js.map +1 -0
  27. package/dist/index.umd.js +10643 -0
  28. package/dist/index.umd.js.map +1 -0
  29. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +112 -0
  30. package/dist/server-postgresql/src/PostgresBootstrapper.d.ts +40 -0
  31. package/dist/server-postgresql/src/auth/ensure-tables.d.ts +6 -0
  32. package/dist/server-postgresql/src/auth/services.d.ts +188 -0
  33. package/dist/server-postgresql/src/cli.d.ts +1 -0
  34. package/dist/server-postgresql/src/collections/PostgresCollectionRegistry.d.ts +43 -0
  35. package/dist/server-postgresql/src/connection.d.ts +7 -0
  36. package/dist/server-postgresql/src/data-transformer.d.ts +36 -0
  37. package/dist/server-postgresql/src/databasePoolManager.d.ts +20 -0
  38. package/dist/server-postgresql/src/history/HistoryService.d.ts +71 -0
  39. package/dist/server-postgresql/src/history/ensure-history-table.d.ts +7 -0
  40. package/dist/server-postgresql/src/index.d.ts +13 -0
  41. package/dist/server-postgresql/src/interfaces.d.ts +18 -0
  42. package/dist/server-postgresql/src/schema/auth-schema.d.ts +767 -0
  43. package/dist/server-postgresql/src/schema/generate-drizzle-schema-logic.d.ts +2 -0
  44. package/dist/server-postgresql/src/schema/generate-drizzle-schema.d.ts +1 -0
  45. package/dist/server-postgresql/src/services/BranchService.d.ts +47 -0
  46. package/dist/server-postgresql/src/services/EntityFetchService.d.ts +195 -0
  47. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +41 -0
  48. package/dist/server-postgresql/src/services/RelationService.d.ts +92 -0
  49. package/dist/server-postgresql/src/services/entity-helpers.d.ts +24 -0
  50. package/dist/server-postgresql/src/services/entityService.d.ts +102 -0
  51. package/dist/server-postgresql/src/services/index.d.ts +4 -0
  52. package/dist/server-postgresql/src/services/realtimeService.d.ts +186 -0
  53. package/dist/server-postgresql/src/utils/drizzle-conditions.d.ts +116 -0
  54. package/dist/server-postgresql/src/websocket.d.ts +5 -0
  55. package/dist/types/src/controllers/analytics_controller.d.ts +7 -0
  56. package/dist/types/src/controllers/auth.d.ts +117 -0
  57. package/dist/types/src/controllers/client.d.ts +58 -0
  58. package/dist/types/src/controllers/collection_registry.d.ts +44 -0
  59. package/dist/types/src/controllers/customization_controller.d.ts +54 -0
  60. package/dist/types/src/controllers/data.d.ts +141 -0
  61. package/dist/types/src/controllers/data_driver.d.ts +168 -0
  62. package/dist/types/src/controllers/database_admin.d.ts +11 -0
  63. package/dist/types/src/controllers/dialogs_controller.d.ts +36 -0
  64. package/dist/types/src/controllers/effective_role.d.ts +4 -0
  65. package/dist/types/src/controllers/index.d.ts +17 -0
  66. package/dist/types/src/controllers/local_config_persistence.d.ts +20 -0
  67. package/dist/types/src/controllers/navigation.d.ts +213 -0
  68. package/dist/types/src/controllers/registry.d.ts +51 -0
  69. package/dist/types/src/controllers/side_dialogs_controller.d.ts +67 -0
  70. package/dist/types/src/controllers/side_entity_controller.d.ts +89 -0
  71. package/dist/types/src/controllers/snackbar.d.ts +24 -0
  72. package/dist/types/src/controllers/storage.d.ts +173 -0
  73. package/dist/types/src/index.d.ts +4 -0
  74. package/dist/types/src/rebase_context.d.ts +101 -0
  75. package/dist/types/src/types/backend.d.ts +533 -0
  76. package/dist/types/src/types/builders.d.ts +14 -0
  77. package/dist/types/src/types/chips.d.ts +5 -0
  78. package/dist/types/src/types/collections.d.ts +812 -0
  79. package/dist/types/src/types/data_source.d.ts +64 -0
  80. package/dist/types/src/types/entities.d.ts +145 -0
  81. package/dist/types/src/types/entity_actions.d.ts +98 -0
  82. package/dist/types/src/types/entity_callbacks.d.ts +173 -0
  83. package/dist/types/src/types/entity_link_builder.d.ts +7 -0
  84. package/dist/types/src/types/entity_overrides.d.ts +9 -0
  85. package/dist/types/src/types/entity_views.d.ts +61 -0
  86. package/dist/types/src/types/export_import.d.ts +21 -0
  87. package/dist/types/src/types/index.d.ts +22 -0
  88. package/dist/types/src/types/locales.d.ts +4 -0
  89. package/dist/types/src/types/modify_collections.d.ts +5 -0
  90. package/dist/types/src/types/plugins.d.ts +225 -0
  91. package/dist/types/src/types/properties.d.ts +1091 -0
  92. package/dist/types/src/types/property_config.d.ts +70 -0
  93. package/dist/types/src/types/relations.d.ts +336 -0
  94. package/dist/types/src/types/slots.d.ts +228 -0
  95. package/dist/types/src/types/translations.d.ts +826 -0
  96. package/dist/types/src/types/user_management_delegate.d.ts +120 -0
  97. package/dist/types/src/types/websockets.d.ts +78 -0
  98. package/dist/types/src/users/index.d.ts +2 -0
  99. package/dist/types/src/users/roles.d.ts +22 -0
  100. package/dist/types/src/users/user.d.ts +46 -0
  101. package/jest-all.log +3128 -0
  102. package/jest.log +49 -0
  103. package/package.json +93 -0
  104. package/src/PostgresBackendDriver.ts +1024 -0
  105. package/src/PostgresBootstrapper.ts +232 -0
  106. package/src/auth/ensure-tables.ts +309 -0
  107. package/src/auth/services.ts +740 -0
  108. package/src/cli.ts +347 -0
  109. package/src/collections/PostgresCollectionRegistry.ts +96 -0
  110. package/src/connection.ts +62 -0
  111. package/src/data-transformer.ts +569 -0
  112. package/src/databasePoolManager.ts +84 -0
  113. package/src/history/HistoryService.ts +257 -0
  114. package/src/history/ensure-history-table.ts +45 -0
  115. package/src/index.ts +13 -0
  116. package/src/interfaces.ts +60 -0
  117. package/src/schema/auth-schema.ts +146 -0
  118. package/src/schema/generate-drizzle-schema-logic.ts +618 -0
  119. package/src/schema/generate-drizzle-schema.ts +151 -0
  120. package/src/services/BranchService.ts +237 -0
  121. package/src/services/EntityFetchService.ts +1447 -0
  122. package/src/services/EntityPersistService.ts +351 -0
  123. package/src/services/RelationService.ts +1012 -0
  124. package/src/services/entity-helpers.ts +121 -0
  125. package/src/services/entityService.ts +209 -0
  126. package/src/services/index.ts +13 -0
  127. package/src/services/realtimeService.ts +1005 -0
  128. package/src/utils/drizzle-conditions.ts +999 -0
  129. package/src/websocket.ts +487 -0
  130. package/test/auth-services.test.ts +569 -0
  131. package/test/branchService.test.ts +357 -0
  132. package/test/drizzle-conditions.test.ts +895 -0
  133. package/test/entityService.errors.test.ts +352 -0
  134. package/test/entityService.relations.test.ts +912 -0
  135. package/test/entityService.subcollection-search.test.ts +516 -0
  136. package/test/entityService.test.ts +977 -0
  137. package/test/generate-drizzle-schema.test.ts +795 -0
  138. package/test/historyService.test.ts +126 -0
  139. package/test/postgresDataDriver.test.ts +556 -0
  140. package/test/realtimeService.test.ts +276 -0
  141. package/test/relations.test.ts +662 -0
  142. package/test_drizzle_mock.js +3 -0
  143. package/test_find_changed.mjs +30 -0
  144. package/test_output.txt +3145 -0
  145. package/tsconfig.json +49 -0
  146. package/tsconfig.prod.json +20 -0
  147. package/vite.config.ts +82 -0
@@ -0,0 +1,121 @@
1
+ import { PgTable, AnyPgColumn } from "drizzle-orm/pg-core";
2
+ import { EntityCollection, Property } from "@rebasepro/types";
3
+ import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
4
+ import { getTableName } from "@rebasepro/common";
5
+
6
+ /**
7
+ * Shared helper functions for entity operations.
8
+ * These are used by EntityFetchService, EntityPersistService, and RelationService.
9
+ *
10
+ * All functions that need collection/table lookups require an explicit
11
+ * `PostgresCollectionRegistry` instance — there is no global singleton.
12
+ */
13
+
14
+ export function getCollectionByPath(collectionPath: string, registry: PostgresCollectionRegistry): EntityCollection {
15
+ const collection = registry.getCollectionByPath(collectionPath);
16
+ if (!collection) {
17
+ throw new Error(`Collection not found: ${collectionPath}`);
18
+ }
19
+ return collection;
20
+ }
21
+
22
+ export function getTableForCollection(collection: EntityCollection, registry: PostgresCollectionRegistry): PgTable<any> {
23
+ const tableName = getTableName(collection);
24
+ const table = registry.getTable(tableName);
25
+ if (!table) {
26
+ throw new Error(`Table not found for collection '${collection.slug}' (table: ${tableName})`);
27
+ }
28
+ return table;
29
+ }
30
+
31
+ export function getPrimaryKeys(collection: EntityCollection, registry: PostgresCollectionRegistry): { fieldName: string; type: "string" | "number" }[] {
32
+ const table = getTableForCollection(collection, registry);
33
+
34
+ // Fallback to explicitly defined isId properties
35
+ if (collection.properties) {
36
+ const idProps = Object.entries(collection.properties)
37
+ .filter(([_, prop]) => "isId" in (prop as object) && Boolean((prop as unknown as Record<string, unknown>).isId))
38
+ .map(([key, prop]) => ({
39
+ fieldName: key,
40
+ type: prop.type === "number" ? "number" as const : "string" as const
41
+ }));
42
+
43
+ if (idProps.length > 0) {
44
+ return idProps;
45
+ }
46
+ }
47
+
48
+ // Otherwise infer from Drizzle schema
49
+ const keys: { fieldName: string; type: "string" | "number" }[] = [];
50
+ for (const [key, colRaw] of Object.entries(table)) {
51
+ const col = colRaw as AnyPgColumn;
52
+ if (col && typeof col === "object" && "primary" in col && col.primary) {
53
+ const type = col.dataType === "number" || (col as unknown as Record<string, unknown>).columnType === "PgSerial" || (col as unknown as Record<string, unknown>).columnType === "PgInteger" ? "number" : "string";
54
+ keys.push({ fieldName: key, type });
55
+ }
56
+ }
57
+
58
+ // Default to 'id' if no primary keys are found and it exists in the schema
59
+ // This maintains backwards compatibility
60
+ if (keys.length === 0 && "id" in table) {
61
+ const idCol = table["id" as keyof typeof table] as AnyPgColumn;
62
+ const type = idCol.dataType === "number" || (idCol as unknown as Record<string, unknown>).columnType === "PgSerial" || (idCol as unknown as Record<string, unknown>).columnType === "PgInteger" ? "number" : "string";
63
+ keys.push({ fieldName: "id", type });
64
+ }
65
+
66
+ return keys;
67
+ }
68
+
69
+ export function parseIdValues(idValue: string | number, primaryKeys: { fieldName: string; type: "string" | "number" }[]): Record<string, string | number> {
70
+ const result: Record<string, string | number> = {};
71
+
72
+ if (primaryKeys.length === 0) {
73
+ return result;
74
+ }
75
+
76
+ if (primaryKeys.length === 1) {
77
+ const pk = primaryKeys[0];
78
+ if (pk.type === "number") {
79
+ const parsed = typeof idValue === "number" ? idValue : parseInt(String(idValue), 10);
80
+ if (isNaN(parsed)) {
81
+ throw new Error(`Invalid numeric ID: ${idValue}`);
82
+ }
83
+ result[pk.fieldName] = parsed;
84
+ } else {
85
+ result[pk.fieldName] = String(idValue);
86
+ }
87
+ return result;
88
+ }
89
+
90
+ // Composite key - split by :::
91
+ const parts = String(idValue).split(":::");
92
+ if (parts.length !== primaryKeys.length) {
93
+ throw new Error(`Composite ID parts mismatch. Expected ${primaryKeys.length}, got ${parts.length} for ID: ${idValue}`);
94
+ }
95
+
96
+ for (let i = 0; i < primaryKeys.length; i++) {
97
+ const pk = primaryKeys[i];
98
+ const val = parts[i];
99
+ if (pk.type === "number") {
100
+ const parsed = parseInt(val, 10);
101
+ if (isNaN(parsed)) {
102
+ throw new Error(`Invalid numeric ID component: ${val}`);
103
+ }
104
+ result[pk.fieldName] = parsed;
105
+ } else {
106
+ result[pk.fieldName] = val;
107
+ }
108
+ }
109
+
110
+ return result;
111
+ }
112
+
113
+ export function buildCompositeId(values: Record<string, any>, primaryKeys: { fieldName: string; type: "string" | "number" }[]): string {
114
+ if (primaryKeys.length === 0) {
115
+ return "";
116
+ }
117
+ if (primaryKeys.length === 1) {
118
+ return String(values[primaryKeys[0].fieldName] ?? "");
119
+ }
120
+ return primaryKeys.map(pk => String(values[pk.fieldName] ?? "")).join(":::");
121
+ }
@@ -0,0 +1,209 @@
1
+ // import { NodePgDatabase } from "drizzle-orm/node-postgres";
2
+ import { Entity, FilterValues } from "@rebasepro/types";
3
+ import { EntityFetchService } from "./EntityFetchService";
4
+ import { EntityPersistService } from "./EntityPersistService";
5
+ import { RelationService } from "./RelationService";
6
+ import { EntityRepository, FetchCollectionOptions, SearchOptions, CountOptions, DrizzleClient } from "../interfaces";
7
+ import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
8
+
9
+ // Re-export data transformer functions for external use
10
+ export { sanitizeAndConvertDates, serializeDataToServer, parseDataFromServer } from "../data-transformer";
11
+
12
+ // Re-export service classes for direct use
13
+ export { EntityFetchService } from "./EntityFetchService";
14
+ export { EntityPersistService } from "./EntityPersistService";
15
+ export { RelationService } from "./RelationService";
16
+
17
+ // Re-export interfaces
18
+ export * from "../interfaces";
19
+
20
+ /**
21
+ * EntityService - Facade for entity operations.
22
+ *
23
+ * This class provides a unified API for entity CRUD operations by delegating
24
+ * to specialized services:
25
+ * - EntityFetchService: Read operations (fetch, search, count)
26
+ * - EntityPersistService: Write operations (save, delete)
27
+ * - RelationService: Relation operations (fetch related, update relations)
28
+ *
29
+ * Implements the EntityRepository interface for database abstraction.
30
+ */
31
+ export class EntityService implements EntityRepository {
32
+ private fetchService: EntityFetchService;
33
+ private persistService: EntityPersistService;
34
+
35
+ constructor(private db: DrizzleClient, private registry: PostgresCollectionRegistry) {
36
+ this.fetchService = new EntityFetchService(db, registry);
37
+ this.persistService = new EntityPersistService(db, registry);
38
+ }
39
+
40
+ // =============================================================
41
+ // READ OPERATIONS - Delegated to EntityFetchService
42
+ // =============================================================
43
+
44
+ /**
45
+ * Fetch a single entity by ID
46
+ */
47
+ async fetchEntity<M extends Record<string, any>>(
48
+ collectionPath: string,
49
+ entityId: string | number,
50
+ databaseId?: string
51
+ ): Promise<Entity<M> | undefined> {
52
+ return this.fetchService.fetchEntity<M>(collectionPath, entityId, databaseId);
53
+ }
54
+
55
+ /**
56
+ * Fetch a collection of entities with optional filtering, ordering, and pagination
57
+ */
58
+ async fetchCollection<M extends Record<string, any>>(
59
+ collectionPath: string,
60
+ options: {
61
+ filter?: FilterValues<Extract<keyof M, string>>;
62
+ orderBy?: string;
63
+ order?: "desc" | "asc";
64
+ limit?: number;
65
+ startAfter?: Record<string, unknown>;
66
+ searchString?: string;
67
+ databaseId?: string;
68
+ } = {}
69
+ ): Promise<Entity<M>[]> {
70
+ return this.fetchService.fetchCollection<M>(collectionPath, options);
71
+ }
72
+
73
+ /**
74
+ * Search entities by text
75
+ */
76
+ async searchEntities<M extends Record<string, any>>(
77
+ collectionPath: string,
78
+ searchString: string,
79
+ options: {
80
+ filter?: FilterValues<Extract<keyof M, string>>;
81
+ orderBy?: string;
82
+ order?: "desc" | "asc";
83
+ limit?: number;
84
+ databaseId?: string;
85
+ } = {}
86
+ ): Promise<Entity<M>[]> {
87
+ return this.fetchService.searchEntities<M>(collectionPath, searchString, options);
88
+ }
89
+
90
+ /**
91
+ * Count entities in a collection
92
+ */
93
+ async countEntities<M extends Record<string, any>>(
94
+ collectionPath: string,
95
+ options: {
96
+ filter?: FilterValues<Extract<keyof M, string>>;
97
+ databaseId?: string;
98
+ } = {}
99
+ ): Promise<number> {
100
+ return this.fetchService.countEntities<M>(collectionPath, options);
101
+ }
102
+
103
+ /**
104
+ * Check if a field value is unique in a collection
105
+ */
106
+ async checkUniqueField(
107
+ collectionPath: string,
108
+ fieldName: string,
109
+ value: unknown,
110
+ excludeEntityId?: string,
111
+ databaseId?: string
112
+ ): Promise<boolean> {
113
+ return this.fetchService.checkUniqueField(collectionPath, fieldName, value, excludeEntityId, databaseId);
114
+ }
115
+
116
+ /**
117
+ * Fetch entities related to a parent entity
118
+ */
119
+ async fetchRelatedEntities<M extends Record<string, any>>(
120
+ parentCollectionPath: string,
121
+ parentEntityId: string | number,
122
+ relationKey: string,
123
+ options: {
124
+ filter?: FilterValues<Extract<keyof M, string>>;
125
+ orderBy?: string;
126
+ order?: "desc" | "asc";
127
+ limit?: number;
128
+ startAfter?: Record<string, unknown>;
129
+ searchString?: string;
130
+ databaseId?: string;
131
+ } = {}
132
+ ): Promise<Entity<M>[]> {
133
+ return this.fetchService.getRelationService().fetchRelatedEntities<M>(
134
+ parentCollectionPath,
135
+ parentEntityId,
136
+ relationKey,
137
+ options
138
+ );
139
+ }
140
+
141
+ // =============================================================
142
+ // WRITE OPERATIONS - Delegated to EntityPersistService
143
+ // =============================================================
144
+
145
+ /**
146
+ * Save an entity (create or update)
147
+ */
148
+ async saveEntity<M extends Record<string, any>>(
149
+ collectionPath: string,
150
+ values: Partial<M>,
151
+ entityId?: string | number,
152
+ databaseId?: string
153
+ ): Promise<Entity<M>> {
154
+ return this.persistService.saveEntity<M>(collectionPath, values, entityId, databaseId);
155
+ }
156
+
157
+ /**
158
+ * Delete an entity by ID
159
+ */
160
+ async deleteEntity(
161
+ collectionPath: string,
162
+ entityId: string | number,
163
+ databaseId?: string
164
+ ): Promise<void> {
165
+ return this.persistService.deleteEntity(collectionPath, entityId, databaseId);
166
+ }
167
+
168
+
169
+ /**
170
+ * Execute raw SQL
171
+ */
172
+ async executeSql(sqlText: string): Promise<Record<string, unknown>[]> {
173
+ if (process.env.NODE_ENV !== "production") {
174
+ console.debug("Executing raw SQL:", sqlText);
175
+ }
176
+ const { sql } = await import("drizzle-orm");
177
+ const result = await this.db.execute(sql.raw(sqlText));
178
+ const rows = result.rows;
179
+ if (process.env.NODE_ENV !== "production") {
180
+ console.debug(`SQL executed successfully. Returned ${Array.isArray(rows) ? rows.length : 'non-array'} rows.`);
181
+ }
182
+ return rows as Record<string, unknown>[];
183
+ }
184
+
185
+ // =============================================================
186
+ // SERVICE ACCESSORS
187
+ // =============================================================
188
+
189
+ /**
190
+ * Get the underlying EntityFetchService for advanced use
191
+ */
192
+ getFetchService(): EntityFetchService {
193
+ return this.fetchService;
194
+ }
195
+
196
+ /**
197
+ * Get the underlying EntityPersistService for advanced use
198
+ */
199
+ getPersistService(): EntityPersistService {
200
+ return this.persistService;
201
+ }
202
+
203
+ /**
204
+ * Get the underlying RelationService for advanced use
205
+ */
206
+ getRelationService(): RelationService {
207
+ return this.fetchService.getRelationService();
208
+ }
209
+ }
@@ -0,0 +1,13 @@
1
+ // Re-export all service classes
2
+ export { EntityFetchService } from "./EntityFetchService";
3
+ export { EntityPersistService } from "./EntityPersistService";
4
+ export { RelationService } from "./RelationService";
5
+
6
+ // Re-export helper functions
7
+ export {
8
+ getCollectionByPath,
9
+ getTableForCollection,
10
+ getPrimaryKeys,
11
+ parseIdValues,
12
+ buildCompositeId
13
+ } from "./entity-helpers";