@ronin/compiler 0.14.0 → 0.14.1
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/index.d.ts +1 -1
- package/dist/index.js +149 -102
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
@@ -169,7 +169,7 @@ type ModelFieldBasics = {
|
|
169
169
|
* The value that should be inserted into the field in the case that no value was
|
170
170
|
* explicitly provided for it when a record is created.
|
171
171
|
*/
|
172
|
-
defaultValue?: unknown;
|
172
|
+
defaultValue?: Expression | unknown;
|
173
173
|
/**
|
174
174
|
* An expression that should be evaluated to form the value of the field. The
|
175
175
|
* expression can either be VIRTUAL (evaluated whenever a record is read) or STORED
|
package/dist/index.js
CHANGED
@@ -350,6 +350,16 @@ var handleIncluding = (models, model, statementParams, single, instruction) => {
|
|
350
350
|
if (single && !subSingle) {
|
351
351
|
tableSubQuery = `SELECT * FROM "${model.table}" LIMIT 1`;
|
352
352
|
}
|
353
|
+
if (modifiableQueryInstructions?.including) {
|
354
|
+
const subIncluding = handleIncluding(
|
355
|
+
models,
|
356
|
+
{ ...relatedModel, tableAlias },
|
357
|
+
statementParams,
|
358
|
+
subSingle,
|
359
|
+
modifiableQueryInstructions.including
|
360
|
+
);
|
361
|
+
statement += ` ${subIncluding.statement}`;
|
362
|
+
}
|
353
363
|
}
|
354
364
|
return { statement, tableSubQuery };
|
355
365
|
};
|
@@ -391,93 +401,95 @@ var handleOrderedBy = (model, instruction) => {
|
|
391
401
|
};
|
392
402
|
|
393
403
|
// src/instructions/selecting.ts
|
394
|
-
var handleSelecting = (models, model, statementParams, single, instructions, options) => {
|
395
|
-
let loadedFields = [];
|
396
|
-
let expandColumns = false;
|
397
|
-
let statement = "*";
|
404
|
+
var handleSelecting = (models, model, statementParams, single, instructions, options = {}) => {
|
398
405
|
let isJoining = false;
|
406
|
+
const selectedFields = (instructions.selecting ? instructions.selecting.map((slug) => {
|
407
|
+
const { field } = getFieldFromModel(model, slug, {
|
408
|
+
instructionName: "selecting"
|
409
|
+
});
|
410
|
+
return field;
|
411
|
+
}) : model.fields).filter((field) => !(field.type === "link" && field.kind === "many")).map((field) => {
|
412
|
+
const newField = { ...field, mountingPath: field.slug };
|
413
|
+
if (options.mountingPath) {
|
414
|
+
newField.mountingPath = `${options.mountingPath}.${field.slug}`;
|
415
|
+
}
|
416
|
+
return newField;
|
417
|
+
});
|
418
|
+
if (instructions.selecting) options.expandColumns = true;
|
419
|
+
const joinedSelectedFields = [];
|
420
|
+
const joinedColumns = [];
|
399
421
|
if (instructions.including) {
|
422
|
+
const symbol = getSymbol(instructions.including);
|
423
|
+
if (symbol?.type === "query") {
|
424
|
+
instructions.including.ronin_root = { ...instructions.including };
|
425
|
+
delete instructions.including[QUERY_SYMBOLS.QUERY];
|
426
|
+
}
|
400
427
|
const flatObject = flatten(instructions.including);
|
401
|
-
instructions.including = {};
|
402
428
|
for (const [key, value] of Object.entries(flatObject)) {
|
403
|
-
const
|
404
|
-
if (
|
405
|
-
const { queryModel, queryInstructions } = splitQuery(
|
429
|
+
const symbol2 = getSymbol(value);
|
430
|
+
if (symbol2?.type === "query") {
|
431
|
+
const { queryModel, queryInstructions } = splitQuery(symbol2.value);
|
406
432
|
const subQueryModel = getModelBySlug(models, queryModel);
|
407
433
|
isJoining = true;
|
408
|
-
|
434
|
+
if (queryInstructions?.selecting) options.expandColumns = true;
|
409
435
|
const tableAlias = composeIncludedTableAlias(key);
|
410
436
|
const subSingle = queryModel !== subQueryModel.pluralSlug;
|
411
|
-
if (
|
412
|
-
model.tableAlias = `sub_${model.table}
|
413
|
-
}
|
414
|
-
const
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
437
|
+
if (!model.tableAlias)
|
438
|
+
model.tableAlias = single && !subSingle ? `sub_${model.table}` : model.table;
|
439
|
+
const subMountingPath = key === "ronin_root" ? options.mountingPath : `${options?.mountingPath ? `${options?.mountingPath}.` : ""}${subSingle ? key : `${key}[0]`}`;
|
440
|
+
const { columns: nestedColumns, selectedFields: nestedSelectedFields } = handleSelecting(
|
441
|
+
models,
|
442
|
+
{ ...subQueryModel, tableAlias },
|
443
|
+
statementParams,
|
444
|
+
subSingle,
|
445
|
+
{
|
446
|
+
selecting: queryInstructions?.selecting,
|
447
|
+
including: queryInstructions?.including
|
448
|
+
},
|
449
|
+
{ ...options, mountingPath: subMountingPath }
|
421
450
|
);
|
422
|
-
|
423
|
-
|
424
|
-
...field,
|
425
|
-
parentField: {
|
426
|
-
slug: key,
|
427
|
-
single: subSingle
|
428
|
-
}
|
429
|
-
});
|
430
|
-
if (expandColumns) {
|
431
|
-
const newValue2 = parseFieldExpression(
|
432
|
-
{ ...subQueryModel, tableAlias },
|
433
|
-
"including",
|
434
|
-
`${QUERY_SYMBOLS.FIELD}${field.slug}`
|
435
|
-
);
|
436
|
-
instructions.including[`${tableAlias}.${field.slug}`] = newValue2;
|
437
|
-
}
|
438
|
-
}
|
451
|
+
if (nestedColumns !== "*") joinedColumns.push(nestedColumns);
|
452
|
+
joinedSelectedFields.push(...nestedSelectedFields);
|
439
453
|
continue;
|
440
454
|
}
|
441
|
-
let
|
442
|
-
if (
|
443
|
-
|
455
|
+
let mountedValue = value;
|
456
|
+
if (symbol2?.type === "expression") {
|
457
|
+
mountedValue = `(${parseFieldExpression(model, "including", symbol2.value)})`;
|
444
458
|
} else {
|
445
|
-
|
459
|
+
mountedValue = prepareStatementValue(statementParams, value);
|
446
460
|
}
|
447
|
-
|
448
|
-
loadedFields.push({
|
461
|
+
selectedFields.push({
|
449
462
|
slug: key,
|
450
|
-
|
463
|
+
mountingPath: key,
|
464
|
+
type: RAW_FIELD_TYPES.includes(typeof value) ? typeof value : "string",
|
465
|
+
mountedValue
|
451
466
|
});
|
452
467
|
}
|
453
468
|
}
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
statement += Object.entries(instructions.including).map(([key, value]) => `${value} as "${key}"`).join(", ");
|
479
|
-
}
|
480
|
-
return { columns: statement, isJoining, loadedFields };
|
469
|
+
let columns = ["*"];
|
470
|
+
const fieldsToExpand = options.expandColumns ? selectedFields : selectedFields.filter(
|
471
|
+
(loadedField) => typeof loadedField.mountedValue !== "undefined"
|
472
|
+
);
|
473
|
+
const extraColumns = fieldsToExpand.map((selectedField) => {
|
474
|
+
if (selectedField.mountedValue) {
|
475
|
+
return `${selectedField.mountedValue} as "${selectedField.slug}"`;
|
476
|
+
}
|
477
|
+
const { fieldSelector } = getFieldFromModel(model, selectedField.slug, {
|
478
|
+
instructionName: "selecting"
|
479
|
+
});
|
480
|
+
if (options.mountingPath) {
|
481
|
+
return `${fieldSelector} as "${options.mountingPath}.${selectedField.slug}"`;
|
482
|
+
}
|
483
|
+
return fieldSelector;
|
484
|
+
});
|
485
|
+
if (options.expandColumns) {
|
486
|
+
columns = extraColumns;
|
487
|
+
} else if (extraColumns) {
|
488
|
+
columns.push(...extraColumns);
|
489
|
+
}
|
490
|
+
columns.push(...joinedColumns);
|
491
|
+
selectedFields.push(...joinedSelectedFields);
|
492
|
+
return { columns: columns.join(", "), isJoining, selectedFields };
|
481
493
|
};
|
482
494
|
|
483
495
|
// src/instructions/to.ts
|
@@ -599,7 +611,7 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
599
611
|
defaultQuery
|
600
612
|
);
|
601
613
|
if (query === null)
|
602
|
-
return { dependencies: [], main: dependencyStatements[0],
|
614
|
+
return { dependencies: [], main: dependencyStatements[0], selectedFields: [] };
|
603
615
|
const parsedQuery = splitQuery(query);
|
604
616
|
const { queryType, queryModel, queryInstructions } = parsedQuery;
|
605
617
|
const model = getModelBySlug(models, queryModel);
|
@@ -609,7 +621,7 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
609
621
|
if (instructions && Object.hasOwn(instructions, "for")) {
|
610
622
|
instructions = handleFor(model, instructions);
|
611
623
|
}
|
612
|
-
const { columns, isJoining,
|
624
|
+
const { columns, isJoining, selectedFields } = handleSelecting(
|
613
625
|
models,
|
614
626
|
model,
|
615
627
|
statementParams,
|
@@ -741,7 +753,7 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
|
741
753
|
return {
|
742
754
|
dependencies: dependencyStatements,
|
743
755
|
main: mainStatement,
|
744
|
-
|
756
|
+
selectedFields
|
745
757
|
};
|
746
758
|
};
|
747
759
|
|
@@ -1215,15 +1227,59 @@ var addDefaultModelPresets = (list, model) => {
|
|
1215
1227
|
const defaultPresets = [];
|
1216
1228
|
for (const field of model.fields || []) {
|
1217
1229
|
if (field.type === "link" && !field.slug.startsWith("ronin.")) {
|
1218
|
-
const
|
1219
|
-
if (field.kind === "many")
|
1230
|
+
const targetModel = getModelBySlug(list, field.target);
|
1231
|
+
if (field.kind === "many") {
|
1232
|
+
const systemModel = list.find(({ system }) => {
|
1233
|
+
return system?.model === model.id && system?.associationSlug === field.slug;
|
1234
|
+
});
|
1235
|
+
if (!systemModel) continue;
|
1236
|
+
const preset = {
|
1237
|
+
instructions: {
|
1238
|
+
// Perform a LEFT JOIN that adds the associative table.
|
1239
|
+
including: {
|
1240
|
+
[field.slug]: {
|
1241
|
+
[QUERY_SYMBOLS.QUERY]: {
|
1242
|
+
get: {
|
1243
|
+
[systemModel.pluralSlug]: {
|
1244
|
+
// ON associative_table.source = origin_model.id
|
1245
|
+
with: {
|
1246
|
+
source: {
|
1247
|
+
[QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}id`
|
1248
|
+
}
|
1249
|
+
},
|
1250
|
+
// Perform a LEFT JOIN that adds the target model table.
|
1251
|
+
including: {
|
1252
|
+
[QUERY_SYMBOLS.QUERY]: {
|
1253
|
+
get: {
|
1254
|
+
[targetModel.slug]: {
|
1255
|
+
// ON target_model.id = associative_table.target
|
1256
|
+
with: {
|
1257
|
+
id: {
|
1258
|
+
[QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD_PARENT}target`
|
1259
|
+
}
|
1260
|
+
}
|
1261
|
+
}
|
1262
|
+
}
|
1263
|
+
}
|
1264
|
+
}
|
1265
|
+
}
|
1266
|
+
}
|
1267
|
+
}
|
1268
|
+
}
|
1269
|
+
}
|
1270
|
+
},
|
1271
|
+
slug: field.slug
|
1272
|
+
};
|
1273
|
+
defaultPresets.push(preset);
|
1274
|
+
continue;
|
1275
|
+
}
|
1220
1276
|
defaultPresets.push({
|
1221
1277
|
instructions: {
|
1222
1278
|
including: {
|
1223
1279
|
[field.slug]: {
|
1224
1280
|
[QUERY_SYMBOLS.QUERY]: {
|
1225
1281
|
get: {
|
1226
|
-
[
|
1282
|
+
[targetModel.slug]: {
|
1227
1283
|
with: {
|
1228
1284
|
// Compare the `id` field of the related model to the link field on
|
1229
1285
|
// the root model (`field.slug`).
|
@@ -1242,6 +1298,7 @@ var addDefaultModelPresets = (list, model) => {
|
|
1242
1298
|
}
|
1243
1299
|
}
|
1244
1300
|
const childModels = list.map((subModel) => {
|
1301
|
+
if (subModel.system?.associationSlug) return null;
|
1245
1302
|
const field = subModel.fields?.find((field2) => {
|
1246
1303
|
return field2.type === "link" && field2.target === model.slug;
|
1247
1304
|
});
|
@@ -1299,8 +1356,10 @@ var getFieldSelector = (model, field, fieldPath, writing) => {
|
|
1299
1356
|
if (field.type === "json" && !writing) {
|
1300
1357
|
const dotParts = fieldPath.split(".");
|
1301
1358
|
const columnName = tablePrefix + dotParts.shift();
|
1302
|
-
|
1303
|
-
|
1359
|
+
if (dotParts.length > 0) {
|
1360
|
+
const jsonField = dotParts.join(".");
|
1361
|
+
return `json_extract(${columnName}, '$.${jsonField}')`;
|
1362
|
+
}
|
1304
1363
|
}
|
1305
1364
|
return `${tablePrefix}"${fieldPath}"`;
|
1306
1365
|
};
|
@@ -1901,7 +1960,7 @@ var Transaction = class {
|
|
1901
1960
|
...subStatements.map((statement) => ({
|
1902
1961
|
...statement,
|
1903
1962
|
query,
|
1904
|
-
|
1963
|
+
selectedFields: result.selectedFields
|
1905
1964
|
}))
|
1906
1965
|
);
|
1907
1966
|
}
|
@@ -1912,12 +1971,8 @@ var Transaction = class {
|
|
1912
1971
|
const records = [];
|
1913
1972
|
for (const row of rows) {
|
1914
1973
|
const record = fields.reduce((acc, field, fieldIndex) => {
|
1915
|
-
|
1974
|
+
const newSlug = field.mountingPath;
|
1916
1975
|
let newValue = row[fieldIndex];
|
1917
|
-
if (field.parentField) {
|
1918
|
-
const arrayKey = field.parentField.single ? "" : "[0]";
|
1919
|
-
newSlug = `${field.parentField.slug}${arrayKey}.${field.slug}`;
|
1920
|
-
}
|
1921
1976
|
if (field.type === "json") {
|
1922
1977
|
newValue = JSON.parse(newValue);
|
1923
1978
|
} else if (field.type === "boolean") {
|
@@ -1938,17 +1993,13 @@ var Transaction = class {
|
|
1938
1993
|
records.push(record);
|
1939
1994
|
continue;
|
1940
1995
|
}
|
1941
|
-
const joinFields = fields.reduce(
|
1942
|
-
(acc
|
1943
|
-
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
[]
|
1948
|
-
);
|
1949
|
-
for (const parentField of joinFields) {
|
1950
|
-
const currentValue = existingRecord[parentField];
|
1951
|
-
const newValue = record[parentField];
|
1996
|
+
const joinFields = fields.reduce((acc, { mountingPath }) => {
|
1997
|
+
if (mountingPath.includes("[0]")) acc.add(mountingPath.split("[0]")[0]);
|
1998
|
+
return acc;
|
1999
|
+
}, /* @__PURE__ */ new Set());
|
2000
|
+
for (const arrayField of joinFields.values()) {
|
2001
|
+
const currentValue = existingRecord[arrayField];
|
2002
|
+
const newValue = record[arrayField];
|
1952
2003
|
currentValue.push(...newValue);
|
1953
2004
|
}
|
1954
2005
|
}
|
@@ -1976,11 +2027,7 @@ var Transaction = class {
|
|
1976
2027
|
});
|
1977
2028
|
const formattedResults = normalizedResults.map(
|
1978
2029
|
(rows, index) => {
|
1979
|
-
const {
|
1980
|
-
returning,
|
1981
|
-
query,
|
1982
|
-
fields: rawModelFields
|
1983
|
-
} = this.#internalStatements[index];
|
2030
|
+
const { returning, query, selectedFields } = this.#internalStatements[index];
|
1984
2031
|
if (!returning) return null;
|
1985
2032
|
const { queryType, queryModel, queryInstructions } = splitQuery(query);
|
1986
2033
|
const model = getModelBySlug(this.models, queryModel);
|
@@ -1994,13 +2041,13 @@ var Transaction = class {
|
|
1994
2041
|
const single = queryModel !== model.pluralSlug;
|
1995
2042
|
if (single) {
|
1996
2043
|
return {
|
1997
|
-
record: rows[0] ? this.#formatRows(
|
2044
|
+
record: rows[0] ? this.#formatRows(selectedFields, rows, true, isMeta) : null,
|
1998
2045
|
modelFields
|
1999
2046
|
};
|
2000
2047
|
}
|
2001
2048
|
const pageSize = queryInstructions?.limitedTo;
|
2002
2049
|
const output = {
|
2003
|
-
records: this.#formatRows(
|
2050
|
+
records: this.#formatRows(selectedFields, rows, false, isMeta),
|
2004
2051
|
modelFields
|
2005
2052
|
};
|
2006
2053
|
if (pageSize && output.records.length > 0) {
|