@rebasepro/server-postgres 0.9.1-canary.a57c262 → 0.9.1-canary.ad25bc0
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/data-transformer.d.ts +2 -9
- package/dist/index.es.js +298 -639
- package/dist/index.es.js.map +1 -1
- package/dist/services/FetchService.d.ts +32 -4
- package/dist/services/RelationService.d.ts +1 -34
- package/dist/services/collection-helpers.d.ts +0 -76
- package/dist/services/index.d.ts +1 -1
- package/dist/services/realtimeService.d.ts +0 -7
- package/package.json +7 -10
- package/src/PostgresBackendDriver.ts +6 -21
- package/src/PostgresBootstrapper.ts +23 -11
- package/src/data-transformer.ts +9 -11
- package/src/schema/generate-drizzle-schema-logic.ts +4 -21
- package/src/schema/generate-postgres-ddl-logic.ts +3 -63
- package/src/schema/introspect-db.ts +1 -8
- package/src/services/FetchService.ts +229 -50
- package/src/services/RelationService.ts +94 -153
- package/src/services/collection-helpers.ts +3 -166
- package/src/services/index.ts +0 -1
- package/src/services/realtimeService.ts +19 -40
- package/dist/collections/buildRegistry.d.ts +0 -27
- package/dist/services/row-pipeline.d.ts +0 -60
- package/src/collections/buildRegistry.ts +0 -59
- package/src/services/row-pipeline.ts +0 -176
|
@@ -7,18 +7,15 @@ import { DrizzleConditionBuilder } from "../utils/drizzle-conditions";
|
|
|
7
7
|
import {
|
|
8
8
|
getCollectionByPath,
|
|
9
9
|
getTableForCollection,
|
|
10
|
-
|
|
11
|
-
deriveRowAddress,
|
|
10
|
+
getPrimaryKeys,
|
|
12
11
|
parseIdValues,
|
|
13
|
-
buildCompositeId
|
|
14
|
-
COMPOSITE_ID_SEPARATOR
|
|
12
|
+
buildCompositeId
|
|
15
13
|
} from "./collection-helpers";
|
|
16
14
|
import { parseDataFromServer, normalizeDbValues } from "../data-transformer";
|
|
17
15
|
import { RelationService } from "./RelationService";
|
|
18
16
|
import { RelationalQueryBuilder } from "drizzle-orm/pg-core/query-builders/query";
|
|
19
17
|
import { DrizzleClient } from "../interfaces";
|
|
20
18
|
import { PostgresCollectionRegistry } from "../collections/PostgresCollectionRegistry";
|
|
21
|
-
import { toCmsRow, toRestRow, isJunctionRelation } from "./row-pipeline";
|
|
22
19
|
import { logger } from "@rebasepro/server";
|
|
23
20
|
|
|
24
21
|
/** Type-safe accessor for Drizzle's relational query API via dynamic table name */
|
|
@@ -112,7 +109,7 @@ export class FetchService {
|
|
|
112
109
|
// Detect many-to-many junction tables:
|
|
113
110
|
// If the relation goes through a junction table (relation.through exists or
|
|
114
111
|
// the Drizzle schema maps to a junction table), we need two-level with.
|
|
115
|
-
if (relation.cardinality === "many" && isJunctionRelation(relation)) {
|
|
112
|
+
if (relation.cardinality === "many" && this.isJunctionRelation(relation, collection)) {
|
|
116
113
|
// The Drizzle relation points to the junction table.
|
|
117
114
|
// We need: { [junctionRelName]: { with: { [targetFkName]: true } } }
|
|
118
115
|
// The target FK name is the relation on the junction table that points to the actual target.
|
|
@@ -130,6 +127,17 @@ export class FetchService {
|
|
|
130
127
|
return withConfig;
|
|
131
128
|
}
|
|
132
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Detect if a many-to-many relation uses a junction table in the Drizzle schema.
|
|
132
|
+
*/
|
|
133
|
+
private isJunctionRelation(relation: Relation, _collection: CollectionConfig): boolean {
|
|
134
|
+
// If `through` is defined, it's explicitly a junction relation
|
|
135
|
+
if (relation.through) return true;
|
|
136
|
+
// If joinPath has an intermediate table, it's likely junction-based
|
|
137
|
+
if (relation.joinPath && relation.joinPath.length > 1) return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
133
141
|
/**
|
|
134
142
|
* Get the Drizzle relation name on the junction table that points to the actual target row.
|
|
135
143
|
* For example, for posts_tags junction, this returns "tag_id" (the relation pointing to tags).
|
|
@@ -143,6 +151,85 @@ export class FetchService {
|
|
|
143
151
|
return null;
|
|
144
152
|
}
|
|
145
153
|
|
|
154
|
+
/**
|
|
155
|
+
* Convert a db.query result row (with nested relation objects) to a flat row.
|
|
156
|
+
* Handles:
|
|
157
|
+
* - Type normalization (dates, numbers, NaN) via normalizeDbValues
|
|
158
|
+
* - Converting nested relation objects to { id, path, __type: "relation" } for CMS
|
|
159
|
+
* - Flattening junction-table many-to-many results
|
|
160
|
+
*
|
|
161
|
+
* The row's own address is not among them: it is derived by the consumer
|
|
162
|
+
* from the collection's primary keys.
|
|
163
|
+
*/
|
|
164
|
+
private drizzleResultToRow<M extends Record<string, unknown>>(
|
|
165
|
+
row: Record<string, unknown>,
|
|
166
|
+
collection: CollectionConfig
|
|
167
|
+
): Record<string, unknown> {
|
|
168
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
169
|
+
|
|
170
|
+
// Normalize non-relation values (dates, numbers, etc.)
|
|
171
|
+
const normalizedValues = normalizeDbValues(row as M, collection) as Record<string, unknown>;
|
|
172
|
+
|
|
173
|
+
// Convert nested relation objects to CMS-style { id, path, __type: "relation" }
|
|
174
|
+
for (const [key, relation] of Object.entries(resolvedRelations)) {
|
|
175
|
+
const drizzleRelName = relation.relationName || key;
|
|
176
|
+
const relData = row[drizzleRelName];
|
|
177
|
+
|
|
178
|
+
if (relData === undefined || relData === null) continue;
|
|
179
|
+
|
|
180
|
+
if (relation.cardinality === "many" && Array.isArray(relData)) {
|
|
181
|
+
const targetCollection = relation.target();
|
|
182
|
+
const targetPath = targetCollection.slug;
|
|
183
|
+
const targetPks = getPrimaryKeys(targetCollection, this.registry);
|
|
184
|
+
const targetIdField = targetPks[0].fieldName;
|
|
185
|
+
|
|
186
|
+
normalizedValues[key] = relData.map((item: Record<string, unknown>) => {
|
|
187
|
+
// Handle junction table flattening:
|
|
188
|
+
// Junction rows look like { post_id: 1, tag_id: { id: 5, name: "ts" } }
|
|
189
|
+
let targetRow = item;
|
|
190
|
+
if (this.isJunctionRelation(relation, collection)) {
|
|
191
|
+
// Find the nested target object in the junction row
|
|
192
|
+
const nestedKey = Object.keys(item).find(
|
|
193
|
+
nk => typeof item[nk] === "object" && item[nk] !== null && !Array.isArray(item[nk])
|
|
194
|
+
);
|
|
195
|
+
if (nestedKey) {
|
|
196
|
+
targetRow = item[nestedKey] as Record<string, unknown>;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const relId = String(targetRow[targetIdField] ?? targetRow.id ?? targetRow[Object.keys(targetRow)[0]]);
|
|
201
|
+
const targetValues = normalizeDbValues(targetRow, targetCollection);
|
|
202
|
+
|
|
203
|
+
return createRelationRefWithData(relId, targetPath, {
|
|
204
|
+
id: relId,
|
|
205
|
+
path: targetPath,
|
|
206
|
+
values: targetValues
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
} else if (relation.cardinality === "one" && typeof relData === "object" && !Array.isArray(relData)) {
|
|
210
|
+
const targetCollection = relation.target();
|
|
211
|
+
const targetPath = targetCollection.slug;
|
|
212
|
+
const targetPks = getPrimaryKeys(targetCollection, this.registry);
|
|
213
|
+
const targetIdField = targetPks[0].fieldName;
|
|
214
|
+
const relObj = relData as Record<string, unknown>;
|
|
215
|
+
|
|
216
|
+
const relId = String(relObj[targetIdField] ?? relObj.id ?? relObj[Object.keys(relObj)[0]]);
|
|
217
|
+
const targetValues = normalizeDbValues(relObj, targetCollection);
|
|
218
|
+
|
|
219
|
+
normalizedValues[key] = createRelationRefWithData(relId, targetPath, {
|
|
220
|
+
id: relId,
|
|
221
|
+
path: targetPath,
|
|
222
|
+
values: targetValues
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// A row is exactly its columns. The address is derived by the consumer
|
|
228
|
+
// from the collection's primary keys — writing it here would rename the
|
|
229
|
+
// key column (`sku` → `id`) and restringify it (`42` → `"42"`).
|
|
230
|
+
return normalizedValues;
|
|
231
|
+
}
|
|
232
|
+
|
|
146
233
|
/**
|
|
147
234
|
* Post-fetch joinPath relations for a single flat row.
|
|
148
235
|
* joinPath relations cannot be expressed via Drizzle's `with` config,
|
|
@@ -184,6 +271,57 @@ export class FetchService {
|
|
|
184
271
|
await Promise.all(promises);
|
|
185
272
|
}
|
|
186
273
|
|
|
274
|
+
/**
|
|
275
|
+
* Post-fetch joinPath relations for a batch of flat rows.
|
|
276
|
+
* Uses batch fetching to avoid N+1 queries for list views.
|
|
277
|
+
*/
|
|
278
|
+
private async resolveJoinPathRelationsBatch<M extends Record<string, unknown>>(
|
|
279
|
+
rows: Record<string, unknown>[],
|
|
280
|
+
collection: CollectionConfig,
|
|
281
|
+
collectionPath: string,
|
|
282
|
+
idInfo: { fieldName: string; type: "string" | "number" },
|
|
283
|
+
_databaseId?: string
|
|
284
|
+
): Promise<void> {
|
|
285
|
+
if (rows.length === 0) return;
|
|
286
|
+
|
|
287
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
288
|
+
|
|
289
|
+
const joinPathRelations = Object.entries(resolvedRelations)
|
|
290
|
+
.filter(([key, relation]) => relation.joinPath && relation.joinPath.length > 0);
|
|
291
|
+
|
|
292
|
+
if (joinPathRelations.length === 0) return;
|
|
293
|
+
|
|
294
|
+
for (const [key, relation] of joinPathRelations) {
|
|
295
|
+
try {
|
|
296
|
+
const rowIds = rows.map(r => {
|
|
297
|
+
const parsed = parseIdValues(String(r.id), [idInfo]);
|
|
298
|
+
return parsed[idInfo.fieldName] as string | number;
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
const resultMap = await this.relationService.batchFetchRelatedEntities(
|
|
302
|
+
collectionPath,
|
|
303
|
+
rowIds,
|
|
304
|
+
key,
|
|
305
|
+
relation
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
for (const row of rows) {
|
|
309
|
+
const parsed = parseIdValues(String(row.id), [idInfo]);
|
|
310
|
+
const id = parsed[idInfo.fieldName] as string | number;
|
|
311
|
+
const relatedRow = resultMap.get(String(id));
|
|
312
|
+
|
|
313
|
+
if (relatedRow) {
|
|
314
|
+
if (relation.cardinality === "one") {
|
|
315
|
+
row[key] = createRelationRefWithData(relatedRow.id, relatedRow.path, relatedRow);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
} catch (e) {
|
|
320
|
+
logger.warn(`Could not batch resolve joinPath relation '${key}'`, { error: e });
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
187
325
|
/**
|
|
188
326
|
* Resolves joinPath relations for raw REST rows and directly injects them.
|
|
189
327
|
* Uses RelationService to query the database and maps results back to the flattened objects.
|
|
@@ -207,25 +345,15 @@ export class FetchService {
|
|
|
207
345
|
|
|
208
346
|
if (joinPathRelations.length === 0) return;
|
|
209
347
|
|
|
210
|
-
|
|
211
|
-
// is derived from them. It used to be parsed back out of a synthesized
|
|
212
|
-
// `id` — which no longer exists on a row, and threw (composite: parts
|
|
213
|
-
// mismatch; numeric: NaN) into the catch below, where a warning is all
|
|
214
|
-
// that separates "no relations" from "relations dropped".
|
|
215
|
-
//
|
|
216
|
-
// The whole key, because that is what the batch groups its results by:
|
|
217
|
-
// both sides derive the token the same way, so they agree by
|
|
218
|
-
// construction rather than by both happening to pick column zero.
|
|
219
|
-
const parentIdOf = (row: Record<string, unknown>): string | undefined => {
|
|
220
|
-
const address = buildCompositeId(row, idInfoArray);
|
|
221
|
-
return address && address.split(COMPOSITE_ID_SEPARATOR).some(part => part !== "") ? address : undefined;
|
|
222
|
-
};
|
|
348
|
+
const idInfo = idInfoArray[0];
|
|
223
349
|
|
|
224
350
|
for (const [key, relation] of joinPathRelations) {
|
|
225
351
|
try {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
352
|
+
// Determine the parent IDs based on the parsed string ID from the REST row
|
|
353
|
+
const rowIds = rows.map(r => {
|
|
354
|
+
const parsed = parseIdValues(String(r.id), idInfoArray);
|
|
355
|
+
return parsed[idInfo.fieldName] as string | number;
|
|
356
|
+
});
|
|
229
357
|
|
|
230
358
|
if (relation.cardinality === "one") {
|
|
231
359
|
const resultMap = await this.relationService.batchFetchRelatedEntities(
|
|
@@ -235,11 +363,19 @@ export class FetchService {
|
|
|
235
363
|
relation
|
|
236
364
|
);
|
|
237
365
|
|
|
238
|
-
for (const row of
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
366
|
+
for (const row of rows) {
|
|
367
|
+
const parsed = parseIdValues(String(row.id), idInfoArray);
|
|
368
|
+
const id = parsed[idInfo.fieldName] as string | number;
|
|
369
|
+
const relatedRow = resultMap.get(String(id));
|
|
370
|
+
|
|
371
|
+
if (relatedRow) {
|
|
372
|
+
row[key] = {
|
|
373
|
+
...relatedRow.values,
|
|
374
|
+
id: relatedRow.id
|
|
375
|
+
};
|
|
376
|
+
} else {
|
|
377
|
+
row[key] = null;
|
|
378
|
+
}
|
|
243
379
|
}
|
|
244
380
|
} else if (relation.cardinality === "many") {
|
|
245
381
|
const resultMap = await this.relationService.batchFetchRelatedEntitiesMany(
|
|
@@ -249,9 +385,14 @@ export class FetchService {
|
|
|
249
385
|
relation
|
|
250
386
|
);
|
|
251
387
|
|
|
252
|
-
for (const row of
|
|
253
|
-
const
|
|
254
|
-
|
|
388
|
+
for (const row of rows) {
|
|
389
|
+
const parsed = parseIdValues(String(row.id), idInfoArray);
|
|
390
|
+
const id = parsed[idInfo.fieldName] as string | number;
|
|
391
|
+
const relatedList = resultMap.get(String(id)) || [];
|
|
392
|
+
row[key] = relatedList.map(e => ({
|
|
393
|
+
...e.values,
|
|
394
|
+
id: e.id
|
|
395
|
+
}));
|
|
255
396
|
}
|
|
256
397
|
}
|
|
257
398
|
} catch (e) {
|
|
@@ -260,6 +401,47 @@ export class FetchService {
|
|
|
260
401
|
}
|
|
261
402
|
}
|
|
262
403
|
|
|
404
|
+
/**
|
|
405
|
+
* Convert a db.query result row to a flat REST-style row with populated relations.
|
|
406
|
+
*
|
|
407
|
+
* Every column is copied through under its own name, with the value Postgres
|
|
408
|
+
* returned. This used to open with a synthesized `id` and then skip the key
|
|
409
|
+
* column, which renamed it (a `sku` primary key was served as `id`, and `sku`
|
|
410
|
+
* did not appear at all) and restringified it (`42` → `"42"`). Consumers that
|
|
411
|
+
* need an address derive it from the collection's primary keys.
|
|
412
|
+
*/
|
|
413
|
+
private drizzleResultToRestRow(
|
|
414
|
+
row: Record<string, unknown>,
|
|
415
|
+
collection: CollectionConfig
|
|
416
|
+
): Record<string, unknown> {
|
|
417
|
+
const flat: Record<string, unknown> = {};
|
|
418
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
419
|
+
|
|
420
|
+
for (const [k, v] of Object.entries(row)) {
|
|
421
|
+
const relation = findRelation(resolvedRelations, k);
|
|
422
|
+
if (Array.isArray(v) && relation) {
|
|
423
|
+
// Many relation — inline each nested row, unwrapping junction rows
|
|
424
|
+
flat[k] = v.map((item: Record<string, unknown>) => {
|
|
425
|
+
if (this.isJunctionRelation(relation, collection)) {
|
|
426
|
+
const nestedKey = Object.keys(item).find(
|
|
427
|
+
nk => typeof item[nk] === "object" && item[nk] !== null && !Array.isArray(item[nk])
|
|
428
|
+
);
|
|
429
|
+
if (nestedKey) {
|
|
430
|
+
return { ...(item[nestedKey] as Record<string, unknown>) };
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return { ...item };
|
|
434
|
+
});
|
|
435
|
+
} else if (typeof v === "object" && v !== null && !Array.isArray(v) && relation) {
|
|
436
|
+
// One-to-one relation — inline the target's columns
|
|
437
|
+
flat[k] = { ...(v as Record<string, unknown>) };
|
|
438
|
+
} else {
|
|
439
|
+
flat[k] = v;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return flat;
|
|
443
|
+
}
|
|
444
|
+
|
|
263
445
|
/**
|
|
264
446
|
* Build db.query-compatible options from standard fetch options.
|
|
265
447
|
* Handles filter, search, orderBy, limit, and cursor-based pagination.
|
|
@@ -401,7 +583,7 @@ export class FetchService {
|
|
|
401
583
|
): Promise<Record<string, unknown> | undefined> {
|
|
402
584
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
403
585
|
const table = getTableForCollection(collection, this.registry);
|
|
404
|
-
const idInfoArray =
|
|
586
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
405
587
|
const idInfo = idInfoArray[0];
|
|
406
588
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
407
589
|
|
|
@@ -428,7 +610,7 @@ export class FetchService {
|
|
|
428
610
|
|
|
429
611
|
if (!row) return undefined;
|
|
430
612
|
|
|
431
|
-
const flatRow =
|
|
613
|
+
const flatRow = this.drizzleResultToRow<M>(row, collection);
|
|
432
614
|
|
|
433
615
|
// Post-fetch joinPath relations that Drizzle's `with` can't express
|
|
434
616
|
await this.resolveJoinPathRelations<M>(flatRow, collection, collectionPath, parsedId, databaseId);
|
|
@@ -520,7 +702,7 @@ export class FetchService {
|
|
|
520
702
|
): Promise<Record<string, unknown>[]> {
|
|
521
703
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
522
704
|
const table = getTableForCollection(collection, this.registry);
|
|
523
|
-
const idInfoArray =
|
|
705
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
524
706
|
const idInfo = idInfoArray[0];
|
|
525
707
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
526
708
|
|
|
@@ -552,7 +734,7 @@ export class FetchService {
|
|
|
552
734
|
const results = await qb.findMany(queryOpts as Parameters<NonNullable<typeof qb>["findMany"]>[0]);
|
|
553
735
|
|
|
554
736
|
const rows = (results as Record<string, unknown>[]).map(row =>
|
|
555
|
-
|
|
737
|
+
this.drizzleResultToRow<M>(row, collection)
|
|
556
738
|
);
|
|
557
739
|
|
|
558
740
|
return rows;
|
|
@@ -652,10 +834,8 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
652
834
|
|
|
653
835
|
/**
|
|
654
836
|
* Fallback path used when db.query is unavailable.
|
|
655
|
-
*
|
|
656
|
-
*
|
|
657
|
-
* relations from what drizzle already nested — no query per row. This one
|
|
658
|
-
* has no nesting to read, so it resolves relations itself, in batches.
|
|
837
|
+
* The primary path uses drizzleResultToRow which handles relation
|
|
838
|
+
* mapping without N+1 queries.
|
|
659
839
|
*
|
|
660
840
|
* Process raw database results into flat rows with relations.
|
|
661
841
|
*/
|
|
@@ -840,12 +1020,11 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
840
1020
|
relationKey,
|
|
841
1021
|
options
|
|
842
1022
|
);
|
|
843
|
-
//
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
return rows.map(row => ({ ...row.values as Record<string, unknown> }));
|
|
1023
|
+
// Convert RelatedRow[] from RelationService to flat rows
|
|
1024
|
+
return rows.map(row => ({
|
|
1025
|
+
...row.values as Record<string, unknown>,
|
|
1026
|
+
id: row.id
|
|
1027
|
+
}));
|
|
849
1028
|
}
|
|
850
1029
|
|
|
851
1030
|
if (i + 1 < pathSegments.length) {
|
|
@@ -959,7 +1138,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
959
1138
|
|
|
960
1139
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
961
1140
|
const table = getTableForCollection(collection, this.registry);
|
|
962
|
-
const idInfoArray =
|
|
1141
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
963
1142
|
const idInfo = idInfoArray[0];
|
|
964
1143
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
965
1144
|
const field = table[fieldName as keyof typeof table] as AnyPgColumn;
|
|
@@ -1019,7 +1198,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
1019
1198
|
): Promise<Record<string, unknown>[]> {
|
|
1020
1199
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
1021
1200
|
const table = getTableForCollection(collection, this.registry);
|
|
1022
|
-
const idInfoArray =
|
|
1201
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
1023
1202
|
const idInfo = idInfoArray[0];
|
|
1024
1203
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
1025
1204
|
|
|
@@ -1046,7 +1225,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
1046
1225
|
const results = await qb.findMany(queryOpts as Parameters<NonNullable<typeof qb>["findMany"]>[0]);
|
|
1047
1226
|
|
|
1048
1227
|
const restRows = (results as Record<string, unknown>[]).map(row =>
|
|
1049
|
-
|
|
1228
|
+
this.drizzleResultToRestRow(row, collection)
|
|
1050
1229
|
);
|
|
1051
1230
|
|
|
1052
1231
|
// Drizzle relational query API doesn't resolve joinPath relations, fetch manually
|
|
@@ -1125,7 +1304,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
1125
1304
|
): Promise<Record<string, unknown> | null> {
|
|
1126
1305
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
1127
1306
|
const table = getTableForCollection(collection, this.registry);
|
|
1128
|
-
const idInfoArray =
|
|
1307
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
1129
1308
|
const idInfo = idInfoArray[0];
|
|
1130
1309
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
1131
1310
|
|
|
@@ -1151,7 +1330,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
1151
1330
|
|
|
1152
1331
|
if (!row) return null;
|
|
1153
1332
|
|
|
1154
|
-
const restRow =
|
|
1333
|
+
const restRow = this.drizzleResultToRestRow(row, collection);
|
|
1155
1334
|
|
|
1156
1335
|
// Drizzle relational query API doesn't resolve joinPath relations, fetch manually
|
|
1157
1336
|
await this.resolveJoinPathRelationsBatchRest([restRow], collection, collectionPath, idInfoArray, include);
|
|
@@ -1233,7 +1412,7 @@ _distance: vectorMeta.distanceSelect }).from(table).$dynamic()
|
|
|
1233
1412
|
): Promise<Record<string, unknown>[]> {
|
|
1234
1413
|
const collection = getCollectionByPath(collectionPath, this.registry);
|
|
1235
1414
|
const table = getTableForCollection(collection, this.registry);
|
|
1236
|
-
const idInfoArray =
|
|
1415
|
+
const idInfoArray = getPrimaryKeys(collection, this.registry);
|
|
1237
1416
|
const idInfo = idInfoArray[0];
|
|
1238
1417
|
const idField = table[idInfo.fieldName as keyof typeof table] as AnyPgColumn;
|
|
1239
1418
|
|