velocious 1.0.673 → 1.0.675

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.
Files changed (32) hide show
  1. package/README.md +2 -0
  2. package/build/database/query/model-class-query.js +25 -2
  3. package/build/database/query/order-base.js +9 -0
  4. package/build/database/query/order-column.js +10 -0
  5. package/build/database/query/order-plain.js +16 -0
  6. package/build/frontend-model-controller.js +10 -2
  7. package/build/frontend-model-resource/base-resource.js +21 -2
  8. package/build/src/database/query/model-class-query.d.ts +10 -0
  9. package/build/src/database/query/model-class-query.d.ts.map +1 -1
  10. package/build/src/database/query/model-class-query.js +24 -3
  11. package/build/src/database/query/order-base.d.ts +6 -0
  12. package/build/src/database/query/order-base.d.ts.map +1 -1
  13. package/build/src/database/query/order-base.js +9 -1
  14. package/build/src/database/query/order-column.d.ts +5 -0
  15. package/build/src/database/query/order-column.d.ts.map +1 -1
  16. package/build/src/database/query/order-column.js +9 -1
  17. package/build/src/database/query/order-plain.d.ts +5 -0
  18. package/build/src/database/query/order-plain.d.ts.map +1 -1
  19. package/build/src/database/query/order-plain.js +14 -1
  20. package/build/src/frontend-model-controller.d.ts +5 -0
  21. package/build/src/frontend-model-controller.d.ts.map +1 -1
  22. package/build/src/frontend-model-controller.js +10 -3
  23. package/build/src/frontend-model-resource/base-resource.d.ts +10 -0
  24. package/build/src/frontend-model-resource/base-resource.d.ts.map +1 -1
  25. package/build/src/frontend-model-resource/base-resource.js +19 -3
  26. package/package.json +1 -1
  27. package/src/database/query/model-class-query.js +25 -2
  28. package/src/database/query/order-base.js +9 -0
  29. package/src/database/query/order-column.js +10 -0
  30. package/src/database/query/order-plain.js +16 -0
  31. package/src/frontend-model-controller.js +10 -2
  32. package/src/frontend-model-resource/base-resource.js +21 -2
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.673",
6
+ "version": "1.0.675",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -940,10 +940,17 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
940
940
 
941
941
  /**
942
942
  * Runs first.
943
+ *
944
+ * An explicitly set order is preserved; the deterministic identity order is
945
+ * only applied as a fallback when no order was set, so `LIMIT 1` never
946
+ * returns an arbitrary row.
943
947
  * @returns {Promise<InstanceType<MC> | null>} - Resolves with the first.
944
948
  */
945
949
  async first() {
946
- const newQuery = this.clone().limit(1).reorder(this._defaultIdentityOrder("ASC"))
950
+ const newQuery = this.clone().limit(1)
951
+
952
+ if (newQuery.getOrders().length == 0) newQuery.reorder(this._defaultIdentityOrder("ASC"))
953
+
947
954
  const results = await newQuery.toArray()
948
955
 
949
956
  return results[0] || null
@@ -951,10 +958,26 @@ export default class VelociousDatabaseQueryModelClassQuery extends DatabaseQuery
951
958
 
952
959
  /**
953
960
  * Runs last.
961
+ *
962
+ * An explicitly set order is preserved and read from its end; the
963
+ * deterministic identity order is only applied as a fallback when no order
964
+ * was set. The clone shares its order instances with the source query, so
965
+ * the explicit orders are replaced by independent reversed copies instead
966
+ * of mutating the shared ones.
954
967
  * @returns {Promise<InstanceType<MC> | null>} - Resolves with the last.
955
968
  */
956
969
  async last() {
957
- const results = await this.clone().reorder(this._defaultIdentityOrder("DESC")).limit(1).toArray()
970
+ const newQuery = this.clone().limit(1)
971
+
972
+ if (newQuery.getOrders().length == 0) {
973
+ newQuery.reorder(this._defaultIdentityOrder("DESC"))
974
+ } else {
975
+ const orders = newQuery.getOrders()
976
+
977
+ for (let i = 0; i < orders.length; i += 1) orders[i] = orders[i].reversedCopy()
978
+ }
979
+
980
+ const results = await newQuery.toArray()
958
981
 
959
982
  return results[0] || null
960
983
  }
@@ -27,6 +27,15 @@ export default class VelociousDatabaseQueryOrderBase {
27
27
  throw new Error("setReverseOrder not implemented")
28
28
  }
29
29
 
30
+ /**
31
+ * Runs reversed copy.
32
+ * @abstract
33
+ * @returns {import("./order-base.js").default} - A new independent order with the direction reversed.
34
+ */
35
+ reversedCopy() {
36
+ throw new Error("reversedCopy not implemented")
37
+ }
38
+
30
39
  toSql() {
31
40
  throw new Error("'toSql' wasn't implemented")
32
41
  }
@@ -59,6 +59,16 @@ export default class VelociousDatabaseQueryOrderColumn extends OrderBase {
59
59
  this.reverseOrder = reverseOrder
60
60
  }
61
61
 
62
+ /**
63
+ * Runs reversed copy.
64
+ * @returns {VelociousDatabaseQueryOrderColumn} - A new independent order reversing the effective (rendered) direction.
65
+ */
66
+ reversedCopy() {
67
+ const direction = this.reverseOrder ? this.direction : reverseDirection(this.direction)
68
+
69
+ return new VelociousDatabaseQueryOrderColumn(this.query, {column: this.column, direction, tableName: this.tableName})
70
+ }
71
+
62
72
  /**
63
73
  * Runs to sql.
64
74
  * @returns {string} - SQL string.
@@ -18,6 +18,22 @@ export default class VelociousDatabaseQueryOrderPlain extends OrderBase {
18
18
  this.reverseOrder = true
19
19
  }
20
20
 
21
+ /**
22
+ * Runs reversed copy.
23
+ * @returns {VelociousDatabaseQueryOrderPlain} - A new independent order reversing the effective (rendered) direction; a directionless plain order renders DESC.
24
+ */
25
+ reversedCopy() {
26
+ const effective = this.reverseOrder ? `${this.plain} DESC` : this.plain
27
+ const match = effective.match(/^(.*\S)\s+(ASC|DESC)$/i)
28
+
29
+ if (match) {
30
+ const direction = match[2].toUpperCase() == "ASC" ? "DESC" : "ASC"
31
+ return new VelociousDatabaseQueryOrderPlain(this.query, `${match[1]} ${direction}`)
32
+ }
33
+
34
+ return new VelociousDatabaseQueryOrderPlain(this.query, `${effective} DESC`)
35
+ }
36
+
21
37
  toSql() {
22
38
  if (this.reverseOrder) {
23
39
  return `${this.plain} DESC`
@@ -1060,6 +1060,14 @@ export default class FrontendModelController extends Controller {
1060
1060
  return this.frontendModelResourceInstance().primaryKey()
1061
1061
  }
1062
1062
 
1063
+ /**
1064
+ * Runs frontend model database primary key.
1065
+ * @returns {import("./utils/model-primary-key.js").ModelPrimaryKeyDefinition} - Primary key resolved to database-queryable attribute names.
1066
+ */
1067
+ frontendModelDatabasePrimaryKey() {
1068
+ return this.frontendModelResourceInstance().databasePrimaryKey()
1069
+ }
1070
+
1063
1071
  /**
1064
1072
  * Runs frontend model ability action.
1065
1073
  * @param {"index" | "find" | "create" | "update" | "destroy" | "attach" | "attachmentList" | "download" | "url"} action - Frontend action.
@@ -1138,7 +1146,7 @@ export default class FrontendModelController extends Controller {
1138
1146
  * @returns {import("./utils/model-primary-key.js").ModelPrimaryKeyValue} - Primary key value.
1139
1147
  */
1140
1148
  frontendModelPrimaryKeyValue(model) {
1141
- const primaryKey = this.frontendModelPrimaryKey()
1149
+ const primaryKey = this.frontendModelDatabasePrimaryKey()
1142
1150
 
1143
1151
  return readModelPrimaryKeyValue(primaryKey, (attributeName) => model.readAttribute(attributeName))
1144
1152
  }
@@ -1194,7 +1202,7 @@ export default class FrontendModelController extends Controller {
1194
1202
  async frontendModelFilterAuthorizedModels({action, models}) {
1195
1203
  if (models.length === 0) return models
1196
1204
 
1197
- const primaryKey = this.frontendModelPrimaryKey()
1205
+ const primaryKey = this.frontendModelDatabasePrimaryKey()
1198
1206
 
1199
1207
  const identities = models.map((model) => this.frontendModelPrimaryKeyValue(model))
1200
1208
  const authorizedIds = await this.frontendModelAuthorizedIdentitySet({
@@ -699,7 +699,7 @@ export default class FrontendModelBaseResource extends AuthorizationBaseResource
699
699
  ? ModelClass.accessibleFor(this.syncAbilityAction(forDelete ? "destroy" : "update"), ability)
700
700
  : ModelClass.where({})
701
701
 
702
- return await query.findBy(modelPrimaryKeyConditions(this.primaryKey(), mutation.resourceId))
702
+ return await query.findBy(modelPrimaryKeyConditions(this.databasePrimaryKey(), mutation.resourceId))
703
703
  }
704
704
 
705
705
  /**
@@ -894,6 +894,25 @@ export default class FrontendModelBaseResource extends AuthorizationBaseResource
894
894
  return ResourceClass.resolvedPrimaryKey(this.resourceConfiguration())
895
895
  }
896
896
 
897
+ /**
898
+ * Runs database primary key.
899
+ *
900
+ * Declared scalar resource primary keys are client-facing aliases (for example
901
+ * a camelCase name for a legacy raw-column primary key). Database-facing identity
902
+ * operations must resolve the alias to the model's canonical attribute so where
903
+ * and pluck clauses hit real columns, while client-facing payloads keep the alias.
904
+ * @returns {import("../utils/model-primary-key.js").ModelPrimaryKeyDefinition} - Primary key resolved to database-queryable attribute names.
905
+ */
906
+ databasePrimaryKey() {
907
+ const primaryKey = this.primaryKey()
908
+
909
+ if (Array.isArray(primaryKey)) return primaryKey
910
+
911
+ const modelClass = this.databaseModelClass()
912
+
913
+ return modelClass.resolveAttributeName(primaryKey) || primaryKey
914
+ }
915
+
897
916
  /**
898
917
  * Runs authorized query.
899
918
  * @param {FrontendModelResourceAction} action - Ability action.
@@ -1027,7 +1046,7 @@ export default class FrontendModelBaseResource extends AuthorizationBaseResource
1027
1046
  query = query.preload(preload)
1028
1047
  }
1029
1048
 
1030
- return await query.findBy(modelPrimaryKeyConditions(this.primaryKey(), id))
1049
+ return await query.findBy(modelPrimaryKeyConditions(this.databasePrimaryKey(), id))
1031
1050
  }
1032
1051
 
1033
1052
  /**