@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.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -5
- package/cjs/index.cjs +0 -1
- package/cjs/index.cjs.map +1 -1
- package/esm/contracts/database-restorer.contract.d.mts.map +1 -1
- package/esm/data-source/data-source-registry.d.mts.map +1 -1
- package/esm/data-source/data-source-registry.mjs.map +1 -1
- package/esm/drivers/mongodb/mongodb-driver.d.mts.map +1 -1
- package/esm/drivers/mongodb/mongodb-driver.mjs.map +1 -1
- package/esm/drivers/mongodb/mongodb-id-generator.d.mts.map +1 -1
- package/esm/drivers/mongodb/mongodb-id-generator.mjs.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-builder.d.mts.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-builder.mjs.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-operations.d.mts.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-operations.mjs.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-parser.d.mts.map +1 -1
- package/esm/drivers/mongodb/mongodb-query-parser.mjs.map +1 -1
- package/esm/drivers/postgres/naming.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-dialect.d.mts.map +1 -1
- package/esm/drivers/postgres/postgres-dialect.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-driver.d.mts.map +1 -1
- package/esm/drivers/postgres/postgres-driver.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-migration-driver.d.mts.map +1 -1
- package/esm/drivers/postgres/postgres-migration-driver.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-query-builder.d.mts.map +1 -1
- package/esm/drivers/postgres/postgres-query-builder.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-query-parser.d.mts.map +1 -1
- package/esm/drivers/postgres/postgres-query-parser.mjs +0 -1
- package/esm/drivers/postgres/postgres-query-parser.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-sql-serializer.mjs.map +1 -1
- package/esm/drivers/postgres/postgres-ttl-purge.mjs.map +1 -1
- package/esm/drivers/postgres/types.d.mts.map +1 -1
- package/esm/errors/unsupported-query-operation.error.mjs.map +1 -1
- package/esm/expressions/column-expressions.d.mts.map +1 -1
- package/esm/expressions/column-expressions.mjs.map +1 -1
- package/esm/migration/foreign-key-builder.mjs.map +1 -1
- package/esm/migration/parse-created-at.mjs.map +1 -1
- package/esm/migration/sql-grammar.mjs.map +1 -1
- package/esm/model/generate-model-id.mjs.map +1 -1
- package/esm/model/methods/accessor-methods.mjs.map +1 -1
- package/esm/model/methods/dirty-methods.mjs.map +1 -1
- package/esm/model/methods/hydration-methods.mjs.map +1 -1
- package/esm/model/methods/query-methods.mjs.map +1 -1
- package/esm/model/methods/scope-methods.mjs.map +1 -1
- package/esm/model/methods/static-event-methods.mjs.map +1 -1
- package/esm/model/methods/write-methods.mjs.map +1 -1
- package/esm/model/model.d.mts.map +1 -1
- package/esm/model/model.mjs.map +1 -1
- package/esm/model/register-model.d.mts.map +1 -1
- package/esm/model/register-model.mjs.map +1 -1
- package/esm/operations/migrations.d.mts.map +1 -1
- package/esm/operations/migrations.mjs.map +1 -1
- package/esm/query-builder/query-builder.d.mts.map +1 -1
- package/esm/query-builder/query-builder.mjs.map +1 -1
- package/esm/relations/key-conventions.mjs.map +1 -1
- package/esm/relations/pivot-operations.d.mts.map +1 -1
- package/esm/relations/pivot-operations.mjs.map +1 -1
- package/esm/relations/relation-loader.d.mts.map +1 -1
- package/esm/relations/relation-loader.mjs.map +1 -1
- package/esm/remover/database-remover.d.mts.map +1 -1
- package/esm/remover/database-remover.mjs.map +1 -1
- package/esm/sync/sync-context.d.mts.map +1 -1
- package/esm/sync/sync-context.mjs.map +1 -1
- package/esm/sync/sync-fanout.mjs.map +1 -1
- package/esm/sync/sync-manager.d.mts.map +1 -1
- package/esm/sync/sync-manager.mjs.map +1 -1
- package/esm/utils/database-writer.utils.d.mts.map +1 -1
- package/esm/utils/database-writer.utils.mjs.map +1 -1
- package/esm/utils/is-valid-date-value.mjs.map +1 -1
- package/esm/writer/database-writer.d.mts.map +1 -1
- package/esm/writer/database-writer.mjs.map +1 -1
- package/llms-full.txt +541 -434
- package/package.json +5 -5
- package/skills/aggregate-data/SKILL.md +28 -17
- package/skills/alter-migration/SKILL.md +325 -233
- package/skills/cascade-basics/SKILL.md +19 -19
- package/skills/configure-delete-strategy/SKILL.md +11 -11
- package/skills/define-model/SKILL.md +19 -17
- package/skills/define-relations/SKILL.md +13 -18
- package/skills/index.md +3 -0
- package/skills/manage-transactions/SKILL.md +18 -12
- package/skills/paginate-results/SKILL.md +6 -8
- package/skills/perform-atomic-ops/SKILL.md +26 -21
- package/skills/query-data/SKILL.md +27 -33
- package/skills/run-cascade-cli/SKILL.md +11 -10
- package/skills/search-by-vector/SKILL.md +8 -5
- package/skills/subscribe-to-model-events/SKILL.md +17 -17
- package/skills/track-changes/SKILL.md +9 -9
- package/skills/write-migration/SKILL.md +4 -4
|
@@ -96,7 +96,10 @@ async function answer(question: string) {
|
|
|
96
96
|
// optional: drop low-similarity hits in code
|
|
97
97
|
const relevant = context.filter((document) => document.score >= 0.75);
|
|
98
98
|
|
|
99
|
-
const prompt = buildPrompt(
|
|
99
|
+
const prompt = buildPrompt(
|
|
100
|
+
question,
|
|
101
|
+
relevant.map((document) => document.body),
|
|
102
|
+
);
|
|
100
103
|
return ai.complete(prompt);
|
|
101
104
|
}
|
|
102
105
|
```
|
|
@@ -105,11 +108,11 @@ A score threshold isn't a query option — filter on the `score` column in code
|
|
|
105
108
|
|
|
106
109
|
## Driver support
|
|
107
110
|
|
|
108
|
-
| Driver
|
|
109
|
-
|
|
|
110
|
-
| Postgres (with `CREATE EXTENSION vector`)
|
|
111
|
+
| Driver | Vector |
|
|
112
|
+
| ---------------------------------------------- | ------------------------------------ |
|
|
113
|
+
| Postgres (with `CREATE EXTENSION vector`) | ✅ pgvector + IVFFlat index |
|
|
111
114
|
| MongoDB Atlas (paid tier + Atlas Search index) | ✅ `$vectorSearch` aggregation stage |
|
|
112
|
-
| MongoDB community / self-hosted / local
|
|
115
|
+
| MongoDB community / self-hosted / local | ❌ Atlas-only |
|
|
113
116
|
|
|
114
117
|
For local dev with MongoDB, develop the vector path against Postgres + pgvector.
|
|
115
118
|
|
|
@@ -25,18 +25,18 @@ Listeners are async-aware — the model's persistence awaits the listener before
|
|
|
25
25
|
|
|
26
26
|
The events fire in this order. The **gerund** form (`saving`, `creating`) is the "before" hook — there is no `beforeSave` alias.
|
|
27
27
|
|
|
28
|
-
| Event
|
|
29
|
-
|
|
|
30
|
-
| `saving`
|
|
31
|
-
| `validating` / `validated`
|
|
32
|
-
| `creating`
|
|
33
|
-
| `updating`
|
|
34
|
-
| `saved`
|
|
35
|
-
| `created`
|
|
36
|
-
| `updated`
|
|
37
|
-
| `deleting` / `deleted`
|
|
38
|
-
| `restoring` / `restored`
|
|
39
|
-
| `fetching` / `fetched` / `hydrating` | Around reads / instance hydration
|
|
28
|
+
| Event | Fires |
|
|
29
|
+
| ------------------------------------ | ------------------------------------------------------------------- |
|
|
30
|
+
| `saving` | Before validation, on every `save()` (both insert and update paths) |
|
|
31
|
+
| `validating` / `validated` | Around schema validation |
|
|
32
|
+
| `creating` | Before a new record is inserted (first save) |
|
|
33
|
+
| `updating` | Before an existing record's update is written |
|
|
34
|
+
| `saved` | After a successful write (any branch — insert or update) |
|
|
35
|
+
| `created` | After a new record is inserted |
|
|
36
|
+
| `updated` | After an existing record's update is written |
|
|
37
|
+
| `deleting` / `deleted` | Before / after the delete strategy runs |
|
|
38
|
+
| `restoring` / `restored` | Before / after a soft-deleted or trashed record is restored |
|
|
39
|
+
| `fetching` / `fetched` / `hydrating` | Around reads / instance hydration |
|
|
40
40
|
|
|
41
41
|
`saving` fires for both inserts and updates; `creating` / `updating` narrow to the branch. So `saved` always fires; exactly one of `created` / `updated` follows.
|
|
42
42
|
|
|
@@ -67,17 +67,17 @@ Pair with `isDirty()` from the `track-changes` topic so the listener only runs i
|
|
|
67
67
|
|
|
68
68
|
## Global listeners — across all models
|
|
69
69
|
|
|
70
|
-
For framework-level concerns (audit log, observability, cache invalidation), subscribe
|
|
70
|
+
For framework-level concerns (audit log, observability, cache invalidation), subscribe through `Model.globalEvents()` — the listener runs for every model:
|
|
71
71
|
|
|
72
72
|
```ts
|
|
73
73
|
import { Model } from "@warlock.js/cascade";
|
|
74
74
|
|
|
75
|
-
Model.on("saved",
|
|
76
|
-
|
|
75
|
+
Model.globalEvents().on("saved", (instance) => {
|
|
76
|
+
console.info("save", instance.constructor.name, instance.id, instance.getDirtyColumns());
|
|
77
77
|
});
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
Filter by `instance.constructor.name === "User"` when you only care about specific models, or register per-model handlers when the scope is narrow.
|
|
80
|
+
Filter by `instance.constructor.name === "User"` when you only care about specific models, or register per-model handlers when the scope is narrow. The base `Model` is abstract; its per-model `on()` shortcut expects a concrete subclass.
|
|
81
81
|
|
|
82
82
|
## `off()` to unsubscribe
|
|
83
83
|
|
|
@@ -115,7 +115,7 @@ Model.on("updated", async (instance) => {
|
|
|
115
115
|
});
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
Use `updated` (not `saved`) when you only want change diffs — `getDirtyColumnsWithValues()` is still populated in the post-write events because the tracker resets
|
|
118
|
+
Use `updated` (not `saved`) when you only want change diffs — `getDirtyColumnsWithValues()` is still populated in the post-write events because the tracker resets _after_ they fire.
|
|
119
119
|
|
|
120
120
|
### Cache invalidation
|
|
121
121
|
|
|
@@ -10,11 +10,11 @@ Every Cascade model carries a dirty tracker that records which fields you've cha
|
|
|
10
10
|
## The main reads
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
|
-
user.hasChanges();
|
|
14
|
-
user.isDirty("email");
|
|
13
|
+
user.hasChanges(); // boolean — any field changed (or removed)?
|
|
14
|
+
user.isDirty("email"); // boolean — specifically this column?
|
|
15
15
|
|
|
16
|
-
user.getDirtyColumns();
|
|
17
|
-
user.getRemovedColumns();
|
|
16
|
+
user.getDirtyColumns(); // string[] — names of changed columns
|
|
17
|
+
user.getRemovedColumns(); // string[] — columns explicitly unset since load
|
|
18
18
|
|
|
19
19
|
user.getDirtyColumnsWithValues();
|
|
20
20
|
// Record<string, { oldValue, newValue }> — the full diff, old + new per column
|
|
@@ -59,9 +59,9 @@ await AuditLog.create({
|
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
61
|
user.set("name", "Augusta");
|
|
62
|
-
user.isDirty("name");
|
|
62
|
+
user.isDirty("name"); // true
|
|
63
63
|
await user.save();
|
|
64
|
-
user.isDirty("name");
|
|
64
|
+
user.isDirty("name"); // false — tracker reset to the just-saved state
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
`save()` resets the tracker's baseline to the persisted state. Subsequent `isDirty()` checks measure changes since the last `save()`, not since the original load.
|
|
@@ -103,12 +103,12 @@ for (const [field, { oldValue, newValue }] of Object.entries(dirty)) {
|
|
|
103
103
|
|
|
104
104
|
```ts
|
|
105
105
|
// plain object → merged key-by-key, siblings survive
|
|
106
|
-
user.merge({ profile: { age: 26 } });
|
|
107
|
-
user.getDirtyColumns();
|
|
106
|
+
user.merge({ profile: { age: 26 } }); // profile.city untouched
|
|
107
|
+
user.getDirtyColumns(); // ["profile.age"]
|
|
108
108
|
|
|
109
109
|
// Date → replaced, not merged
|
|
110
110
|
conversation.merge({ lastOutboundAt: new Date() });
|
|
111
|
-
conversation.getDirtyColumns();
|
|
111
|
+
conversation.getDirtyColumns(); // ["lastOutboundAt"]
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
:::note[Fixed in 4.9.1]
|
|
@@ -129,10 +129,10 @@ Class-form builders include `createTable()` / `createTableIfNotExists()`, `dropT
|
|
|
129
129
|
`this.foreignId(name)` (5.8+) derives the column's type from `migrationDefaults.primaryKey` so a foreign-key column always matches the type of the `id` it points at, instead of hardcoding one:
|
|
130
130
|
|
|
131
131
|
| `migrationDefaults.primaryKey` | `foreignId` produces |
|
|
132
|
-
|
|
|
133
|
-
| `uuid`
|
|
134
|
-
| `bigInt`
|
|
135
|
-
| anything else (default)
|
|
132
|
+
| ------------------------------ | -------------------- |
|
|
133
|
+
| `uuid` | `uuid` column |
|
|
134
|
+
| `bigInt` | `bigInteger` column |
|
|
135
|
+
| anything else (default) | `integer` column |
|
|
136
136
|
|
|
137
137
|
```ts
|
|
138
138
|
import { Migration } from "@warlock.js/cascade";
|