@ronin/compiler 0.10.1 → 0.10.2-leo-ron-1083-experimental-212

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -103,7 +103,25 @@ new Transaction(queries, {
103
103
  // Instead of returning an array of parameters for every statement (which allows for
104
104
  // preventing SQL injections), all parameters are inlined directly into the SQL strings.
105
105
  // This option should only be used if the generated SQL will be manually verified.
106
- inlineParams: true
106
+ inlineParams: true,
107
+
108
+ // By default, in the generated SQL statements, the compiler does not alias columns if
109
+ // multiple different tables with the same column names are being joined. Only the table
110
+ // names themselves are aliased.
111
+ //
112
+ // This ensures the cleanest possible SQL statements in conjunction with the default
113
+ // behavior of SQL databases, where the result of a statement is a list (array) of
114
+ // values, which are inherently not prone to conflicts.
115
+ //
116
+ // If the driver being used instead returns an object for every row, the driver must
117
+ // ensure the uniqueness of every key in that object, which means prefixing duplicated
118
+ // column names with the name of the respective table, if multiple tables are joined.
119
+ //
120
+ // Drivers that return objects for rows offer this behavior as an option that is
121
+ // usually called "expand columns". If the driver being used does not offer such an
122
+ // option, you can instead activate the option in the compiler, which results in longer
123
+ // SQL statements because any duplicated column name is aliased.
124
+ expandColumns: true
107
125
  });
108
126
  ```
109
127
 
package/dist/index.d.ts CHANGED
@@ -6005,13 +6005,22 @@ type AmountResult = {
6005
6005
  };
6006
6006
  type Result = SingleRecordResult | MultipleRecordResult | AmountResult;
6007
6007
 
6008
+ interface TransactionOptions {
6009
+ /** A list of models that already exist in the database. */
6010
+ models?: Array<PublicModel>;
6011
+ /**
6012
+ * Place statement parameters directly inside the statement strings instead of
6013
+ * separating them out into a dedicated `params` array.
6014
+ */
6015
+ inlineParams?: boolean;
6016
+ /** Alias column names that are duplicated when joining multiple tables. */
6017
+ expandColumns?: boolean;
6018
+ }
6008
6019
  declare class Transaction {
6009
6020
  statements: Array<Statement>;
6010
6021
  models: Array<Model>;
6011
6022
  private queries;
6012
- constructor(queries: Array<Query>, options?: Parameters<typeof this.compileQueries>[2] & {
6013
- models?: Array<PublicModel>;
6014
- });
6023
+ constructor(queries: Array<Query>, options?: TransactionOptions);
6015
6024
  /**
6016
6025
  * Composes SQL statements for the provided RONIN queries.
6017
6026
  *
package/dist/index.js CHANGED
@@ -102,6 +102,9 @@ var expand = (obj) => {
102
102
  return res;
103
103
  }, {});
104
104
  };
105
+ var getProperty = (obj, path) => {
106
+ return path.split(".").reduce((acc, key) => acc?.[key], obj);
107
+ };
105
108
  var splitQuery = (query) => {
106
109
  const queryType = Object.keys(query)[0];
107
110
  const queryModel = Object.keys(query[queryType])[0];
@@ -939,9 +942,24 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
939
942
  };
940
943
  };
941
944
 
942
- // src/instructions/before-after.ts
945
+ // src/utils/pagination.ts
943
946
  var CURSOR_SEPARATOR = ",";
944
947
  var CURSOR_NULL_PLACEHOLDER = "RONIN_NULL";
948
+ var generatePaginationCursor = (model, orderedBy, record) => {
949
+ const { ascending = [], descending = [] } = orderedBy || {};
950
+ const keys = [...ascending, ...descending];
951
+ if (keys.length === 0) keys.push("ronin.createdAt");
952
+ const cursors = keys.map((fieldSlug) => {
953
+ const property = getProperty(record, fieldSlug);
954
+ if (property === null || property === void 0) return CURSOR_NULL_PLACEHOLDER;
955
+ const { field } = getFieldFromModel(model, fieldSlug, "orderedBy");
956
+ if (field.type === "date") return new Date(property).getTime();
957
+ return property;
958
+ });
959
+ return cursors.map((cursor) => encodeURIComponent(String(cursor))).join(CURSOR_SEPARATOR);
960
+ };
961
+
962
+ // src/instructions/before-after.ts
945
963
  var handleBeforeOrAfter = (model, statementParams, instructions) => {
946
964
  if (!(instructions.before || instructions.after)) {
947
965
  throw new RoninError({
@@ -1212,6 +1230,11 @@ var handleTo = (models, model, statementParams, queryType, dependencyStatements,
1212
1230
  if (symbol?.type === "query") {
1213
1231
  let { queryModel: subQueryModelSlug, queryInstructions: subQueryInstructions } = splitQuery(symbol.value);
1214
1232
  const subQueryModel = getModelBySlug(models, subQueryModelSlug);
1233
+ if (subQueryInstructions?.selecting) {
1234
+ const currentFields = new Set(subQueryInstructions.selecting);
1235
+ currentFields.add("id");
1236
+ subQueryInstructions.selecting = Array.from(currentFields);
1237
+ }
1215
1238
  const subQuerySelectedFields = subQueryInstructions?.selecting;
1216
1239
  const subQueryIncludedFields = subQueryInstructions?.including;
1217
1240
  const subQueryFields = [
@@ -1234,7 +1257,19 @@ var handleTo = (models, model, statementParams, queryType, dependencyStatements,
1234
1257
  ...subQueryInstructions.including
1235
1258
  };
1236
1259
  }
1237
- return compileQueryInput(symbol.value, models, statementParams).main.statement;
1260
+ let statement2 = "";
1261
+ if (subQuerySelectedFields) {
1262
+ const selectedFields = [
1263
+ ...subQueryFields,
1264
+ ...defaultFieldsToAdd.map(([key]) => key)
1265
+ ];
1266
+ const columns = selectedFields.map((field) => {
1267
+ return getFieldFromModel(model, field, "to").fieldSelector;
1268
+ });
1269
+ statement2 = `(${columns.join(", ")}) `;
1270
+ }
1271
+ statement2 += compileQueryInput(symbol.value, models, statementParams).main.statement;
1272
+ return statement2;
1238
1273
  }
1239
1274
  Object.assign(toInstruction, defaultFields);
1240
1275
  for (const fieldSlug in toInstruction) {
@@ -1498,11 +1533,47 @@ var Transaction = class {
1498
1533
  return expand(formattedRecord);
1499
1534
  }
1500
1535
  prepareResults(results) {
1501
- return results.map((result, index) => {
1536
+ const relevantResults = results.filter((_, index) => {
1537
+ return this.statements[index].returning;
1538
+ });
1539
+ return relevantResults.map((result, index) => {
1502
1540
  const query = this.queries.at(-index);
1503
- const { queryModel } = splitQuery(query);
1541
+ const { queryType, queryModel, queryInstructions } = splitQuery(query);
1504
1542
  const model = getModelBySlug(this.models, queryModel);
1505
- return { record: this.formatRecord(model, result[0]) };
1543
+ if (queryType === "count") {
1544
+ return { amount: result[0]["COUNT(*)"] };
1545
+ }
1546
+ const single = queryModel !== model.pluralSlug;
1547
+ if (single) {
1548
+ return { record: this.formatRecord(model, result[0]) };
1549
+ }
1550
+ const pageSize = queryInstructions?.limitedTo;
1551
+ const output = {
1552
+ records: result.map((resultItem) => {
1553
+ return this.formatRecord(model, resultItem);
1554
+ })
1555
+ };
1556
+ if (pageSize && output.records.length > 0) {
1557
+ if (queryInstructions?.before || queryInstructions?.after) {
1558
+ const direction = queryInstructions?.before ? "moreAfter" : "moreBefore";
1559
+ const firstRecord = output.records[0];
1560
+ output[direction] = generatePaginationCursor(
1561
+ model,
1562
+ queryInstructions.orderedBy,
1563
+ firstRecord
1564
+ );
1565
+ }
1566
+ if (output.records.length > pageSize) {
1567
+ const direction = queryInstructions?.before ? "moreBefore" : "moreAfter";
1568
+ const lastRecord = output.records.pop();
1569
+ output[direction] = generatePaginationCursor(
1570
+ model,
1571
+ queryInstructions.orderedBy,
1572
+ lastRecord
1573
+ );
1574
+ }
1575
+ }
1576
+ return output;
1506
1577
  });
1507
1578
  }
1508
1579
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.10.1",
3
+ "version": "0.10.2-leo-ron-1083-experimental-212",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {