@ronin/compiler 0.10.3-leo-ron-1083-experimental-219 → 0.10.3-leo-ron-1083-experimental-221
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +161 -107
- package/package.json +1 -1
package/README.md
CHANGED
@@ -65,9 +65,11 @@ Once the RONIN queries have been compiled down to SQL statements, the statements
|
|
65
65
|
executed and their results can be formatted by the compiler as well:
|
66
66
|
|
67
67
|
```typescript
|
68
|
-
// `
|
68
|
+
// Passing `rawResults` (rows being of arrays of values) provided by the database (ideal)
|
69
|
+
const results: Array<Result> = transaction.formatResults(rawResults);
|
69
70
|
|
70
|
-
|
71
|
+
// Passing `objectResults` (rows being of objects) provided by a driver
|
72
|
+
const results: Array<Result> = transaction.formatResults(objectResults, false);
|
71
73
|
```
|
72
74
|
|
73
75
|
#### Root Model
|
@@ -133,12 +135,13 @@ new Transaction(queries, {
|
|
133
135
|
//
|
134
136
|
// If the driver being used instead returns an object for every row, the driver must
|
135
137
|
// ensure the uniqueness of every key in that object, which means prefixing duplicated
|
136
|
-
// column names with the name of the respective table, if multiple tables are joined
|
138
|
+
// column names with the name of the respective table, if multiple tables are joined
|
139
|
+
// (example for an object key: "table_name.column_name").
|
137
140
|
//
|
138
141
|
// Drivers that return objects for rows offer this behavior as an option that is
|
139
142
|
// usually called "expand columns". If the driver being used does not offer such an
|
140
143
|
// option, you can instead activate the option in the compiler, which results in longer
|
141
|
-
// SQL statements because
|
144
|
+
// SQL statements because all column names are aliased.
|
142
145
|
expandColumns: true
|
143
146
|
});
|
144
147
|
```
|
package/dist/index.d.ts
CHANGED
@@ -5867,7 +5867,7 @@ type ModelFieldBasics = {
|
|
5867
5867
|
increment?: boolean;
|
5868
5868
|
};
|
5869
5869
|
type ModelFieldNormal = ModelFieldBasics & {
|
5870
|
-
type: 'string' | 'number' | 'boolean' | 'date' | 'json'
|
5870
|
+
type: 'string' | 'number' | 'boolean' | 'date' | 'json';
|
5871
5871
|
};
|
5872
5872
|
type ModelFieldReferenceAction = 'CASCADE' | 'RESTRICT' | 'SET NULL' | 'SET DEFAULT' | 'NO ACTION';
|
5873
5873
|
type ModelFieldReference = ModelFieldBasics & {
|
@@ -5984,7 +5984,8 @@ type PublicModel<T extends Array<ModelField> = Array<ModelField>> = Omit<Partial
|
|
5984
5984
|
identifiers?: Partial<Model['identifiers']>;
|
5985
5985
|
};
|
5986
5986
|
|
5987
|
-
type
|
5987
|
+
type RawRow = Array<unknown>;
|
5988
|
+
type ObjectRow = Record<string, unknown>;
|
5988
5989
|
type NativeRecord = Record<string, unknown> & {
|
5989
5990
|
id: string;
|
5990
5991
|
ronin: {
|
@@ -6059,6 +6060,7 @@ declare class Transaction {
|
|
6059
6060
|
statements: Array<Statement>;
|
6060
6061
|
models: Array<Model>;
|
6061
6062
|
private queries;
|
6063
|
+
private fields;
|
6062
6064
|
constructor(queries: Array<Query>, options?: TransactionOptions);
|
6063
6065
|
/**
|
6064
6066
|
* Composes SQL statements for the provided RONIN queries.
|
@@ -6070,8 +6072,9 @@ declare class Transaction {
|
|
6070
6072
|
* @returns The composed SQL statements.
|
6071
6073
|
*/
|
6072
6074
|
private compileQueries;
|
6073
|
-
private
|
6074
|
-
|
6075
|
+
private formatRow;
|
6076
|
+
formatResults(results: Array<Array<RawRow>>, raw?: true): Array<Result>;
|
6077
|
+
formatResults(results: Array<Array<ObjectRow>>, raw?: false): Array<Result>;
|
6075
6078
|
}
|
6076
6079
|
|
6077
6080
|
declare const CLEAN_ROOT_MODEL: PublicModel;
|
package/dist/index.js
CHANGED
@@ -20,6 +20,7 @@ var RONIN_MODEL_FIELD_REGEX = new RegExp(
|
|
20
20
|
`${QUERY_SYMBOLS.FIELD}[_a-zA-Z0-9.]+`,
|
21
21
|
"g"
|
22
22
|
);
|
23
|
+
var composeIncludedTableAlias = (fieldSlug) => `including_${fieldSlug}`;
|
23
24
|
var MODEL_ENTITY_ERROR_CODES = {
|
24
25
|
field: "FIELD_NOT_FOUND",
|
25
26
|
index: "INDEX_NOT_FOUND",
|
@@ -117,7 +118,11 @@ var omit = (obj, properties) => Object.fromEntries(
|
|
117
118
|
var expand = (obj) => {
|
118
119
|
return Object.entries(obj).reduce((res, [key, val]) => {
|
119
120
|
key.split(".").reduce((acc, part, i, arr) => {
|
120
|
-
|
121
|
+
if (i === arr.length - 1) {
|
122
|
+
acc[part] = val;
|
123
|
+
} else {
|
124
|
+
acc[part] = typeof acc[part] === "object" && acc[part] !== null ? acc[part] : {};
|
125
|
+
}
|
121
126
|
return acc[part];
|
122
127
|
}, res);
|
123
128
|
return res;
|
@@ -208,47 +213,52 @@ var composeConditions = (models, model, statementParams, instructionName, value,
|
|
208
213
|
return conditions.join(" AND ");
|
209
214
|
}
|
210
215
|
if (options.fieldSlug) {
|
211
|
-
const
|
212
|
-
|
213
|
-
|
214
|
-
if (!
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
if (
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
216
|
+
const childField = model.fields.some(({ slug }) => {
|
217
|
+
return slug.includes(".") && slug.split(".")[0] === options.fieldSlug;
|
218
|
+
});
|
219
|
+
if (!childField) {
|
220
|
+
const fieldDetails = getFieldFromModel(model, options.fieldSlug, instructionName);
|
221
|
+
const { field: modelField } = fieldDetails || {};
|
222
|
+
const consumeJSON = modelField?.type === "json" && instructionName === "to";
|
223
|
+
if (modelField && !(isObject(value) || Array.isArray(value)) || getSymbol(value) || consumeJSON) {
|
224
|
+
return composeFieldValues(
|
225
|
+
models,
|
226
|
+
model,
|
227
|
+
statementParams,
|
228
|
+
instructionName,
|
229
|
+
value,
|
230
|
+
{ ...options, fieldSlug: options.fieldSlug }
|
231
|
+
);
|
232
|
+
}
|
233
|
+
if (modelField?.type === "link" && isNested) {
|
234
|
+
const keys = Object.keys(value);
|
235
|
+
const values = Object.values(value);
|
236
|
+
let recordTarget;
|
237
|
+
if (keys.length === 1 && keys[0] === "id") {
|
238
|
+
recordTarget = values[0];
|
239
|
+
} else {
|
240
|
+
const relatedModel = getModelBySlug(models, modelField.target);
|
241
|
+
const subQuery = {
|
242
|
+
get: {
|
243
|
+
[relatedModel.slug]: {
|
244
|
+
with: value,
|
245
|
+
selecting: ["id"]
|
246
|
+
}
|
237
247
|
}
|
238
|
-
}
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
}
|
248
|
+
};
|
249
|
+
recordTarget = {
|
250
|
+
[QUERY_SYMBOLS.QUERY]: subQuery
|
251
|
+
};
|
252
|
+
}
|
253
|
+
return composeConditions(
|
254
|
+
models,
|
255
|
+
model,
|
256
|
+
statementParams,
|
257
|
+
instructionName,
|
258
|
+
recordTarget,
|
259
|
+
options
|
260
|
+
);
|
243
261
|
}
|
244
|
-
return composeConditions(
|
245
|
-
models,
|
246
|
-
model,
|
247
|
-
statementParams,
|
248
|
-
instructionName,
|
249
|
-
recordTarget,
|
250
|
-
options
|
251
|
-
);
|
252
262
|
}
|
253
263
|
}
|
254
264
|
if (isNested) {
|
@@ -358,7 +368,7 @@ var getFieldSelector = (model, field, fieldPath, instructionName) => {
|
|
358
368
|
}
|
359
369
|
return `${tablePrefix}"${fieldPath}"`;
|
360
370
|
};
|
361
|
-
|
371
|
+
function getFieldFromModel(model, fieldPath, instructionName, shouldThrow = true) {
|
362
372
|
const errorPrefix = `Field "${fieldPath}" defined for \`${instructionName}\``;
|
363
373
|
const modelFields = model.fields || [];
|
364
374
|
let modelField;
|
@@ -376,16 +386,19 @@ var getFieldFromModel = (model, fieldPath, instructionName) => {
|
|
376
386
|
}
|
377
387
|
modelField = modelFields.find((field) => field.slug === fieldPath);
|
378
388
|
if (!modelField) {
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
389
|
+
if (shouldThrow) {
|
390
|
+
throw new RoninError({
|
391
|
+
message: `${errorPrefix} does not exist in model "${model.name}".`,
|
392
|
+
code: "FIELD_NOT_FOUND",
|
393
|
+
field: fieldPath,
|
394
|
+
queries: null
|
395
|
+
});
|
396
|
+
}
|
397
|
+
return null;
|
385
398
|
}
|
386
399
|
const fieldSelector = getFieldSelector(model, modelField, fieldPath, instructionName);
|
387
400
|
return { field: modelField, fieldSelector };
|
388
|
-
}
|
401
|
+
}
|
389
402
|
var slugToName = (slug) => {
|
390
403
|
const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
|
391
404
|
return title(name);
|
@@ -441,11 +454,6 @@ var SYSTEM_FIELDS = [
|
|
441
454
|
slug: "id",
|
442
455
|
displayAs: "single-line"
|
443
456
|
},
|
444
|
-
{
|
445
|
-
name: "RONIN",
|
446
|
-
type: "group",
|
447
|
-
slug: "ronin"
|
448
|
-
},
|
449
457
|
{
|
450
458
|
name: "RONIN - Locked",
|
451
459
|
type: "boolean",
|
@@ -489,7 +497,6 @@ var ROOT_MODEL = {
|
|
489
497
|
{ slug: "pluralSlug", type: "string" },
|
490
498
|
{ slug: "idPrefix", type: "string" },
|
491
499
|
{ slug: "table", type: "string" },
|
492
|
-
{ slug: "identifiers", type: "group" },
|
493
500
|
{ slug: "identifiers.name", type: "string" },
|
494
501
|
{ slug: "identifiers.slug", type: "string" },
|
495
502
|
// Providing an empty object as a default value allows us to use `json_insert`
|
@@ -611,7 +618,6 @@ var typesInSQLite = {
|
|
611
618
|
json: "TEXT"
|
612
619
|
};
|
613
620
|
var getFieldStatement = (models, model, field) => {
|
614
|
-
if (field.type === "group") return null;
|
615
621
|
let statement = `"${field.slug}" ${typesInSQLite[field.type]}`;
|
616
622
|
if (field.slug === "id") statement += " PRIMARY KEY";
|
617
623
|
if (field.unique === true) statement += " UNIQUE";
|
@@ -1103,7 +1109,7 @@ var handleIncluding = (models, model, statementParams, instruction) => {
|
|
1103
1109
|
const relatedModel = getModelBySlug(models, queryModel);
|
1104
1110
|
let joinType = "LEFT";
|
1105
1111
|
let relatedTableSelector = `"${relatedModel.table}"`;
|
1106
|
-
const tableAlias =
|
1112
|
+
const tableAlias = composeIncludedTableAlias(ephemeralFieldSlug);
|
1107
1113
|
const single = queryModel !== relatedModel.pluralSlug;
|
1108
1114
|
if (!modifiableQueryInstructions?.with) {
|
1109
1115
|
joinType = "CROSS";
|
@@ -1185,49 +1191,69 @@ var handleOrderedBy = (model, instruction) => {
|
|
1185
1191
|
|
1186
1192
|
// src/instructions/selecting.ts
|
1187
1193
|
var handleSelecting = (models, model, statementParams, instructions, options) => {
|
1194
|
+
let loadedFields = [];
|
1195
|
+
let statement = "*";
|
1188
1196
|
let isJoining = false;
|
1189
|
-
let statement = instructions.selecting ? instructions.selecting.map((slug) => {
|
1190
|
-
return getFieldFromModel(model, slug, "selecting").fieldSelector;
|
1191
|
-
}).join(", ") : "*";
|
1192
1197
|
if (instructions.including) {
|
1193
1198
|
const flatObject = flatten(instructions.including);
|
1194
|
-
|
1199
|
+
instructions.including = {};
|
1200
|
+
for (const [key, value] of Object.entries(flatObject)) {
|
1195
1201
|
const symbol = getSymbol(value);
|
1196
1202
|
if (symbol?.type === "query") {
|
1197
1203
|
isJoining = true;
|
1198
|
-
|
1199
|
-
const
|
1200
|
-
const
|
1201
|
-
const
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
|
1213
|
-
|
1214
|
-
|
1215
|
-
|
1216
|
-
});
|
1204
|
+
const { queryModel, queryInstructions } = splitQuery(symbol.value);
|
1205
|
+
const subQueryModel = getModelBySlug(models, queryModel);
|
1206
|
+
const tableName = composeIncludedTableAlias(key);
|
1207
|
+
const queryModelFields = queryInstructions?.selecting ? subQueryModel.fields.filter((field) => {
|
1208
|
+
return queryInstructions.selecting?.includes(field.slug);
|
1209
|
+
}) : subQueryModel.fields;
|
1210
|
+
for (const field of queryModelFields) {
|
1211
|
+
loadedFields.push({ ...field, parentField: key });
|
1212
|
+
if (options?.expandColumns) {
|
1213
|
+
const newValue2 = parseFieldExpression(
|
1214
|
+
{ ...subQueryModel, tableAlias: tableName },
|
1215
|
+
"including",
|
1216
|
+
`${QUERY_SYMBOLS.FIELD}${field.slug}`
|
1217
|
+
);
|
1218
|
+
instructions.including[`${tableName}.${field.slug}`] = newValue2;
|
1219
|
+
}
|
1220
|
+
}
|
1221
|
+
continue;
|
1217
1222
|
}
|
1223
|
+
let newValue = value;
|
1218
1224
|
if (symbol?.type === "expression") {
|
1219
|
-
|
1225
|
+
newValue = `(${parseFieldExpression(model, "including", symbol.value)})`;
|
1220
1226
|
} else {
|
1221
|
-
|
1227
|
+
newValue = prepareStatementValue(statementParams, value);
|
1222
1228
|
}
|
1223
|
-
|
1224
|
-
}).filter((entry) => entry !== null).map((entry) => [entry.key, entry.value]);
|
1225
|
-
if (filteredObject.length > 0) {
|
1226
|
-
statement += ", ";
|
1227
|
-
statement += filteredObject.map(([key, value]) => `${value} as "${key}"`).join(", ");
|
1229
|
+
instructions.including[key] = newValue;
|
1228
1230
|
}
|
1229
1231
|
}
|
1230
|
-
|
1232
|
+
const expandColumns = isJoining && options?.expandColumns;
|
1233
|
+
if (expandColumns) {
|
1234
|
+
instructions.selecting = model.fields.map((field) => field.slug);
|
1235
|
+
}
|
1236
|
+
if (instructions.selecting) {
|
1237
|
+
const usableModel = expandColumns ? { ...model, tableAlias: model.tableAlias || model.table } : model;
|
1238
|
+
const selectedFields = [];
|
1239
|
+
statement = instructions.selecting.map((slug) => {
|
1240
|
+
const { field, fieldSelector } = getFieldFromModel(
|
1241
|
+
usableModel,
|
1242
|
+
slug,
|
1243
|
+
"selecting"
|
1244
|
+
);
|
1245
|
+
selectedFields.push(field);
|
1246
|
+
return fieldSelector;
|
1247
|
+
}).join(", ");
|
1248
|
+
loadedFields = [...selectedFields, ...loadedFields];
|
1249
|
+
} else {
|
1250
|
+
loadedFields = [...model.fields, ...loadedFields];
|
1251
|
+
}
|
1252
|
+
if (instructions.including && Object.keys(instructions.including).length > 0) {
|
1253
|
+
statement += ", ";
|
1254
|
+
statement += Object.entries(instructions.including).map(([key, value]) => `${value} as "${key}"`).join(", ");
|
1255
|
+
}
|
1256
|
+
return { columns: statement, isJoining, loadedFields };
|
1231
1257
|
};
|
1232
1258
|
|
1233
1259
|
// src/instructions/to.ts
|
@@ -1294,8 +1320,8 @@ var handleTo = (models, model, statementParams, queryType, dependencyStatements,
|
|
1294
1320
|
Object.assign(toInstruction, defaultFields);
|
1295
1321
|
for (const fieldSlug in toInstruction) {
|
1296
1322
|
const fieldValue = toInstruction[fieldSlug];
|
1297
|
-
const fieldDetails = getFieldFromModel(model, fieldSlug, "to");
|
1298
|
-
if (fieldDetails
|
1323
|
+
const fieldDetails = getFieldFromModel(model, fieldSlug, "to", false);
|
1324
|
+
if (fieldDetails?.field.type === "link" && fieldDetails.field.kind === "many") {
|
1299
1325
|
delete toInstruction[fieldSlug];
|
1300
1326
|
const associativeModelSlug = composeAssociationModelSlug(model, fieldDetails.field);
|
1301
1327
|
const composeStatement = (subQueryType, value) => {
|
@@ -1360,7 +1386,8 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
1360
1386
|
statementParams,
|
1361
1387
|
defaultQuery
|
1362
1388
|
);
|
1363
|
-
if (query === null)
|
1389
|
+
if (query === null)
|
1390
|
+
return { dependencies: [], main: dependencyStatements[0], loadedFields: [] };
|
1364
1391
|
const parsedQuery = splitQuery(query);
|
1365
1392
|
const { queryType, queryModel, queryInstructions } = parsedQuery;
|
1366
1393
|
const model = getModelBySlug(models, queryModel);
|
@@ -1370,7 +1397,7 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
1370
1397
|
if (instructions && Object.hasOwn(instructions, "for")) {
|
1371
1398
|
instructions = handleFor(model, instructions);
|
1372
1399
|
}
|
1373
|
-
const { columns, isJoining } = handleSelecting(
|
1400
|
+
const { columns, isJoining, loadedFields } = handleSelecting(
|
1374
1401
|
models,
|
1375
1402
|
model,
|
1376
1403
|
statementParams,
|
@@ -1499,7 +1526,8 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
1499
1526
|
if (returning) mainStatement.returning = true;
|
1500
1527
|
return {
|
1501
1528
|
dependencies: dependencyStatements,
|
1502
|
-
main: mainStatement
|
1529
|
+
main: mainStatement,
|
1530
|
+
loadedFields
|
1503
1531
|
};
|
1504
1532
|
};
|
1505
1533
|
|
@@ -1508,6 +1536,7 @@ var Transaction = class {
|
|
1508
1536
|
statements;
|
1509
1537
|
models = [];
|
1510
1538
|
queries;
|
1539
|
+
fields = [];
|
1511
1540
|
constructor(queries, options) {
|
1512
1541
|
const models = options?.models || [];
|
1513
1542
|
this.statements = this.compileQueries(queries, models, options);
|
@@ -1544,42 +1573,67 @@ var Transaction = class {
|
|
1544
1573
|
);
|
1545
1574
|
dependencyStatements.push(...result.dependencies);
|
1546
1575
|
mainStatements.push(result.main);
|
1576
|
+
this.fields.push(result.loadedFields);
|
1547
1577
|
}
|
1548
1578
|
this.models = modelListWithPresets;
|
1549
1579
|
return [...dependencyStatements, ...mainStatements];
|
1550
1580
|
};
|
1551
|
-
|
1552
|
-
const
|
1553
|
-
for (
|
1554
|
-
const
|
1581
|
+
formatRow(fields, row) {
|
1582
|
+
const record = {};
|
1583
|
+
for (let index = 0; index < row.length; index++) {
|
1584
|
+
const value = row[index];
|
1585
|
+
const field = fields[index];
|
1586
|
+
let newSlug = field.slug;
|
1587
|
+
let newValue = value;
|
1588
|
+
const parentFieldSlug = field.parentField;
|
1589
|
+
if (parentFieldSlug) {
|
1590
|
+
newSlug = `${parentFieldSlug}.${field.slug}`;
|
1591
|
+
}
|
1555
1592
|
if (field.type === "json") {
|
1556
|
-
|
1557
|
-
continue;
|
1593
|
+
newValue = JSON.parse(value);
|
1558
1594
|
}
|
1559
|
-
|
1595
|
+
record[newSlug] = newValue;
|
1560
1596
|
}
|
1561
|
-
return expand(
|
1597
|
+
return expand(record);
|
1562
1598
|
}
|
1563
|
-
|
1599
|
+
/**
|
1600
|
+
* Format the results returned from the database into RONIN records.
|
1601
|
+
*
|
1602
|
+
* @param results - A list of results from the database, where each result is an array
|
1603
|
+
* of rows.
|
1604
|
+
* @param raw - By default, rows are expected to be arrays of values, which is how SQL
|
1605
|
+
* databases return rows by default. If the driver being used returns rows as objects
|
1606
|
+
* instead, this option should be set to `false`.
|
1607
|
+
*
|
1608
|
+
* @returns A list of formatted RONIN results, where each result is either a single
|
1609
|
+
* RONIN record, an array of RONIN records, or a RONIN count result.
|
1610
|
+
*/
|
1611
|
+
formatResults(results, raw = true) {
|
1564
1612
|
const relevantResults = results.filter((_, index) => {
|
1565
1613
|
return this.statements[index].returning;
|
1566
1614
|
});
|
1567
|
-
|
1615
|
+
const normalizedResults = raw ? relevantResults : relevantResults.map((rows) => {
|
1616
|
+
return rows.map((row) => {
|
1617
|
+
if (Array.isArray(row)) return row;
|
1618
|
+
if (row["COUNT(*)"]) return [row["COUNT(*)"]];
|
1619
|
+
return Object.values(row);
|
1620
|
+
});
|
1621
|
+
});
|
1622
|
+
return normalizedResults.map((rows, index) => {
|
1568
1623
|
const query = this.queries.at(-index);
|
1624
|
+
const fields = this.fields.at(-index);
|
1569
1625
|
const { queryType, queryModel, queryInstructions } = splitQuery(query);
|
1570
1626
|
const model = getModelBySlug(this.models, queryModel);
|
1571
1627
|
if (queryType === "count") {
|
1572
|
-
return { amount:
|
1628
|
+
return { amount: rows[0][0] };
|
1573
1629
|
}
|
1574
1630
|
const single = queryModel !== model.pluralSlug;
|
1575
1631
|
if (single) {
|
1576
|
-
return { record: this.
|
1632
|
+
return { record: this.formatRow(fields, rows[0]) };
|
1577
1633
|
}
|
1578
1634
|
const pageSize = queryInstructions?.limitedTo;
|
1579
1635
|
const output = {
|
1580
|
-
records:
|
1581
|
-
return this.formatRecord(model, resultItem);
|
1582
|
-
})
|
1636
|
+
records: rows.map((row) => this.formatRow(fields, row))
|
1583
1637
|
};
|
1584
1638
|
if (pageSize && output.records.length > 0) {
|
1585
1639
|
if (queryInstructions?.before || queryInstructions?.after) {
|
package/package.json
CHANGED