@shivaedev/sql 0.28.0 → 0.29.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 +10 -0
- package/README.md +18 -3
- package/dist/repository.d.ts +5 -9
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +2 -0
- package/dist/repository.js.map +1 -1
- package/dist/repositoryCollection.d.ts +28 -0
- package/dist/repositoryCollection.d.ts.map +1 -0
- package/dist/repositoryCollection.js +21 -0
- package/dist/repositoryCollection.js.map +1 -0
- package/dist/testing.d.ts +2 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/package.json +4 -4
- package/src/repository.ts +11 -11
- package/src/repositoryCollection.ts +46 -0
- package/src/testing.ts +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.29.0 - 2026-10-31
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `expectPublished` accepts a function of the successful write result, so generated-id inserts can assert their own record keys.
|
|
8
|
+
|
|
9
|
+
### Breaking
|
|
10
|
+
|
|
11
|
+
- Bucket-bearing repositories require their contract collection in `makeRepository`'s `collection` option. Pass the collection already used by query read keys; its name must equal `tableName` and its bucket fields must match the model's `bucket` annotations. Registration fails with the typed `BucketRegistrationError` when declarations disagree or the collection is missing. Handle this new registration error when constructing repositories.
|
|
12
|
+
|
|
3
13
|
## 0.28.0 - 2026-10-31
|
|
4
14
|
|
|
5
15
|
### Added
|
package/README.md
CHANGED
|
@@ -454,9 +454,15 @@ class Note extends Model.Class<Note>("Note")({
|
|
|
454
454
|
}) {}
|
|
455
455
|
|
|
456
456
|
const notes = collection("notes", Note.fields.id, { listId: Note.fields.listId, owner: Note.fields.owner });
|
|
457
|
+
const makeNotes = makeRepository(Note, {
|
|
458
|
+
collection: notes,
|
|
459
|
+
idColumn: "id",
|
|
460
|
+
spanPrefix: "Notes",
|
|
461
|
+
tableName: "notes",
|
|
462
|
+
});
|
|
457
463
|
```
|
|
458
464
|
|
|
459
|
-
|
|
465
|
+
Pass the contract collection as the repository's `collection` option when the model has buckets. Registration fails with `BucketRegistrationError` if the collection is missing, its name differs from `tableName`, or its bucket field names differ from the model's annotated fields. The error names both declarations. Repositories without buckets may omit the collection. Every inserted, updated or deleted row announces its record key and each declared bucket from the old and new stored values. An insert belongs only to its new buckets; a move announces both sides; a delete announces the old buckets. Bucket codecs decode stored values before producing keys, so a `bucket(Schema.NumberFromString)` field matches a numeric query bucket even when stored as text. Nullable and optional bucket values contribute no key when absent. Bucket codecs must need no services and decode to strings, numbers or absent values.
|
|
460
466
|
|
|
461
467
|
Bucket writes require PostgreSQL 18 or later: native `RETURNING old` supplies old values atomically, including for conflict updates. Repositories without bucket fields keep their existing SQL dialect support. Bulk writes keep every record and bucket key; the PostgreSQL publisher splits large batches into NOTIFY payloads.
|
|
462
468
|
|
|
@@ -568,7 +574,7 @@ NOTIFY is a wake-up signal, not a durable log. Transaction payloads contain only
|
|
|
568
574
|
|
|
569
575
|
Import the module that defines the name; there is no root entry.
|
|
570
576
|
- `@shivaedev/sql/clientOptions.ts`: `clientOptions(options, { snakeCase? })`, `SqlNameTransforms` — Add default native name transforms to driver or app host options; opt out with `snakeCase: false`.
|
|
571
|
-
- `@shivaedev/sql/repository.ts`: `makeRepository(model, options)` — `tableName`, scalar or composite `idColumn`, `spanPrefix`, optional `versionColumn`, `conflictColumns` and `conflictWhere
|
|
577
|
+
- `@shivaedev/sql/repository.ts`: `makeRepository(model, options)` — `tableName`, scalar or composite `idColumn`, `spanPrefix`, optional `versionColumn`, `conflictColumns` and `conflictWhere`, and `collection` required for bucket models; requires native `SqlClient`.
|
|
572
578
|
- `@shivaedev/sql/repository.ts`: `OptimisticConcurrencyError` — Typed stale or missing-row failure for versioned writes, with `tableName`, `id`, `expectedVersion`, `reason: "missing" | "stale"`.
|
|
573
579
|
- `@shivaedev/sql/tupleIn.ts`: `tupleIn(model, fields, tuples, types)` — Filter entry matching two or more fields together against a list of tuples, for `where` in reads and unversioned deletes.
|
|
574
580
|
- `@shivaedev/sql/upsertResult.ts`: `UpsertRow` — The `{ row, inserted }` result of an unconditional upsert.
|
|
@@ -584,6 +590,7 @@ Import the module that defines the name; there is no root entry.
|
|
|
584
590
|
- `@shivaedev/sql/pendingPostgresMigrations.ts`: `pendingPostgresMigrations({ loader, table?, components? })` — Pending ledger migrations as ID and name, and pending schema components as name and detail.
|
|
585
591
|
- `@shivaedev/sql/postgresRelease.ts`: `postgresRelease(release, table?)`, `readPostgresRelease(table?)` — Release marker schema component and its reader.
|
|
586
592
|
- `@shivaedev/sql/postgresChanges.ts`: `postgresChanges(options)` — Scoped PostgreSQL LISTEN/NOTIFY Layer for commit-bound invalidation.
|
|
593
|
+
- `@shivaedev/sql/repositoryCollection.ts`: `BucketRegistrationError` — Registration failure with table, collection and bucket field names.
|
|
587
594
|
- `@shivaedev/sql/testing.ts`: `withChangeCoverage(body, { covers })`, `expectPublished(keys)`, `UnannouncedWrites`, `PublishedKeysMismatch` — Test assertions that every write announced its keys and that the expected keys were published.
|
|
588
595
|
|
|
589
596
|
### Install and database setup
|
|
@@ -662,4 +669,12 @@ yield* withChangeCoverage(
|
|
|
662
669
|
|
|
663
670
|
The coverage check verifies the declarations, not the contents of arbitrary SQL. Raw writers must declare every affected record and bucket, including unchanged buckets. Transaction statistics retain writes from rolled-back savepoints, so those writes still need declarations during a coverage check.
|
|
664
671
|
|
|
665
|
-
`body.pipe(expectPublished(keys))` compares the distinct published keys, regardless of order, and preserves the body's result. Put it outside the committing transaction. It observes the existing change channel and leaves delivery intact; recorded keys from rolled-back writes do not count. A mismatch fails with `PublishedKeysMismatch`, whose `expected`, `actual` and message show both key sets. The assertion happens after the body, so a mismatch does not roll back a committed write.
|
|
672
|
+
`body.pipe(expectPublished(keys))` accepts an array or a function of the successful body result and compares the distinct published keys, regardless of order, and preserves the body's result. Put it outside the committing transaction. It observes the existing change channel and leaves delivery intact; recorded keys from rolled-back writes do not count. A mismatch fails with `PublishedKeysMismatch`, whose `expected`, `actual` and message show both key sets. The assertion happens after the body, so a mismatch does not roll back a committed write. For generated ids, derive keys after the write:
|
|
673
|
+
|
|
674
|
+
```ts
|
|
675
|
+
const note = yield* repository.insert(draft).pipe(
|
|
676
|
+
expectPublished((row: Note) => invalidationKeys([notes.item(row.id), notes.bucket.listId(row.listId), notes.bucket.owner(row.owner)])),
|
|
677
|
+
);
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
See [automatic change delivery](https://github.com/ShivaeDev/platform/blob/main/docs/framework/changes.md) for host defaults and coverage limits.
|
package/dist/repository.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { type BatchWrites } from "#batchWrites.ts";
|
|
|
5
5
|
import { type PrimaryKey, type Repository } from "#compositeRepository.ts";
|
|
6
6
|
import { type ConflictColumns, type ConflictWrites } from "#conflictWrites.ts";
|
|
7
7
|
import { type SelectWrites } from "#insertFromSelect.ts";
|
|
8
|
+
import { type BucketRegistrationError, type RepositoryOptions } from "#repositoryCollection.ts";
|
|
8
9
|
import type { FindManyFilter, RepositoryFilter, RepositoryListFilter } from "#repositoryFilter.ts";
|
|
9
10
|
import { type Queries } from "#repositoryQueries.ts";
|
|
10
11
|
import { type VersionColumn, type VersionedWrites } from "#versionedRepository.ts";
|
|
@@ -36,31 +37,26 @@ export declare class OptimisticConcurrencyError extends OptimisticConcurrencyErr
|
|
|
36
37
|
readonly reason: "missing" | "stale";
|
|
37
38
|
}> {
|
|
38
39
|
}
|
|
39
|
-
interface RepositoryOptions<TId> {
|
|
40
|
-
readonly idColumn: TId;
|
|
41
|
-
readonly spanPrefix: string;
|
|
42
|
-
readonly tableName: string;
|
|
43
|
-
}
|
|
44
40
|
type VersionedRepository<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = Omit<Repository<TModel, TId>, keyof VersionedWrites<TModel, TId>> & VersionedWrites<TModel, TId> & Queries<TModel>;
|
|
45
41
|
export declare function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>, const TConflict extends ConflictColumns<TModel>, const TWhere extends keyof RepositoryFilter<TModel> = never>(model: TModel, options: RepositoryOptions<TId> & {
|
|
46
42
|
readonly versionColumn: VersionColumn<TModel, TId>;
|
|
47
43
|
readonly conflictColumns: TConflict;
|
|
48
44
|
readonly conflictWhere?: Pick<RepositoryFilter<TModel>, TWhere>;
|
|
49
|
-
}): Effect.Effect<VersionedRepository<TModel, TId> & Pick<ConflictWrites<TModel, never, TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]>, "insertOrIgnore">,
|
|
45
|
+
}): Effect.Effect<VersionedRepository<TModel, TId> & Pick<ConflictWrites<TModel, never, TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]>, "insertOrIgnore">, BucketRegistrationError, SqlClient.SqlClient>;
|
|
50
46
|
export declare function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>>(model: TModel, options: RepositoryOptions<TId> & {
|
|
51
47
|
readonly versionColumn: VersionColumn<TModel, TId>;
|
|
52
48
|
readonly conflictColumns?: never;
|
|
53
49
|
readonly conflictWhere?: never;
|
|
54
|
-
}): Effect.Effect<VersionedRepository<TModel, TId>,
|
|
50
|
+
}): Effect.Effect<VersionedRepository<TModel, TId>, BucketRegistrationError, SqlClient.SqlClient>;
|
|
55
51
|
export declare function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>, const TConflict extends ConflictColumns<TModel>, const TWhere extends keyof RepositoryFilter<TModel> = never>(model: TModel, options: RepositoryOptions<TId> & {
|
|
56
52
|
readonly versionColumn?: never;
|
|
57
53
|
readonly conflictColumns: TConflict;
|
|
58
54
|
readonly conflictWhere?: Pick<RepositoryFilter<TModel>, TWhere>;
|
|
59
|
-
}): Effect.Effect<Repository<TModel, TId> & BatchWrites<TModel> & SelectWrites<TModel> & Queries<TModel> & ConflictWrites<TModel, TConflict[number] | (TId extends readonly PropertyKey[] ? TId[number] : TId), TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]>,
|
|
55
|
+
}): Effect.Effect<Repository<TModel, TId> & BatchWrites<TModel> & SelectWrites<TModel> & Queries<TModel> & ConflictWrites<TModel, TConflict[number] | (TId extends readonly PropertyKey[] ? TId[number] : TId), TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]>, BucketRegistrationError, SqlClient.SqlClient>;
|
|
60
56
|
export declare function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>>(model: TModel, options: RepositoryOptions<TId> & {
|
|
61
57
|
readonly versionColumn?: never;
|
|
62
58
|
readonly conflictColumns?: never;
|
|
63
59
|
readonly conflictWhere?: never;
|
|
64
|
-
}): Effect.Effect<Repository<TModel, TId> & BatchWrites<TModel> & SelectWrites<TModel> & Queries<TModel>,
|
|
60
|
+
}): Effect.Effect<Repository<TModel, TId> & BatchWrites<TModel> & SelectWrites<TModel> & Queries<TModel>, BucketRegistrationError, SqlClient.SqlClient>;
|
|
65
61
|
export {};
|
|
66
62
|
//# sourceMappingURL=repository.d.ts.map
|
package/dist/repository.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAqB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAsB,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAwB,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE/E,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACnG,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAsC,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAEvH,KAAK,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,IAAI,OAAO,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACjG,KAAK,GAAG,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE1E,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG;IAChD,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG,EAAE,IAAI,SAAS,GAAG,CAAC,MAAM,CAAC;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,cAAc,CAAC,MAAM,SAAS,KAAK,CAAC,GAAG;IACvD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC/D,QAAQ,CAAC,KAAK,CAAC,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC;CAC9C;;;;AAED,qBAAa,0BAA2B,SAAQ,gCAA+C;IAC9F,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;CACrC,CAAC;CAAG;AAEL,
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
|
package/dist/repository.js
CHANGED
|
@@ -5,12 +5,14 @@ import { makeCompositeCrud } from "#compositeRepository.ts";
|
|
|
5
5
|
import { makeConflictWrites } from "#conflictWrites.ts";
|
|
6
6
|
import { makeInsertFromSelect } from "#insertFromSelect.ts";
|
|
7
7
|
import { repositoryChanges } from "#repositoryChanges.ts";
|
|
8
|
+
import { validateRepositoryCollection } from "#repositoryCollection.ts";
|
|
8
9
|
import { makeQueries } from "#repositoryQueries.ts";
|
|
9
10
|
import { makeVersionedWrites } from "#versionedRepository.ts";
|
|
10
11
|
export class OptimisticConcurrencyError extends Data.TaggedError("OptimisticConcurrencyError") {
|
|
11
12
|
}
|
|
12
13
|
export function makeRepository(model, options) {
|
|
13
14
|
return Effect.fnUntraced(function* () {
|
|
15
|
+
yield* validateRepositoryCollection(model.fields, options);
|
|
14
16
|
const sql = yield* SqlClient.SqlClient;
|
|
15
17
|
const composite = typeof options.idColumn === "object";
|
|
16
18
|
const idColumns = (composite ? options.idColumn : [options.idColumn]).map(String);
|
package/dist/repository.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAe,MAAM,QAAQ,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAoB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAoC,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAA6C,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAqB,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Effect, type Schema } from "effect";
|
|
2
|
+
export interface RepositoryCollection {
|
|
3
|
+
readonly bucket: Readonly<Record<string, unknown>>;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface RepositoryOptions<TId> {
|
|
7
|
+
readonly collection?: RepositoryCollection;
|
|
8
|
+
readonly idColumn: TId;
|
|
9
|
+
readonly spanPrefix: string;
|
|
10
|
+
readonly tableName: string;
|
|
11
|
+
}
|
|
12
|
+
declare const BucketRegistrationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
13
|
+
readonly _tag: "BucketRegistrationError";
|
|
14
|
+
} & Readonly<A>;
|
|
15
|
+
export declare class BucketRegistrationError extends BucketRegistrationError_base<{
|
|
16
|
+
readonly tableName: string;
|
|
17
|
+
readonly collectionName: string | undefined;
|
|
18
|
+
readonly modelFields: readonly string[];
|
|
19
|
+
readonly collectionFields: readonly string[];
|
|
20
|
+
}> {
|
|
21
|
+
get message(): string;
|
|
22
|
+
}
|
|
23
|
+
export declare const validateRepositoryCollection: (fields: Schema.Struct.Fields, options: {
|
|
24
|
+
readonly tableName: string;
|
|
25
|
+
readonly collection?: RepositoryCollection;
|
|
26
|
+
}) => Effect.Effect<undefined, BucketRegistrationError, never>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=repositoryCollection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryCollection.d.ts","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAS,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAG1D,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB,CAAC,GAAG;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;;;;AAED,qBAAa,uBAAwB,SAAQ,6BAA4C;IACxF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C,CAAC;IACD,IAAa,OAAO,WAEnB;CACD;AAED,eAAO,MAAM,4BAA4B;wBAET,MAAM;0BAAwB,oBAAoB;8DAiBhF,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Data, Effect, Order } from "effect";
|
|
2
|
+
import { declaredBuckets } from "@shivaedev/changes/buckets.ts";
|
|
3
|
+
export class BucketRegistrationError extends Data.TaggedError("BucketRegistrationError") {
|
|
4
|
+
get message() {
|
|
5
|
+
return `Bucket registration for ${this.tableName}: model fields ${JSON.stringify(this.modelFields)} disagree with collection ${this.collectionName ?? "(missing)"} fields ${JSON.stringify(this.collectionFields)}`;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export const validateRepositoryCollection = Effect.fnUntraced(function* (fields, options) {
|
|
9
|
+
const modelFields = declaredBuckets(fields)
|
|
10
|
+
.map(({ field }) => field)
|
|
11
|
+
.sort(Order.String);
|
|
12
|
+
const collectionFields = Object.keys(options.collection?.bucket ?? {}).sort(Order.String);
|
|
13
|
+
if ((options.collection === undefined && modelFields.length === 0)
|
|
14
|
+
|| (options.collection?.name === options.tableName
|
|
15
|
+
&& modelFields.length === collectionFields.length
|
|
16
|
+
&& modelFields.every((field, index) => field === collectionFields[index]))) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
return yield* Effect.fail(new BucketRegistrationError({ collectionFields, collectionName: options.collection?.name, modelFields, tableName: options.tableName }));
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=repositoryCollection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositoryCollection.js","sourceRoot":"","sources":["../src/repositoryCollection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAe,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAchE,MAAM,OAAO,uBAAwB,SAAQ,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAKrF;IACD,IAAa,OAAO;QACnB,OAAO,2BAA2B,IAAI,CAAC,SAAS,kBAAkB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,6BAA6B,IAAI,CAAC,cAAc,IAAI,WAAW,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;IACrN,CAAC;CACD;AAED,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EACtE,MAA4B,EAC5B,OAAmF;IAEnF,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,CAAC;SACzC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC;SACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1F,IACC,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC;WAC3D,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,KAAK,OAAO,CAAC,SAAS;eAC9C,WAAW,CAAC,MAAM,KAAK,gBAAgB,CAAC,MAAM;eAC9C,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,EAC1E,CAAC;QACF,OAAO;IACR,CAAC;IACD,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CACxB,IAAI,uBAAuB,CAAC,EAAE,gBAAgB,EAAE,cAAc,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CACtI,CAAC;AACH,CAAC,CAAC,CAAC"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export declare class PublishedKeysMismatch extends PublishedKeysMismatch_base<{
|
|
|
21
21
|
}> {
|
|
22
22
|
get message(): string;
|
|
23
23
|
}
|
|
24
|
-
export declare function expectPublished(keys: readonly unknown[]): <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch,
|
|
24
|
+
export declare function expectPublished(keys: readonly unknown[]): <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
25
|
+
export declare function expectPublished<A>(keys: (result: A) => readonly unknown[]): <E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
25
26
|
export {};
|
|
26
27
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAoB,MAAM,4BAA4B,CAAC;;;;AAI5F,qBAAa,iBAAkB,SAAQ,uBAAsC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;CAAG;AAEvH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5E;AAED,eAAO,MAAM,kBAAkB,GAAsD,CAAC,EAAE,CAAC,EAAE,CAAC,4UAuD1F,CAAC;;;;AAEH,qBAAa,qBAAsB,SAAQ,2BAA0C;IACpF,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACpC,CAAC;IACD,IAAa,OAAO,WAEnB;CACD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,OAAO,EAAoB,MAAM,4BAA4B,CAAC;;;;AAI5F,qBAAa,iBAAkB,SAAQ,uBAAsC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;CAAG;AAEvH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;CAC5E;AAED,eAAO,MAAM,kBAAkB,GAAsD,CAAC,EAAE,CAAC,EAAE,CAAC,4UAuD1F,CAAC;;;;AAEH,qBAAa,qBAAsB,SAAQ,2BAA0C;IACpF,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACpC,CAAC;IACD,IAAa,OAAO,WAEnB;CACD;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,qBAAqB,EAAE,CAAC,CAAC,CAAC;AACrJ,wBAAgB,eAAe,CAAC,CAAC,EAChC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,SAAS,OAAO,EAAE,GACrC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,qBAAqB,EAAE,CAAC,CAAC,CAAC"}
|
package/dist/testing.js
CHANGED
|
@@ -65,7 +65,7 @@ export function expectPublished(keys) {
|
|
|
65
65
|
}
|
|
66
66
|
return observer(event);
|
|
67
67
|
}));
|
|
68
|
-
const expected = new Set(keys);
|
|
68
|
+
const expected = new Set(typeof keys === "function" ? keys(result) : keys);
|
|
69
69
|
if (actual.size !== expected.size || [...expected].some((key) => !actual.has(key))) {
|
|
70
70
|
return yield* Effect.fail(new PublishedKeysMismatch({ actual: [...actual], expected: [...expected] }));
|
|
71
71
|
}
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/sql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Schema-derived repositories over native Effect SQL",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"effect"
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"@effect/platform-node": "4.0.6",
|
|
51
51
|
"@effect/sql-pg": "4.0.6",
|
|
52
52
|
"@effect/sql-sqlite-node": "4.0.6",
|
|
53
|
-
"@shivaedev/quality": "0.
|
|
54
|
-
"@shivaedev/test-sql": "0.15.
|
|
55
|
-
"@shivaedev/test-story": "0.31.
|
|
53
|
+
"@shivaedev/quality": "0.52.0",
|
|
54
|
+
"@shivaedev/test-sql": "0.15.2",
|
|
55
|
+
"@shivaedev/test-story": "0.31.2",
|
|
56
56
|
"@types/node": "24.19.2",
|
|
57
57
|
"effect": "4.0.6",
|
|
58
58
|
"typescript": "7.0.2",
|
package/src/repository.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { makeCompositeCrud, type PrimaryKey, type Repository } from "#compositeR
|
|
|
6
6
|
import { type ConflictColumns, type ConflictWrites, makeConflictWrites } from "#conflictWrites.ts";
|
|
7
7
|
import { makeInsertFromSelect, type SelectWrites } from "#insertFromSelect.ts";
|
|
8
8
|
import { repositoryChanges } from "#repositoryChanges.ts";
|
|
9
|
+
import { type BucketRegistrationError, type RepositoryOptions, validateRepositoryCollection } from "#repositoryCollection.ts";
|
|
9
10
|
import type { FindManyFilter, RepositoryFilter, RepositoryListFilter } from "#repositoryFilter.ts";
|
|
10
11
|
import { makeQueries, type Queries } from "#repositoryQueries.ts";
|
|
11
12
|
import { type IdColumn, makeVersionedWrites, type VersionColumn, type VersionedWrites } from "#versionedRepository.ts";
|
|
@@ -39,12 +40,6 @@ export class OptimisticConcurrencyError extends Data.TaggedError("OptimisticConc
|
|
|
39
40
|
readonly reason: "missing" | "stale";
|
|
40
41
|
}> {}
|
|
41
42
|
|
|
42
|
-
interface RepositoryOptions<TId> {
|
|
43
|
-
readonly idColumn: TId;
|
|
44
|
-
readonly spanPrefix: string;
|
|
45
|
-
readonly tableName: string;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
43
|
type VersionedRepository<TModel extends Model.Any, TId extends PrimaryKey<TModel>> = Omit<
|
|
49
44
|
Repository<TModel, TId>,
|
|
50
45
|
keyof VersionedWrites<TModel, TId>
|
|
@@ -67,7 +62,7 @@ export function makeRepository<
|
|
|
67
62
|
): Effect.Effect<
|
|
68
63
|
VersionedRepository<TModel, TId> &
|
|
69
64
|
Pick<ConflictWrites<TModel, never, TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]>, "insertOrIgnore">,
|
|
70
|
-
|
|
65
|
+
BucketRegistrationError,
|
|
71
66
|
SqlClient.SqlClient
|
|
72
67
|
>;
|
|
73
68
|
export function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>>(
|
|
@@ -77,7 +72,7 @@ export function makeRepository<TModel extends Model.Any, const TId extends Prima
|
|
|
77
72
|
readonly conflictColumns?: never;
|
|
78
73
|
readonly conflictWhere?: never;
|
|
79
74
|
},
|
|
80
|
-
): Effect.Effect<VersionedRepository<TModel, TId>,
|
|
75
|
+
): Effect.Effect<VersionedRepository<TModel, TId>, BucketRegistrationError, SqlClient.SqlClient>;
|
|
81
76
|
export function makeRepository<
|
|
82
77
|
TModel extends Model.Any,
|
|
83
78
|
const TId extends PrimaryKey<TModel>,
|
|
@@ -100,13 +95,17 @@ export function makeRepository<
|
|
|
100
95
|
TConflict[number] | (TId extends readonly PropertyKey[] ? TId[number] : TId),
|
|
101
96
|
TModel["fields"][Extract<TWhere, keyof TModel["fields"]>]["EncodingServices"]
|
|
102
97
|
>,
|
|
103
|
-
|
|
98
|
+
BucketRegistrationError,
|
|
104
99
|
SqlClient.SqlClient
|
|
105
100
|
>;
|
|
106
101
|
export function makeRepository<TModel extends Model.Any, const TId extends PrimaryKey<TModel>>(
|
|
107
102
|
model: TModel,
|
|
108
103
|
options: RepositoryOptions<TId> & { readonly versionColumn?: never; readonly conflictColumns?: never; readonly conflictWhere?: never },
|
|
109
|
-
): Effect.Effect<
|
|
104
|
+
): Effect.Effect<
|
|
105
|
+
Repository<TModel, TId> & BatchWrites<TModel> & SelectWrites<TModel> & Queries<TModel>,
|
|
106
|
+
BucketRegistrationError,
|
|
107
|
+
SqlClient.SqlClient
|
|
108
|
+
>;
|
|
110
109
|
export function makeRepository<TModel extends Model.Any, TId extends IdColumn<TModel>>(
|
|
111
110
|
model: TModel,
|
|
112
111
|
options: RepositoryOptions<TId | readonly [TId, TId, ...TId[]]> & {
|
|
@@ -114,8 +113,9 @@ export function makeRepository<TModel extends Model.Any, TId extends IdColumn<TM
|
|
|
114
113
|
readonly conflictColumns?: readonly string[];
|
|
115
114
|
readonly conflictWhere?: Readonly<Record<string, unknown>>;
|
|
116
115
|
},
|
|
117
|
-
): Effect.Effect<unknown,
|
|
116
|
+
): Effect.Effect<unknown, BucketRegistrationError, SqlClient.SqlClient> {
|
|
118
117
|
return Effect.fnUntraced(function* () {
|
|
118
|
+
yield* validateRepositoryCollection(model.fields, options);
|
|
119
119
|
const sql = yield* SqlClient.SqlClient;
|
|
120
120
|
const composite = typeof options.idColumn === "object";
|
|
121
121
|
const idColumns = (composite ? options.idColumn : [options.idColumn]).map(String);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Data, Effect, Order, type Schema } from "effect";
|
|
2
|
+
import { declaredBuckets } from "@shivaedev/changes/buckets.ts";
|
|
3
|
+
|
|
4
|
+
export interface RepositoryCollection {
|
|
5
|
+
readonly bucket: Readonly<Record<string, unknown>>;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface RepositoryOptions<TId> {
|
|
10
|
+
readonly collection?: RepositoryCollection;
|
|
11
|
+
readonly idColumn: TId;
|
|
12
|
+
readonly spanPrefix: string;
|
|
13
|
+
readonly tableName: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class BucketRegistrationError extends Data.TaggedError("BucketRegistrationError")<{
|
|
17
|
+
readonly tableName: string;
|
|
18
|
+
readonly collectionName: string | undefined;
|
|
19
|
+
readonly modelFields: readonly string[];
|
|
20
|
+
readonly collectionFields: readonly string[];
|
|
21
|
+
}> {
|
|
22
|
+
override get message() {
|
|
23
|
+
return `Bucket registration for ${this.tableName}: model fields ${JSON.stringify(this.modelFields)} disagree with collection ${this.collectionName ?? "(missing)"} fields ${JSON.stringify(this.collectionFields)}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const validateRepositoryCollection = Effect.fnUntraced(function* (
|
|
28
|
+
fields: Schema.Struct.Fields,
|
|
29
|
+
options: { readonly tableName: string; readonly collection?: RepositoryCollection },
|
|
30
|
+
) {
|
|
31
|
+
const modelFields = declaredBuckets(fields)
|
|
32
|
+
.map(({ field }) => field)
|
|
33
|
+
.sort(Order.String);
|
|
34
|
+
const collectionFields = Object.keys(options.collection?.bucket ?? {}).sort(Order.String);
|
|
35
|
+
if (
|
|
36
|
+
(options.collection === undefined && modelFields.length === 0)
|
|
37
|
+
|| (options.collection?.name === options.tableName
|
|
38
|
+
&& modelFields.length === collectionFields.length
|
|
39
|
+
&& modelFields.every((field, index) => field === collectionFields[index]))
|
|
40
|
+
) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
return yield* Effect.fail(
|
|
44
|
+
new BucketRegistrationError({ collectionFields, collectionName: options.collection?.name, modelFields, tableName: options.tableName }),
|
|
45
|
+
);
|
|
46
|
+
});
|
package/src/testing.ts
CHANGED
|
@@ -76,8 +76,12 @@ export class PublishedKeysMismatch extends Data.TaggedError("PublishedKeysMismat
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
export function expectPublished(keys: readonly unknown[])
|
|
80
|
-
|
|
79
|
+
export function expectPublished(keys: readonly unknown[]): <A, E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
80
|
+
export function expectPublished<A>(
|
|
81
|
+
keys: (result: A) => readonly unknown[],
|
|
82
|
+
): <E, R>(body: Effect.Effect<A, E, R>) => Effect.Effect<A, E | PublishedKeysMismatch, R>;
|
|
83
|
+
export function expectPublished<A>(keys: readonly unknown[] | ((result: A) => readonly unknown[])) {
|
|
84
|
+
return Effect.fn("Changes.expectPublished")(function* <E, R>(body: Effect.Effect<A, E, R>) {
|
|
81
85
|
const observer = yield* ChangeObserver;
|
|
82
86
|
const actual = new Set<unknown>();
|
|
83
87
|
const result = yield* body.pipe(
|
|
@@ -90,7 +94,7 @@ export function expectPublished(keys: readonly unknown[]) {
|
|
|
90
94
|
return observer(event);
|
|
91
95
|
}),
|
|
92
96
|
);
|
|
93
|
-
const expected = new Set(keys);
|
|
97
|
+
const expected = new Set(typeof keys === "function" ? keys(result) : keys);
|
|
94
98
|
if (actual.size !== expected.size || [...expected].some((key) => !actual.has(key))) {
|
|
95
99
|
return yield* Effect.fail(new PublishedKeysMismatch({ actual: [...actual], expected: [...expected] }));
|
|
96
100
|
}
|