@rebasepro/server-postgresql 0.2.1 → 0.2.3
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/common/src/data/query_builder.d.ts +51 -0
- package/dist/common/src/index.d.ts +1 -0
- package/dist/index.es.js +280 -131
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +280 -131
- package/dist/index.umd.js.map +1 -1
- package/dist/types/src/controllers/data.d.ts +21 -0
- package/package.json +7 -6
- package/src/PostgresBackendDriver.ts +9 -5
- package/src/cli.ts +5 -0
- package/src/schema/default-collections.ts +1 -0
- package/src/schema/doctor.ts +82 -41
- package/test/postgresDataDriver.test.ts +130 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { FindResponse, CollectionAccessor, QueryBuilderInterface, FilterOperator } from "@rebasepro/types";
|
|
2
|
+
export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> implements QueryBuilderInterface<M> {
|
|
3
|
+
private collection;
|
|
4
|
+
private params;
|
|
5
|
+
constructor(collection: CollectionAccessor<M>);
|
|
6
|
+
/**
|
|
7
|
+
* Add a filter condition to your query.
|
|
8
|
+
* @example
|
|
9
|
+
* client.collection('users').where('age', '>=', 18).find()
|
|
10
|
+
*/
|
|
11
|
+
where(column: keyof M & string, operator: FilterOperator, value: unknown): this;
|
|
12
|
+
/**
|
|
13
|
+
* Order the results by a specific column.
|
|
14
|
+
* @example
|
|
15
|
+
* client.collection('users').orderBy('createdAt', 'desc').find()
|
|
16
|
+
*/
|
|
17
|
+
orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
|
|
18
|
+
/**
|
|
19
|
+
* Limit the number of results returned.
|
|
20
|
+
*/
|
|
21
|
+
limit(count: number): this;
|
|
22
|
+
/**
|
|
23
|
+
* Skip the first N results.
|
|
24
|
+
*/
|
|
25
|
+
offset(count: number): this;
|
|
26
|
+
/**
|
|
27
|
+
* Set a free-text search string if supported by the backend.
|
|
28
|
+
*/
|
|
29
|
+
search(searchString: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Include related entities in the response.
|
|
32
|
+
* Relations will be populated with full entity data instead of just IDs.
|
|
33
|
+
*
|
|
34
|
+
* @param relations - Relation names to include, or "*" for all.
|
|
35
|
+
* @example
|
|
36
|
+
* // Include specific relations
|
|
37
|
+
* client.data.posts.include("tags", "author").find()
|
|
38
|
+
*
|
|
39
|
+
* // Include all relations
|
|
40
|
+
* client.data.posts.include("*").find()
|
|
41
|
+
*/
|
|
42
|
+
include(...relations: string[]): this;
|
|
43
|
+
/**
|
|
44
|
+
* Execute the find query and return the results.
|
|
45
|
+
*/
|
|
46
|
+
find(): Promise<FindResponse<M>>;
|
|
47
|
+
/**
|
|
48
|
+
* Listen to realtime updates matching this query.
|
|
49
|
+
*/
|
|
50
|
+
listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
|
|
51
|
+
}
|
package/dist/index.es.js
CHANGED
|
@@ -1158,118 +1158,6 @@ function enumToObjectEntries(enumValues) {
|
|
|
1158
1158
|
});
|
|
1159
1159
|
}
|
|
1160
1160
|
}
|
|
1161
|
-
function getSubcollections(collection) {
|
|
1162
|
-
if (collection.childCollections) {
|
|
1163
|
-
return collection.childCollections() ?? [];
|
|
1164
|
-
}
|
|
1165
|
-
if (getDataSourceCapabilities(collection.driver).supportsSubcollections && collection.subcollections) {
|
|
1166
|
-
return collection.subcollections() ?? [];
|
|
1167
|
-
}
|
|
1168
|
-
if (getDataSourceCapabilities(collection.driver).supportsRelations && collection.relations) {
|
|
1169
|
-
const manyRelations = collection.relations.filter((r) => r.cardinality === "many");
|
|
1170
|
-
return manyRelations.map((r) => {
|
|
1171
|
-
const target = r.target();
|
|
1172
|
-
if (!target) return void 0;
|
|
1173
|
-
const relationKey = r.relationName || target.slug;
|
|
1174
|
-
let customName;
|
|
1175
|
-
if (collection.properties) {
|
|
1176
|
-
const prop = Object.entries(collection.properties).find(([_, p]) => p.type === "relation" && p.relationName === relationKey);
|
|
1177
|
-
if (prop && prop[1].name) {
|
|
1178
|
-
customName = prop[1].name;
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
const baseOverrides = {
|
|
1182
|
-
slug: relationKey
|
|
1183
|
-
};
|
|
1184
|
-
if (customName) {
|
|
1185
|
-
baseOverrides.name = customName;
|
|
1186
|
-
baseOverrides.singularName = customName;
|
|
1187
|
-
}
|
|
1188
|
-
const targetWithOverrides = {
|
|
1189
|
-
...target,
|
|
1190
|
-
...baseOverrides
|
|
1191
|
-
};
|
|
1192
|
-
return r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides;
|
|
1193
|
-
}).filter((c) => Boolean(c));
|
|
1194
|
-
}
|
|
1195
|
-
return [];
|
|
1196
|
-
}
|
|
1197
|
-
function hasPropertyCallbacks(properties, callbackName) {
|
|
1198
|
-
if (!properties) return false;
|
|
1199
|
-
for (const property of Object.values(properties)) {
|
|
1200
|
-
if (property.callbacks?.[callbackName]) return true;
|
|
1201
|
-
if (property.type === "map" && property.properties) {
|
|
1202
|
-
if (hasPropertyCallbacks(property.properties, callbackName)) return true;
|
|
1203
|
-
} else if (property.type === "array" && property.of) {
|
|
1204
|
-
const ofs = Array.isArray(property.of) ? property.of : [property.of];
|
|
1205
|
-
for (const of of ofs) {
|
|
1206
|
-
if (of.callbacks?.[callbackName]) return true;
|
|
1207
|
-
if (of.type === "map" && of.properties && hasPropertyCallbacks(of.properties, callbackName)) return true;
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
return false;
|
|
1212
|
-
}
|
|
1213
|
-
async function processProperties(properties, values, previousValues, propsContext, callbackName) {
|
|
1214
|
-
if (!values || typeof values !== "object") return values;
|
|
1215
|
-
const result = {
|
|
1216
|
-
...values
|
|
1217
|
-
};
|
|
1218
|
-
for (const [key, property] of Object.entries(properties)) {
|
|
1219
|
-
if (result[key] === void 0) continue;
|
|
1220
|
-
let currentValue = result[key];
|
|
1221
|
-
const previousValue = previousValues?.[key];
|
|
1222
|
-
if (property.type === "array" && Array.isArray(currentValue)) {
|
|
1223
|
-
if (property.of && !Array.isArray(property.of)) {
|
|
1224
|
-
currentValue = await Promise.all(currentValue.map(async (item, index) => {
|
|
1225
|
-
const prevItem = Array.isArray(previousValue) ? previousValue[index] : void 0;
|
|
1226
|
-
const singlePropData = {
|
|
1227
|
-
"_tmp": property.of
|
|
1228
|
-
};
|
|
1229
|
-
const res = await processProperties(singlePropData, {
|
|
1230
|
-
"_tmp": item
|
|
1231
|
-
}, {
|
|
1232
|
-
"_tmp": prevItem
|
|
1233
|
-
}, propsContext, callbackName);
|
|
1234
|
-
return res["_tmp"];
|
|
1235
|
-
}));
|
|
1236
|
-
}
|
|
1237
|
-
} else if (property.type === "map" && property.properties && typeof currentValue === "object") {
|
|
1238
|
-
currentValue = await processProperties(property.properties, currentValue, previousValue ?? {}, propsContext, callbackName);
|
|
1239
|
-
}
|
|
1240
|
-
if (property.callbacks?.[callbackName]) {
|
|
1241
|
-
const cbRes = await Promise.resolve(property.callbacks[callbackName]({
|
|
1242
|
-
...propsContext,
|
|
1243
|
-
value: currentValue,
|
|
1244
|
-
previousValue
|
|
1245
|
-
}));
|
|
1246
|
-
if (cbRes !== void 0) {
|
|
1247
|
-
currentValue = cbRes;
|
|
1248
|
-
}
|
|
1249
|
-
}
|
|
1250
|
-
result[key] = currentValue;
|
|
1251
|
-
}
|
|
1252
|
-
return result;
|
|
1253
|
-
}
|
|
1254
|
-
const buildPropertyCallbacks = (properties) => {
|
|
1255
|
-
if (!properties) return void 0;
|
|
1256
|
-
const propertyCallbacks = {};
|
|
1257
|
-
if (hasPropertyCallbacks(properties, "afterRead")) {
|
|
1258
|
-
propertyCallbacks.afterRead = async (props) => {
|
|
1259
|
-
const processedValues = await processProperties(properties, props.entity.values, props.entity.values, props, "afterRead");
|
|
1260
|
-
return {
|
|
1261
|
-
...props.entity,
|
|
1262
|
-
values: processedValues
|
|
1263
|
-
};
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
if (hasPropertyCallbacks(properties, "beforeSave")) {
|
|
1267
|
-
propertyCallbacks.beforeSave = async (props) => {
|
|
1268
|
-
return await processProperties(properties, props.values, props.previousValues ?? {}, props, "beforeSave");
|
|
1269
|
-
};
|
|
1270
|
-
}
|
|
1271
|
-
return Object.keys(propertyCallbacks).length > 0 ? propertyCallbacks : void 0;
|
|
1272
|
-
};
|
|
1273
1161
|
function sanitizeRelation(relation, sourceCollection, resolveCollection) {
|
|
1274
1162
|
if (!relation.target) {
|
|
1275
1163
|
throw new Error("Relation is missing a `target` collection.");
|
|
@@ -1301,6 +1189,8 @@ function sanitizeRelation(relation, sourceCollection, resolveCollection) {
|
|
|
1301
1189
|
} else {
|
|
1302
1190
|
targetCollection = evaluated;
|
|
1303
1191
|
}
|
|
1192
|
+
} else if (rawTarget && typeof rawTarget === "object") {
|
|
1193
|
+
targetCollection = rawTarget;
|
|
1304
1194
|
}
|
|
1305
1195
|
if (!targetCollection) {
|
|
1306
1196
|
throw new Error("Relation is missing a valid `target` collection.");
|
|
@@ -1420,11 +1310,14 @@ function resolveCollectionRelations(collection) {
|
|
|
1420
1310
|
const registeredRelationNames = /* @__PURE__ */ new Set();
|
|
1421
1311
|
if (relCollection.relations) {
|
|
1422
1312
|
relCollection.relations.forEach((relation) => {
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1313
|
+
try {
|
|
1314
|
+
const normalizedRelation = sanitizeRelation(relation, collection);
|
|
1315
|
+
const relationKey = normalizedRelation.relationName;
|
|
1316
|
+
if (relationKey) {
|
|
1317
|
+
relations2[relationKey] = normalizedRelation;
|
|
1318
|
+
registeredRelationNames.add(relationKey);
|
|
1319
|
+
}
|
|
1320
|
+
} catch (e) {
|
|
1428
1321
|
}
|
|
1429
1322
|
});
|
|
1430
1323
|
}
|
|
@@ -1472,12 +1365,8 @@ function resolvePropertyRelation({
|
|
|
1472
1365
|
overrides: relProp.overrides
|
|
1473
1366
|
};
|
|
1474
1367
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
console.warn(`Unrecognized relation format for property '${propertyKey}' in collection '${sourceCollection.slug}'`);
|
|
1478
|
-
return void 0;
|
|
1479
|
-
}
|
|
1480
|
-
return relation;
|
|
1368
|
+
console.warn(`Unrecognized or missing relation target for property '${propertyKey}' in collection '${sourceCollection.slug}'`);
|
|
1369
|
+
return void 0;
|
|
1481
1370
|
}
|
|
1482
1371
|
function getTableName(collection) {
|
|
1483
1372
|
if (getDataSourceCapabilities(collection.driver).supportsRelations) {
|
|
@@ -1504,6 +1393,119 @@ function findRelation(resolvedRelations, key) {
|
|
|
1504
1393
|
if (snakeKey !== key && resolvedRelations[snakeKey]) return resolvedRelations[snakeKey];
|
|
1505
1394
|
return void 0;
|
|
1506
1395
|
}
|
|
1396
|
+
function getSubcollections(collection) {
|
|
1397
|
+
if (collection.childCollections) {
|
|
1398
|
+
return collection.childCollections() ?? [];
|
|
1399
|
+
}
|
|
1400
|
+
if (getDataSourceCapabilities(collection.driver).supportsSubcollections && collection.subcollections) {
|
|
1401
|
+
return collection.subcollections() ?? [];
|
|
1402
|
+
}
|
|
1403
|
+
if (getDataSourceCapabilities(collection.driver).supportsRelations) {
|
|
1404
|
+
const resolvedRelations = resolveCollectionRelations(collection);
|
|
1405
|
+
const manyRelations = Object.values(resolvedRelations).filter((r) => r.cardinality === "many");
|
|
1406
|
+
return manyRelations.map((r) => {
|
|
1407
|
+
const target = r.target();
|
|
1408
|
+
if (!target) return void 0;
|
|
1409
|
+
const relationKey = r.relationName || target.slug;
|
|
1410
|
+
let customName;
|
|
1411
|
+
if (collection.properties) {
|
|
1412
|
+
const prop = Object.entries(collection.properties).find(([_, p]) => p.type === "relation" && p.relationName === relationKey);
|
|
1413
|
+
if (prop && prop[1].name) {
|
|
1414
|
+
customName = prop[1].name;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
const baseOverrides = {
|
|
1418
|
+
slug: relationKey
|
|
1419
|
+
};
|
|
1420
|
+
if (customName) {
|
|
1421
|
+
baseOverrides.name = customName;
|
|
1422
|
+
baseOverrides.singularName = customName;
|
|
1423
|
+
}
|
|
1424
|
+
const targetWithOverrides = {
|
|
1425
|
+
...target,
|
|
1426
|
+
...baseOverrides
|
|
1427
|
+
};
|
|
1428
|
+
return r.overrides ? mergeDeep(targetWithOverrides, r.overrides) : targetWithOverrides;
|
|
1429
|
+
}).filter((c) => Boolean(c));
|
|
1430
|
+
}
|
|
1431
|
+
return [];
|
|
1432
|
+
}
|
|
1433
|
+
function hasPropertyCallbacks(properties, callbackName) {
|
|
1434
|
+
if (!properties) return false;
|
|
1435
|
+
for (const property of Object.values(properties)) {
|
|
1436
|
+
if (property.callbacks?.[callbackName]) return true;
|
|
1437
|
+
if (property.type === "map" && property.properties) {
|
|
1438
|
+
if (hasPropertyCallbacks(property.properties, callbackName)) return true;
|
|
1439
|
+
} else if (property.type === "array" && property.of) {
|
|
1440
|
+
const ofs = Array.isArray(property.of) ? property.of : [property.of];
|
|
1441
|
+
for (const of of ofs) {
|
|
1442
|
+
if (of.callbacks?.[callbackName]) return true;
|
|
1443
|
+
if (of.type === "map" && of.properties && hasPropertyCallbacks(of.properties, callbackName)) return true;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
return false;
|
|
1448
|
+
}
|
|
1449
|
+
async function processProperties(properties, values, previousValues, propsContext, callbackName) {
|
|
1450
|
+
if (!values || typeof values !== "object") return values;
|
|
1451
|
+
const result = {
|
|
1452
|
+
...values
|
|
1453
|
+
};
|
|
1454
|
+
for (const [key, property] of Object.entries(properties)) {
|
|
1455
|
+
if (result[key] === void 0) continue;
|
|
1456
|
+
let currentValue = result[key];
|
|
1457
|
+
const previousValue = previousValues?.[key];
|
|
1458
|
+
if (property.type === "array" && Array.isArray(currentValue)) {
|
|
1459
|
+
if (property.of && !Array.isArray(property.of)) {
|
|
1460
|
+
currentValue = await Promise.all(currentValue.map(async (item, index) => {
|
|
1461
|
+
const prevItem = Array.isArray(previousValue) ? previousValue[index] : void 0;
|
|
1462
|
+
const singlePropData = {
|
|
1463
|
+
"_tmp": property.of
|
|
1464
|
+
};
|
|
1465
|
+
const res = await processProperties(singlePropData, {
|
|
1466
|
+
"_tmp": item
|
|
1467
|
+
}, {
|
|
1468
|
+
"_tmp": prevItem
|
|
1469
|
+
}, propsContext, callbackName);
|
|
1470
|
+
return res["_tmp"];
|
|
1471
|
+
}));
|
|
1472
|
+
}
|
|
1473
|
+
} else if (property.type === "map" && property.properties && typeof currentValue === "object") {
|
|
1474
|
+
currentValue = await processProperties(property.properties, currentValue, previousValue ?? {}, propsContext, callbackName);
|
|
1475
|
+
}
|
|
1476
|
+
if (property.callbacks?.[callbackName]) {
|
|
1477
|
+
const cbRes = await Promise.resolve(property.callbacks[callbackName]({
|
|
1478
|
+
...propsContext,
|
|
1479
|
+
value: currentValue,
|
|
1480
|
+
previousValue
|
|
1481
|
+
}));
|
|
1482
|
+
if (cbRes !== void 0) {
|
|
1483
|
+
currentValue = cbRes;
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
result[key] = currentValue;
|
|
1487
|
+
}
|
|
1488
|
+
return result;
|
|
1489
|
+
}
|
|
1490
|
+
const buildPropertyCallbacks = (properties) => {
|
|
1491
|
+
if (!properties) return void 0;
|
|
1492
|
+
const propertyCallbacks = {};
|
|
1493
|
+
if (hasPropertyCallbacks(properties, "afterRead")) {
|
|
1494
|
+
propertyCallbacks.afterRead = async (props) => {
|
|
1495
|
+
const processedValues = await processProperties(properties, props.entity.values, props.entity.values, props, "afterRead");
|
|
1496
|
+
return {
|
|
1497
|
+
...props.entity,
|
|
1498
|
+
values: processedValues
|
|
1499
|
+
};
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
if (hasPropertyCallbacks(properties, "beforeSave")) {
|
|
1503
|
+
propertyCallbacks.beforeSave = async (props) => {
|
|
1504
|
+
return await processProperties(properties, props.values, props.previousValues ?? {}, props, "beforeSave");
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
return Object.keys(propertyCallbacks).length > 0 ? propertyCallbacks : void 0;
|
|
1508
|
+
};
|
|
1507
1509
|
var logic = { exports: {} };
|
|
1508
1510
|
(function(module, exports) {
|
|
1509
1511
|
(function(root, factory) {
|
|
@@ -2411,8 +2413,18 @@ class CollectionRegistry {
|
|
|
2411
2413
|
const mergedRelationsRaw = [...extractedRelations];
|
|
2412
2414
|
for (const manual of manualRelations) {
|
|
2413
2415
|
const name = manual.relationName;
|
|
2414
|
-
if (!name
|
|
2416
|
+
if (!name) {
|
|
2415
2417
|
mergedRelationsRaw.push(manual);
|
|
2418
|
+
} else {
|
|
2419
|
+
const existingIndex = mergedRelationsRaw.findIndex((r) => r.relationName === name);
|
|
2420
|
+
if (existingIndex === -1) {
|
|
2421
|
+
mergedRelationsRaw.push(manual);
|
|
2422
|
+
} else {
|
|
2423
|
+
mergedRelationsRaw[existingIndex] = {
|
|
2424
|
+
...manual,
|
|
2425
|
+
...mergedRelationsRaw[existingIndex]
|
|
2426
|
+
};
|
|
2427
|
+
}
|
|
2416
2428
|
}
|
|
2417
2429
|
}
|
|
2418
2430
|
let mergedRelations = mergedRelationsRaw;
|
|
@@ -2632,6 +2644,118 @@ class CollectionRegistry {
|
|
|
2632
2644
|
};
|
|
2633
2645
|
}
|
|
2634
2646
|
}
|
|
2647
|
+
function mapOperator(op) {
|
|
2648
|
+
switch (op) {
|
|
2649
|
+
case "==":
|
|
2650
|
+
return "eq";
|
|
2651
|
+
case "!=":
|
|
2652
|
+
return "neq";
|
|
2653
|
+
case ">":
|
|
2654
|
+
return "gt";
|
|
2655
|
+
case ">=":
|
|
2656
|
+
return "gte";
|
|
2657
|
+
case "<":
|
|
2658
|
+
return "lt";
|
|
2659
|
+
case "<=":
|
|
2660
|
+
return "lte";
|
|
2661
|
+
case "array-contains":
|
|
2662
|
+
return "cs";
|
|
2663
|
+
case "array-contains-any":
|
|
2664
|
+
return "csa";
|
|
2665
|
+
case "not-in":
|
|
2666
|
+
return "nin";
|
|
2667
|
+
default:
|
|
2668
|
+
return op;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
class QueryBuilder {
|
|
2672
|
+
constructor(collection) {
|
|
2673
|
+
this.collection = collection;
|
|
2674
|
+
}
|
|
2675
|
+
params = {
|
|
2676
|
+
where: {}
|
|
2677
|
+
};
|
|
2678
|
+
/**
|
|
2679
|
+
* Add a filter condition to your query.
|
|
2680
|
+
* @example
|
|
2681
|
+
* client.collection('users').where('age', '>=', 18).find()
|
|
2682
|
+
*/
|
|
2683
|
+
where(column, operator, value) {
|
|
2684
|
+
if (!this.params.where) {
|
|
2685
|
+
this.params.where = {};
|
|
2686
|
+
}
|
|
2687
|
+
const mappedOp = mapOperator(operator);
|
|
2688
|
+
let formattedValue = value;
|
|
2689
|
+
if (Array.isArray(value) && ["in", "nin", "cs", "csa"].includes(mappedOp)) {
|
|
2690
|
+
formattedValue = `(${value.join(",")})`;
|
|
2691
|
+
} else if (value === null) {
|
|
2692
|
+
formattedValue = "null";
|
|
2693
|
+
}
|
|
2694
|
+
this.params.where[column] = mappedOp === "eq" ? String(formattedValue) : `${mappedOp}.${formattedValue}`;
|
|
2695
|
+
return this;
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* Order the results by a specific column.
|
|
2699
|
+
* @example
|
|
2700
|
+
* client.collection('users').orderBy('createdAt', 'desc').find()
|
|
2701
|
+
*/
|
|
2702
|
+
orderBy(column, ascending = "asc") {
|
|
2703
|
+
this.params.orderBy = `${column}:${ascending}`;
|
|
2704
|
+
return this;
|
|
2705
|
+
}
|
|
2706
|
+
/**
|
|
2707
|
+
* Limit the number of results returned.
|
|
2708
|
+
*/
|
|
2709
|
+
limit(count2) {
|
|
2710
|
+
this.params.limit = count2;
|
|
2711
|
+
return this;
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Skip the first N results.
|
|
2715
|
+
*/
|
|
2716
|
+
offset(count2) {
|
|
2717
|
+
this.params.offset = count2;
|
|
2718
|
+
return this;
|
|
2719
|
+
}
|
|
2720
|
+
/**
|
|
2721
|
+
* Set a free-text search string if supported by the backend.
|
|
2722
|
+
*/
|
|
2723
|
+
search(searchString) {
|
|
2724
|
+
this.params.searchString = searchString;
|
|
2725
|
+
return this;
|
|
2726
|
+
}
|
|
2727
|
+
/**
|
|
2728
|
+
* Include related entities in the response.
|
|
2729
|
+
* Relations will be populated with full entity data instead of just IDs.
|
|
2730
|
+
*
|
|
2731
|
+
* @param relations - Relation names to include, or "*" for all.
|
|
2732
|
+
* @example
|
|
2733
|
+
* // Include specific relations
|
|
2734
|
+
* client.data.posts.include("tags", "author").find()
|
|
2735
|
+
*
|
|
2736
|
+
* // Include all relations
|
|
2737
|
+
* client.data.posts.include("*").find()
|
|
2738
|
+
*/
|
|
2739
|
+
include(...relations2) {
|
|
2740
|
+
this.params.include = relations2;
|
|
2741
|
+
return this;
|
|
2742
|
+
}
|
|
2743
|
+
/**
|
|
2744
|
+
* Execute the find query and return the results.
|
|
2745
|
+
*/
|
|
2746
|
+
async find() {
|
|
2747
|
+
return this.collection.find(this.params);
|
|
2748
|
+
}
|
|
2749
|
+
/**
|
|
2750
|
+
* Listen to realtime updates matching this query.
|
|
2751
|
+
*/
|
|
2752
|
+
listen(onUpdate, onError) {
|
|
2753
|
+
if (!this.collection.listen) {
|
|
2754
|
+
throw new Error("Listen is only available when RebaseClient is configured with a websocketUrl.");
|
|
2755
|
+
}
|
|
2756
|
+
return this.collection.listen(this.params, onUpdate, onError);
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2635
2759
|
function convertWhereToFilter(where) {
|
|
2636
2760
|
if (!where) return void 0;
|
|
2637
2761
|
const operatorMap = {
|
|
@@ -2711,7 +2835,7 @@ function parseOrderBy(orderBy) {
|
|
|
2711
2835
|
return [field, direction];
|
|
2712
2836
|
}
|
|
2713
2837
|
function createDriverAccessor(driver, slug) {
|
|
2714
|
-
|
|
2838
|
+
const accessor = {
|
|
2715
2839
|
async find(params) {
|
|
2716
2840
|
const orderParsed = parseOrderBy(params?.orderBy);
|
|
2717
2841
|
const entities = await driver.fetchCollection({
|
|
@@ -2805,8 +2929,28 @@ function createDriverAccessor(driver, slug) {
|
|
|
2805
2929
|
onUpdate: (entity) => onUpdate(entity ?? void 0),
|
|
2806
2930
|
onError
|
|
2807
2931
|
});
|
|
2808
|
-
} : void 0
|
|
2932
|
+
} : void 0,
|
|
2933
|
+
// Fluent Query Builder
|
|
2934
|
+
where(column, operator, value) {
|
|
2935
|
+
return new QueryBuilder(accessor).where(column, operator, value);
|
|
2936
|
+
},
|
|
2937
|
+
orderBy(column, ascending) {
|
|
2938
|
+
return new QueryBuilder(accessor).orderBy(column, ascending);
|
|
2939
|
+
},
|
|
2940
|
+
limit(count2) {
|
|
2941
|
+
return new QueryBuilder(accessor).limit(count2);
|
|
2942
|
+
},
|
|
2943
|
+
offset(count2) {
|
|
2944
|
+
return new QueryBuilder(accessor).offset(count2);
|
|
2945
|
+
},
|
|
2946
|
+
search(searchString) {
|
|
2947
|
+
return new QueryBuilder(accessor).search(searchString);
|
|
2948
|
+
},
|
|
2949
|
+
include(...relations2) {
|
|
2950
|
+
return new QueryBuilder(accessor).include(...relations2);
|
|
2951
|
+
}
|
|
2809
2952
|
};
|
|
2953
|
+
return accessor;
|
|
2810
2954
|
}
|
|
2811
2955
|
function buildRebaseData(driver) {
|
|
2812
2956
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -6514,7 +6658,7 @@ class PostgresBackendDriver {
|
|
|
6514
6658
|
callbacks: void 0,
|
|
6515
6659
|
propertyCallbacks: void 0
|
|
6516
6660
|
};
|
|
6517
|
-
const registryCollection = this.registry
|
|
6661
|
+
const registryCollection = this.registry?.getCollectionByPath(path2);
|
|
6518
6662
|
const resolvedCollection = registryCollection ? {
|
|
6519
6663
|
...collection,
|
|
6520
6664
|
...registryCollection
|
|
@@ -6562,7 +6706,8 @@ class PostgresBackendDriver {
|
|
|
6562
6706
|
user: this.user,
|
|
6563
6707
|
driver: this,
|
|
6564
6708
|
data: this.data,
|
|
6565
|
-
client: this.client
|
|
6709
|
+
client: this.client,
|
|
6710
|
+
storageSource: this.client?.storage
|
|
6566
6711
|
};
|
|
6567
6712
|
return Promise.all(entities.map(async (entity) => {
|
|
6568
6713
|
let fetched = entity;
|
|
@@ -6657,7 +6802,8 @@ class PostgresBackendDriver {
|
|
|
6657
6802
|
user: this.user,
|
|
6658
6803
|
driver: this,
|
|
6659
6804
|
data: this.data,
|
|
6660
|
-
client: this.client
|
|
6805
|
+
client: this.client,
|
|
6806
|
+
storageSource: this.client?.storage
|
|
6661
6807
|
};
|
|
6662
6808
|
if (callbacks?.afterRead) {
|
|
6663
6809
|
entity = await callbacks.afterRead({
|
|
@@ -6727,7 +6873,8 @@ class PostgresBackendDriver {
|
|
|
6727
6873
|
user: this.user,
|
|
6728
6874
|
driver: this,
|
|
6729
6875
|
data: this.data,
|
|
6730
|
-
client: this.client
|
|
6876
|
+
client: this.client,
|
|
6877
|
+
storageSource: this.client?.storage
|
|
6731
6878
|
};
|
|
6732
6879
|
let previousValuesForHistory;
|
|
6733
6880
|
if (status === "existing" && entityId) {
|
|
@@ -6876,7 +7023,8 @@ class PostgresBackendDriver {
|
|
|
6876
7023
|
user: this.user,
|
|
6877
7024
|
driver: this,
|
|
6878
7025
|
data: this.data,
|
|
6879
|
-
client: this.client
|
|
7026
|
+
client: this.client,
|
|
7027
|
+
storageSource: this.client?.storage
|
|
6880
7028
|
};
|
|
6881
7029
|
if (callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {
|
|
6882
7030
|
let preventDefault = false;
|
|
@@ -8155,6 +8303,7 @@ const defaultUsersCollection = {
|
|
|
8155
8303
|
singularName: "User",
|
|
8156
8304
|
slug: "users",
|
|
8157
8305
|
table: "users",
|
|
8306
|
+
schema: "rebase",
|
|
8158
8307
|
icon: "Users",
|
|
8159
8308
|
group: "Settings",
|
|
8160
8309
|
properties: {
|