@restura/core 1.3.0 → 1.4.0

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 CHANGED
@@ -1116,6 +1116,16 @@ declare class PsqlEngine extends SqlEngine {
1116
1116
  protected createNestedSelect(req: RsRequest<unknown>, schema: ResturaSchema, item: ResponseData, routeData: StandardRouteData, sqlParams: string[]): string;
1117
1117
  protected executeCreateRequest(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<DynamicObject>;
1118
1118
  protected executeGetRequest(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<DynamicObject | any[]>;
1119
+ /**
1120
+ * Executes an update request. The request will pull out the id and baseSyncVersion from the request body.
1121
+ * (If Present) The baseSyncVersion is used to check if the record has been modified since the last sync.
1122
+ * If the update fails because the baseSyncVersion has changed, a conflict error will be thrown.
1123
+ * IDs can not be updated using this method.
1124
+ * @param req - The request object.
1125
+ * @param routeData - The route data object.
1126
+ * @param schema - The schema object.
1127
+ * @returns The response object.
1128
+ */
1119
1129
  protected executeUpdateRequest(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<DynamicObject>;
1120
1130
  protected executeDeleteRequest(req: RsRequest<unknown>, routeData: StandardRouteData, schema: ResturaSchema): Promise<boolean>;
1121
1131
  protected generateJoinStatements(req: RsRequest<unknown>, joins: JoinData[], baseTable: string, routeData: StandardRouteData | CustomRouteData, schema: ResturaSchema, sqlParams: string[]): string;
@@ -1171,9 +1181,10 @@ declare function insertObjectQuery(table: string, obj: DynamicObject): string;
1171
1181
  * @param table Table name to update the object in
1172
1182
  * @param obj Data to update in the table
1173
1183
  * @param whereStatement Where clause to determine which rows to update
1184
+ * @param incrementSyncVersion Whether to increment the syncVersion column
1174
1185
  * @returns the query to update the object in the table
1175
1186
  */
1176
- declare function updateObjectQuery(table: string, obj: DynamicObject, whereStatement: string): string;
1187
+ declare function updateObjectQuery(table: string, obj: DynamicObject, whereStatement: string, incrementSyncVersion?: boolean): string;
1177
1188
  declare function isValueNumber(value: unknown): value is number;
1178
1189
  /**
1179
1190
  * This method is used to format a query and escape user input.
package/dist/index.js CHANGED
@@ -1791,15 +1791,18 @@ INSERT INTO "${table}" (${columns})
1791
1791
  query = query.replace(/'(\?)'/, "?");
1792
1792
  return query;
1793
1793
  }
1794
- function updateObjectQuery(table, obj, whereStatement) {
1794
+ function updateObjectQuery(table, obj, whereStatement, incrementSyncVersion = false) {
1795
1795
  const setArray = [];
1796
1796
  for (const i in obj) {
1797
1797
  setArray.push(`${escapeColumnName(i)} = ` + SQL`${obj[i]}`);
1798
1798
  }
1799
+ if (incrementSyncVersion) {
1800
+ setArray.push(`"syncVersion" = "syncVersion" + 1`);
1801
+ }
1799
1802
  return `
1800
- UPDATE ${escapeColumnName(table)}
1801
- SET ${setArray.join(", ")} ${whereStatement}
1802
- RETURNING *`;
1803
+ UPDATE ${escapeColumnName(table)}
1804
+ SET ${setArray.join(", ")} ${whereStatement}
1805
+ RETURNING *`;
1803
1806
  }
1804
1807
  function isValueNumber2(value) {
1805
1808
  return !isNaN(Number(value));
@@ -1835,9 +1838,9 @@ var PsqlConnection = class {
1835
1838
  const startTime = process.hrtime();
1836
1839
  try {
1837
1840
  const response = await this.query(queryMetadata + formattedQuery, options);
1838
- this.logSqlStatement(formattedQuery, options, meta, startTime);
1839
1841
  if (response.rows.length === 0) throw new RsError("NOT_FOUND", "No results found");
1840
1842
  else if (response.rows.length > 1) throw new RsError("DUPLICATE", "More than one result found");
1843
+ this.logSqlStatement(formattedQuery, options, meta, startTime);
1841
1844
  return response.rows[0];
1842
1845
  } catch (error) {
1843
1846
  this.logSqlStatement(formattedQuery, options, meta, startTime);
@@ -2632,9 +2635,19 @@ var PsqlEngine = class extends SqlEngine {
2632
2635
  throw new RsError("UNKNOWN_ERROR", "Unknown route type.");
2633
2636
  }
2634
2637
  }
2638
+ /**
2639
+ * Executes an update request. The request will pull out the id and baseSyncVersion from the request body.
2640
+ * (If Present) The baseSyncVersion is used to check if the record has been modified since the last sync.
2641
+ * If the update fails because the baseSyncVersion has changed, a conflict error will be thrown.
2642
+ * IDs can not be updated using this method.
2643
+ * @param req - The request object.
2644
+ * @param routeData - The route data object.
2645
+ * @param schema - The schema object.
2646
+ * @returns The response object.
2647
+ */
2635
2648
  async executeUpdateRequest(req, routeData, schema) {
2636
2649
  const sqlParams = [];
2637
- const { id, baseModifiedOn, ...bodyNoId } = req.body;
2650
+ const { id, baseSyncVersion, ...bodyNoId } = req.body;
2638
2651
  const table = schema.database.find((item) => {
2639
2652
  return item.name === routeData.table;
2640
2653
  });
@@ -2642,6 +2655,8 @@ var PsqlEngine = class extends SqlEngine {
2642
2655
  if (table.columns.find((column) => column.name === "modifiedOn")) {
2643
2656
  bodyNoId.modifiedOn = (/* @__PURE__ */ new Date()).toISOString();
2644
2657
  }
2658
+ let incrementSyncVersion = false;
2659
+ if (table.columns.find((column) => column.name === "syncVersion")) incrementSyncVersion = true;
2645
2660
  for (const assignment of routeData.assignments) {
2646
2661
  const column = table.columns.find((column2) => column2.name === assignment.name);
2647
2662
  if (!column) continue;
@@ -2653,17 +2668,16 @@ var PsqlEngine = class extends SqlEngine {
2653
2668
  let whereClause = this.generateWhereClause(req, routeData.where, routeData, sqlParams);
2654
2669
  const originalWhereClause = whereClause;
2655
2670
  const originalSqlParams = [...sqlParams];
2656
- if (baseModifiedOn) {
2657
- const replacedBaseModifiedOn = this.replaceParamKeywords(baseModifiedOn, routeData, req, sqlParams);
2658
- const modifiedOnCheck = whereClause ? `${whereClause} AND "modifiedOn" = ?` : `"modifiedOn" = ?`;
2659
- sqlParams.push(replacedBaseModifiedOn.toString());
2660
- whereClause = modifiedOnCheck;
2671
+ if (baseSyncVersion) {
2672
+ const syncVersionCheck = whereClause ? `${whereClause} AND "syncVersion" = ?` : `"syncVersion" = ?`;
2673
+ sqlParams.push(baseSyncVersion.toString());
2674
+ whereClause = syncVersionCheck;
2661
2675
  }
2662
- const query = updateObjectQuery(routeData.table, bodyNoId, whereClause);
2676
+ const query = updateObjectQuery(routeData.table, bodyNoId, whereClause, incrementSyncVersion);
2663
2677
  try {
2664
2678
  await this.psqlConnectionPool.queryOne(query, [...sqlParams], req.requesterDetails);
2665
2679
  } catch (error) {
2666
- if (!baseModifiedOn || !(error instanceof RsError) || error.err !== "NOT_FOUND") throw error;
2680
+ if (!baseSyncVersion || !(error instanceof RsError) || error.err !== "NOT_FOUND") throw error;
2667
2681
  let isConflict = false;
2668
2682
  try {
2669
2683
  await this.psqlConnectionPool.queryOne(
@@ -2677,7 +2691,7 @@ var PsqlEngine = class extends SqlEngine {
2677
2691
  if (isConflict)
2678
2692
  throw new RsError(
2679
2693
  "CONFLICT",
2680
- "The record has been modified since the baseModifiedOn value was provided."
2694
+ "The record has been modified since the baseSyncVersion value was provided."
2681
2695
  );
2682
2696
  throw error;
2683
2697
  }