@ronin/compiler 0.14.9 → 0.14.10

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/README.md CHANGED
@@ -70,7 +70,7 @@ executed and their results can be formatted by the compiler as well:
70
70
 
71
71
  ```typescript
72
72
  // Passing `rawResults` (rows being arrays of values) provided by the database (ideal)
73
- const results: Array<Result> = transaction.formatResults(rawResults);
73
+ const results: Array<Result> = transaction.formatResults(rawResults, true);
74
74
 
75
75
  // Passing `objectResults` (rows being objects) provided by a driver
76
76
  const results: Array<Result> = transaction.formatResults(objectResults, false);
@@ -127,26 +127,7 @@ new Transaction(queries, {
127
127
  // Instead of returning an array of parameters for every statement (which allows for
128
128
  // preventing SQL injections), all parameters are inlined directly into the SQL strings.
129
129
  // This option should only be used if the generated SQL will be manually verified.
130
- inlineParams: true,
131
-
132
- // By default, in the generated SQL statements, the compiler does not alias columns if
133
- // multiple different tables with the same column names are being joined. Only the table
134
- // names themselves are aliased.
135
- //
136
- // This ensures the cleanest possible SQL statements in conjunction with the default
137
- // behavior of SQL databases, where the result of a statement is a list (array) of
138
- // values, which are inherently not prone to conflicts.
139
- //
140
- // If the driver being used instead returns an object for every row, the driver must
141
- // ensure the uniqueness of every key in that object, which means prefixing duplicated
142
- // column names with the name of the respective table, if multiple tables are joined
143
- // (example for an object key: "table_name.column_name").
144
- //
145
- // Drivers that return objects for rows offer this behavior as an option that is
146
- // usually called "expand columns". If the driver being used does not offer such an
147
- // option, you can instead activate the option in the compiler, which results in longer
148
- // SQL statements because all column names are aliased.
149
- expandColumns: true
130
+ inlineParams: true
150
131
  });
151
132
  ```
152
133
 
package/dist/index.d.ts CHANGED
@@ -394,8 +394,6 @@ interface TransactionOptions {
394
394
  * separating them out into a dedicated `params` array.
395
395
  */
396
396
  inlineParams?: boolean;
397
- /** Alias column names that are duplicated when joining multiple tables. */
398
- expandColumns?: boolean;
399
397
  }
400
398
  declare class Transaction {
401
399
  #private;
package/dist/index.js CHANGED
@@ -25,12 +25,13 @@ var CURRENT_TIME_EXPRESSION = {
25
25
  };
26
26
  var MOUNTING_PATH_SUFFIX = /(.*?)(\{(\d+)\})?$/;
27
27
  var composeMountingPath = (single, key, mountingPath) => {
28
- const subMountingPath = key === "ronin_root" ? mountingPath ? mountingPath.replace(
29
- MOUNTING_PATH_SUFFIX,
30
- (_, p, __, n) => `${p}{${n ? +n + 1 : 1}}`
31
- ) : void 0 : `${mountingPath ? `${mountingPath}.` : ""}${single ? key : `${key}[0]`}`;
32
- const tableAlias = `including_${subMountingPath || key}`;
33
- return { subMountingPath, tableAlias };
28
+ if (key === "ronin_root") {
29
+ return mountingPath ? mountingPath.replace(
30
+ MOUNTING_PATH_SUFFIX,
31
+ (_, p, __, n) => `${p}{${n ? +n + 1 : 1}}`
32
+ ) : key;
33
+ }
34
+ return `${mountingPath ? `${mountingPath}.` : ""}${single ? key : `${key}[0]`}`;
34
35
  };
35
36
  var MODEL_ENTITY_ERROR_CODES = {
36
37
  field: "FIELD_NOT_FOUND",
@@ -318,11 +319,12 @@ var handleIncluding = (models, model, statementParams, single, instruction, opti
318
319
  let joinType = "LEFT";
319
320
  let relatedTableSelector = `"${relatedModel.table}"`;
320
321
  const subSingle = queryModel !== relatedModel.pluralSlug;
321
- const { tableAlias, subMountingPath } = composeMountingPath(
322
+ const subMountingPath = composeMountingPath(
322
323
  subSingle,
323
324
  ephemeralFieldSlug,
324
325
  options.mountingPath
325
326
  );
327
+ const tableAlias = `including_${subMountingPath}`;
326
328
  if (!modifiableQueryInstructions?.with) {
327
329
  joinType = "CROSS";
328
330
  if (subSingle) {
@@ -419,12 +421,11 @@ var handleSelecting = (models, model, statementParams, single, instructions, opt
419
421
  instructions.selecting
420
422
  ).filter((field) => !(field.type === "link" && field.kind === "many")).map((field) => {
421
423
  const newField = { ...field, mountingPath: field.slug };
422
- if (options.mountingPath) {
424
+ if (options.mountingPath && options.mountingPath !== "ronin_root") {
423
425
  newField.mountingPath = `${options.mountingPath.replace(/\{\d+\}/g, "")}.${field.slug}`;
424
426
  }
425
427
  return newField;
426
428
  });
427
- if (instructions.selecting) options.expandColumns = true;
428
429
  const joinedSelectedFields = [];
429
430
  const joinedColumns = [];
430
431
  if (instructions.including) {
@@ -440,18 +441,13 @@ var handleSelecting = (models, model, statementParams, single, instructions, opt
440
441
  const { queryModel, queryInstructions } = splitQuery(symbol2.value);
441
442
  const subQueryModel = getModelBySlug(models, queryModel);
442
443
  isJoining = true;
443
- if (queryInstructions?.selecting) options.expandColumns = true;
444
444
  const subSingle = queryModel !== subQueryModel.pluralSlug;
445
445
  if (!model.tableAlias)
446
446
  model.tableAlias = single && !subSingle ? `sub_${model.table}` : model.table;
447
- const { tableAlias, subMountingPath } = composeMountingPath(
448
- subSingle,
449
- key,
450
- options.mountingPath
451
- );
447
+ const subMountingPath = composeMountingPath(subSingle, key, options.mountingPath);
452
448
  const { columns: nestedColumns, selectedFields: nestedSelectedFields } = handleSelecting(
453
449
  models,
454
- { ...subQueryModel, tableAlias },
450
+ { ...subQueryModel, tableAlias: `including_${subMountingPath}` },
455
451
  statementParams,
456
452
  subSingle,
457
453
  {
@@ -478,11 +474,7 @@ var handleSelecting = (models, model, statementParams, single, instructions, opt
478
474
  });
479
475
  }
480
476
  }
481
- let columns = ["*"];
482
- const fieldsToExpand = options.expandColumns ? selectedFields : selectedFields.filter(
483
- (loadedField) => typeof loadedField.mountedValue !== "undefined"
484
- );
485
- const extraColumns = fieldsToExpand.map((selectedField) => {
477
+ const columns = selectedFields.map((selectedField) => {
486
478
  if (selectedField.mountedValue) {
487
479
  return `${selectedField.mountedValue} as "${selectedField.slug}"`;
488
480
  }
@@ -494,11 +486,6 @@ var handleSelecting = (models, model, statementParams, single, instructions, opt
494
486
  }
495
487
  return fieldSelector;
496
488
  });
497
- if (options.expandColumns) {
498
- columns = extraColumns;
499
- } else if (extraColumns) {
500
- columns.push(...extraColumns);
501
- }
502
489
  columns.push(...joinedColumns);
503
490
  selectedFields.push(...joinedSelectedFields);
504
491
  return { columns: columns.join(", "), isJoining, selectedFields };
@@ -631,6 +618,15 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
631
618
  if (instructions && Object.hasOwn(instructions, "for")) {
632
619
  instructions = handleFor(model, instructions);
633
620
  }
621
+ if (queryType === "count") {
622
+ if (!instructions) instructions = {};
623
+ instructions.selecting = ["amount"];
624
+ instructions.including = Object.assign(instructions?.including || {}, {
625
+ amount: {
626
+ [QUERY_SYMBOLS.EXPRESSION]: "COUNT(*)"
627
+ }
628
+ });
629
+ }
634
630
  const { columns, isJoining, selectedFields } = handleSelecting(
635
631
  models,
636
632
  model,
@@ -639,12 +635,12 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
639
635
  {
640
636
  selecting: instructions?.selecting,
641
637
  including: instructions?.including
642
- },
643
- options
638
+ }
644
639
  );
645
640
  let statement = "";
646
641
  switch (queryType) {
647
642
  case "get":
643
+ case "count":
648
644
  statement += `SELECT ${columns} FROM `;
649
645
  break;
650
646
  case "set":
@@ -656,9 +652,6 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
656
652
  case "remove":
657
653
  statement += "DELETE FROM ";
658
654
  break;
659
- case "count":
660
- statement += `SELECT COUNT(${columns}) FROM `;
661
- break;
662
655
  }
663
656
  let isJoiningMultipleRows = false;
664
657
  if (isJoining) {
@@ -753,7 +746,7 @@ var compileQueryInput = (defaultQuery, models, statementParams, options) => {
753
746
  statement += handleLimitedTo(single, instructions?.limitedTo);
754
747
  }
755
748
  if (["add", "set", "remove"].includes(queryType) && returning) {
756
- statement += "RETURNING * ";
749
+ statement += `RETURNING ${columns}`;
757
750
  }
758
751
  const mainStatement = {
759
752
  statement: statement.trimEnd(),
@@ -1390,13 +1383,9 @@ var composeAssociationModelSlug = (model, field) => convertToCamelCase(`ronin_li
1390
1383
  var getFieldSelector = (model, field, fieldPath, writing) => {
1391
1384
  const symbol = model.tableAlias?.startsWith(QUERY_SYMBOLS.FIELD_PARENT) ? `${model.tableAlias.replace(QUERY_SYMBOLS.FIELD_PARENT, "").slice(0, -1)}.` : "";
1392
1385
  const tablePrefix = symbol || (model.tableAlias ? `"${model.tableAlias}".` : "");
1393
- if ((field.type === "json" || field.type === "blob") && !writing) {
1394
- const dotParts = fieldPath.split(".");
1395
- const columnName = tablePrefix + dotParts.shift();
1396
- if (dotParts.length > 0) {
1397
- const jsonField = dotParts.join(".");
1398
- return `json_extract(${columnName}, '$.${jsonField}')`;
1399
- }
1386
+ if ((field.type === "json" || field.type === "blob") && !writing && fieldPath.length > field.slug.length) {
1387
+ const jsonField = fieldPath.replace(`${field.slug}.`, "");
1388
+ return `json_extract(${tablePrefix + field.slug}, '$.${jsonField}')`;
1400
1389
  }
1401
1390
  return `${tablePrefix}"${fieldPath}"`;
1402
1391
  };
@@ -1988,8 +1977,7 @@ var Transaction = class {
1988
1977
  const { dependencies, main, selectedFields } = compileQueryInput(
1989
1978
  query,
1990
1979
  modelsWithPresets,
1991
- options?.inlineParams ? null : [],
1992
- { expandColumns: options?.expandColumns }
1980
+ options?.inlineParams ? null : []
1993
1981
  );
1994
1982
  const preDependencies = dependencies.filter(({ after }) => !after);
1995
1983
  const postDependencies = dependencies.map(({ after, ...rest }) => after ? rest : null).filter((item) => item != null);
@@ -2083,18 +2071,19 @@ var Transaction = class {
2083
2071
  *
2084
2072
  * @param results - A list of results from the database, where each result is an array
2085
2073
  * of rows.
2086
- * @param raw - By default, rows are expected to be arrays of values, which is how SQL
2087
- * databases return rows by default. If the driver being used returns rows as objects
2088
- * instead, this option should be set to `false`.
2074
+ * @param raw - By default, rows are expected to be objects. If the driver being used
2075
+ * returns rows as arrays of values (which is how SQL databases return rows directly),
2076
+ * this option should be set to `true`.
2089
2077
  *
2090
2078
  * @returns A list of formatted RONIN results, where each result is either a single
2091
2079
  * RONIN record, an array of RONIN records, or a RONIN count result.
2092
2080
  */
2093
- formatResults(results, raw = true) {
2094
- const normalizedResults = raw ? results : results.map((rows) => {
2081
+ formatResults(results, raw = false) {
2082
+ const normalizedResults = raw ? results : results.map((rows, index) => {
2083
+ const { query } = this.#internalStatements[index];
2095
2084
  return rows.map((row) => {
2096
2085
  if (Array.isArray(row)) return row;
2097
- if (row["COUNT(*)"]) return [row["COUNT(*)"]];
2086
+ if (query.count) return [row.amount];
2098
2087
  return Object.values(row);
2099
2088
  });
2100
2089
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.14.9",
3
+ "version": "0.14.10",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {