@warlock.js/cascade 5.30.0 → 5.31.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -5
  3. package/cjs/index.cjs +0 -1
  4. package/cjs/index.cjs.map +1 -1
  5. package/esm/contracts/database-restorer.contract.d.mts.map +1 -1
  6. package/esm/data-source/data-source-registry.d.mts.map +1 -1
  7. package/esm/data-source/data-source-registry.mjs.map +1 -1
  8. package/esm/drivers/mongodb/mongodb-driver.d.mts.map +1 -1
  9. package/esm/drivers/mongodb/mongodb-driver.mjs.map +1 -1
  10. package/esm/drivers/mongodb/mongodb-id-generator.d.mts.map +1 -1
  11. package/esm/drivers/mongodb/mongodb-id-generator.mjs.map +1 -1
  12. package/esm/drivers/mongodb/mongodb-query-builder.d.mts.map +1 -1
  13. package/esm/drivers/mongodb/mongodb-query-builder.mjs.map +1 -1
  14. package/esm/drivers/mongodb/mongodb-query-operations.d.mts.map +1 -1
  15. package/esm/drivers/mongodb/mongodb-query-operations.mjs.map +1 -1
  16. package/esm/drivers/mongodb/mongodb-query-parser.d.mts.map +1 -1
  17. package/esm/drivers/mongodb/mongodb-query-parser.mjs.map +1 -1
  18. package/esm/drivers/postgres/naming.mjs.map +1 -1
  19. package/esm/drivers/postgres/postgres-dialect.d.mts.map +1 -1
  20. package/esm/drivers/postgres/postgres-dialect.mjs.map +1 -1
  21. package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
  22. package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
  23. package/esm/drivers/postgres/postgres-migration-driver.d.mts.map +1 -1
  24. package/esm/drivers/postgres/postgres-migration-driver.mjs.map +1 -1
  25. package/esm/drivers/postgres/postgres-query-builder.d.mts.map +1 -1
  26. package/esm/drivers/postgres/postgres-query-builder.mjs.map +1 -1
  27. package/esm/drivers/postgres/postgres-query-parser.d.mts.map +1 -1
  28. package/esm/drivers/postgres/postgres-query-parser.mjs +0 -1
  29. package/esm/drivers/postgres/postgres-query-parser.mjs.map +1 -1
  30. package/esm/drivers/postgres/postgres-sql-serializer.mjs.map +1 -1
  31. package/esm/drivers/postgres/postgres-ttl-purge.mjs.map +1 -1
  32. package/esm/drivers/postgres/types.d.mts.map +1 -1
  33. package/esm/errors/unsupported-query-operation.error.mjs.map +1 -1
  34. package/esm/expressions/column-expressions.d.mts.map +1 -1
  35. package/esm/expressions/column-expressions.mjs.map +1 -1
  36. package/esm/migration/foreign-key-builder.mjs.map +1 -1
  37. package/esm/migration/parse-created-at.mjs.map +1 -1
  38. package/esm/migration/sql-grammar.mjs.map +1 -1
  39. package/esm/model/generate-model-id.mjs.map +1 -1
  40. package/esm/model/methods/accessor-methods.mjs.map +1 -1
  41. package/esm/model/methods/dirty-methods.mjs.map +1 -1
  42. package/esm/model/methods/hydration-methods.mjs.map +1 -1
  43. package/esm/model/methods/query-methods.mjs.map +1 -1
  44. package/esm/model/methods/scope-methods.mjs.map +1 -1
  45. package/esm/model/methods/static-event-methods.mjs.map +1 -1
  46. package/esm/model/methods/write-methods.mjs.map +1 -1
  47. package/esm/model/model.d.mts.map +1 -1
  48. package/esm/model/model.mjs.map +1 -1
  49. package/esm/model/register-model.d.mts.map +1 -1
  50. package/esm/model/register-model.mjs.map +1 -1
  51. package/esm/operations/migrations.d.mts.map +1 -1
  52. package/esm/operations/migrations.mjs.map +1 -1
  53. package/esm/query-builder/query-builder.d.mts.map +1 -1
  54. package/esm/query-builder/query-builder.mjs.map +1 -1
  55. package/esm/relations/key-conventions.mjs.map +1 -1
  56. package/esm/relations/pivot-operations.d.mts.map +1 -1
  57. package/esm/relations/pivot-operations.mjs.map +1 -1
  58. package/esm/relations/relation-loader.d.mts.map +1 -1
  59. package/esm/relations/relation-loader.mjs.map +1 -1
  60. package/esm/remover/database-remover.d.mts.map +1 -1
  61. package/esm/remover/database-remover.mjs.map +1 -1
  62. package/esm/sync/sync-context.d.mts.map +1 -1
  63. package/esm/sync/sync-context.mjs.map +1 -1
  64. package/esm/sync/sync-fanout.mjs.map +1 -1
  65. package/esm/sync/sync-manager.d.mts.map +1 -1
  66. package/esm/sync/sync-manager.mjs.map +1 -1
  67. package/esm/utils/database-writer.utils.d.mts.map +1 -1
  68. package/esm/utils/database-writer.utils.mjs.map +1 -1
  69. package/esm/utils/is-valid-date-value.mjs.map +1 -1
  70. package/esm/writer/database-writer.d.mts.map +1 -1
  71. package/esm/writer/database-writer.mjs.map +1 -1
  72. package/llms-full.txt +541 -434
  73. package/package.json +5 -5
  74. package/skills/aggregate-data/SKILL.md +28 -17
  75. package/skills/alter-migration/SKILL.md +325 -233
  76. package/skills/cascade-basics/SKILL.md +19 -19
  77. package/skills/configure-delete-strategy/SKILL.md +11 -11
  78. package/skills/define-model/SKILL.md +19 -17
  79. package/skills/define-relations/SKILL.md +13 -18
  80. package/skills/index.md +3 -0
  81. package/skills/manage-transactions/SKILL.md +18 -12
  82. package/skills/paginate-results/SKILL.md +6 -8
  83. package/skills/perform-atomic-ops/SKILL.md +26 -21
  84. package/skills/query-data/SKILL.md +27 -33
  85. package/skills/run-cascade-cli/SKILL.md +11 -10
  86. package/skills/search-by-vector/SKILL.md +8 -5
  87. package/skills/subscribe-to-model-events/SKILL.md +17 -17
  88. package/skills/track-changes/SKILL.md +9 -9
  89. package/skills/write-migration/SKILL.md +4 -4
package/package.json CHANGED
@@ -13,10 +13,10 @@
13
13
  "@mongez/events": "^2.2.8",
14
14
  "@mongez/reinforcements": "^4.0.2",
15
15
  "@mongez/supportive-is": "^3.0.0",
16
- "@warlock.js/context": "5.30.0",
17
- "@warlock.js/logger": "5.30.0",
18
- "@warlock.js/scheduler": "5.30.0",
19
- "@warlock.js/seal": "5.30.0",
16
+ "@warlock.js/context": "5.31.0",
17
+ "@warlock.js/logger": "5.31.0",
18
+ "@warlock.js/scheduler": "5.31.0",
19
+ "@warlock.js/seal": "5.31.0",
20
20
  "citty": "^0.2.2",
21
21
  "fast-glob": "^3.3.3"
22
22
  },
@@ -53,7 +53,7 @@
53
53
  ],
54
54
  "author": "hassanzohdy",
55
55
  "license": "MIT",
56
- "version": "5.30.0",
56
+ "version": "5.31.0",
57
57
  "main": "./cjs/index.cjs",
58
58
  "module": "./esm/index.mjs",
59
59
  "types": "./esm/index.d.mts",
@@ -10,23 +10,21 @@ Cascade's query builder isn't only for finding records — it crunches numbers t
10
10
  ## Scalar aggregates
11
11
 
12
12
  ```ts
13
- const total = await Order.count(); // count is static on the model
14
- const revenue = await Order.query().sum("total");
15
- const avgTicket = await Order.query().avg("total");
16
- const cheapest = await Order.query().min("total");
17
- const priciest = await Order.query().max("total");
13
+ const total = await Order.count(); // count is static on the model
14
+ const revenue = await Order.query().sum("total");
15
+ const avgTicket = await Order.query().avg("total");
16
+ const cheapest = await Order.query().min("total");
17
+ const priciest = await Order.query().max("total");
18
18
 
19
19
  // Filtered
20
- const monthRevenue = await Order.query()
21
- .whereDateAfter("created_at", startOfMonth)
22
- .sum("total");
20
+ const monthRevenue = await Order.query().whereDateAfter("created_at", startOfMonth).sum("total");
23
21
  ```
24
22
 
25
23
  Each returns a single number (`Promise<number>`). Only `count` is a static shortcut on the model; `sum` / `avg` / `min` / `max` (and the date helpers) are query-builder methods — reach them via `Order.query()` or chain off `Order.where(...)`. Date filters take a single date: `whereDate(field, value)` (exact day, time ignored), `whereDateAfter` / `whereDateBefore` (one-sided), `whereDateBetween(field, [a, b])` (range) — there is no 3-arg `whereDate(field, op, value)`. By Cascade convention the scalar terminators return **`0` on zero rows — not `null`** — so you can use the result directly without a null guard.
26
24
 
27
25
  ## Grouped rollups — two-arg `groupBy(fields, aggregates)`
28
26
 
29
- To compute aggregates *per group*, pass a second argument to `groupBy`: an object mapping output aliases to aggregate expressions. Build the expressions with the `$agg` helpers:
27
+ To compute aggregates _per group_, pass a second argument to `groupBy`: an object mapping output aliases to aggregate expressions. Build the expressions with the `$agg` helpers:
30
28
 
31
29
  ```ts
32
30
  import { $agg } from "@warlock.js/cascade";
@@ -59,8 +57,8 @@ import { $agg, $expr } from "@warlock.js/cascade";
59
57
 
60
58
  const revenue = await OrderItem.query()
61
59
  .groupBy("product_id", {
62
- revenue: $agg.sum($expr.mul("price", "quantity")), // SUM(price * quantity)
63
- net: $agg.sum($expr.mul($expr.sub($expr.lit(1), "discount"), "price")),// SUM((1 - discount) * price)
60
+ revenue: $agg.sum($expr.mul("price", "quantity")), // SUM(price * quantity)
61
+ net: $agg.sum($expr.mul($expr.sub($expr.lit(1), "discount"), "price")), // SUM((1 - discount) * price)
64
62
  })
65
63
  .get();
66
64
  ```
@@ -108,7 +106,7 @@ const monthly = await Order.query()
108
106
 
109
107
  ## `.having(...)` — filter groups by a computed aggregate
110
108
 
111
- `.where()` filters rows *before* grouping (cheap, uses indexes). `.having()` filters *after* aggregation, by the alias you defined:
109
+ `.where()` filters rows _before_ grouping (cheap, uses indexes). `.having()` filters _after_ aggregation, by the alias you defined:
112
110
 
113
111
  ```ts
114
112
  const big = await Order.query()
@@ -137,14 +135,27 @@ The `orderBy` reference matches the alias from the aggregates object.
137
135
  const rows = await Post.query().unwind("tags").where("tags", "news").lean().get();
138
136
 
139
137
  // Keep posts with no tags; record each tag's position
140
- await Post.query().unwind("tags", { preserveNullAndEmptyArrays: true, includeArrayIndex: "position" }).get();
138
+ await Post.query()
139
+ .unwind("tags", { preserveNullAndEmptyArrays: true, includeArrayIndex: "position" })
140
+ .get();
141
141
 
142
142
  // Computed field, existing fields kept
143
- await Post.query().addFields({ score: { $add: ["$likes", "$shares"] } }).orderBy("score", "desc").get();
143
+ await Post.query()
144
+ .addFields({ score: { $add: ["$likes", "$shares"] } })
145
+ .orderBy("score", "desc")
146
+ .get();
144
147
 
145
148
  // Pipeline $lookup
146
- await Post.query().join({ table: "comments", localField: "id", foreignField: "postId",
147
- alias: "approved", pipeline: [{ $match: { approved: true } }] }).lean().get();
149
+ await Post.query()
150
+ .join({
151
+ table: "comments",
152
+ localField: "id",
153
+ foreignField: "postId",
154
+ alias: "approved",
155
+ pipeline: [{ $match: { approved: true } }],
156
+ })
157
+ .lean()
158
+ .get();
148
159
  ```
149
160
 
150
161
  `unwind()` returns several rows for one stored document. Use `.lean()` when you only read them. `addFields` expressions are raw aggregation expressions: write them in code, never from request data. Computed columns in the output also work with `selectRaw({ alias: expr })` (`$project`). There is no `$facet` method yet.
@@ -156,7 +167,7 @@ Raw stages: `joinRaw({ $lookup: { from, let, pipeline, as } })` (or an array of
156
167
  ## Gotchas
157
168
 
158
169
  - **`where` vs `having`.** Row filters go in `.where()` (before grouping, index-friendly); aggregate filters go in `.having()`.
159
- - **Empty sets.** Scalar terminators return `0` on zero rows (above). For *grouped* reports, a group with no rows simply doesn't appear — a report over an empty range returns `[]`, not a row of zeros.
170
+ - **Empty sets.** Scalar terminators return `0` on zero rows (above). For _grouped_ reports, a group with no rows simply doesn't appear — a report over an empty range returns `[]`, not a row of zeros.
160
171
  - **Don't `.all()` then `array.reduce`.** Always push aggregates to the database.
161
172
 
162
173
  ## See also