@effect-app/infra 4.0.0-beta.305 → 4.0.0-beta.307
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 +27 -0
- package/package.json +2 -2
- package/test/query.test.ts +124 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @effect-app/infra
|
|
2
2
|
|
|
3
|
+
## 4.0.0-beta.307
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 40585ca: Keep tag-aware `ProjectableFromDomain` for `projectComputed` only; restore loose key-presence guard for `project()` so view DTOs with reshaped fields keep typechecking.
|
|
8
|
+
- ad0ede6: Keep tag-aware `ProjectableGuard` on both `project()` and `projectComputed` (no loose key-only paper-over).
|
|
9
|
+
|
|
10
|
+
Hardening:
|
|
11
|
+
|
|
12
|
+
- single-literal tags allow dual same-tag domain variants (KeysOfUnion of matched members)
|
|
13
|
+
- multi-tag / string tags still require keys on every matched member
|
|
14
|
+
- optional projection/domain keys checked by key presence only (not optional-assignability)
|
|
15
|
+
|
|
16
|
+
Call sites must project domain-owned fields per tagged state.
|
|
17
|
+
|
|
18
|
+
- Updated dependencies [40585ca]
|
|
19
|
+
- Updated dependencies [ad0ede6]
|
|
20
|
+
- effect-app@4.0.0-beta.307
|
|
21
|
+
|
|
22
|
+
## 4.0.0-beta.306
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- 0fe925d: Tag-aware `ProjectableFromDomain` for `projectComputed`: projection Encoded fields must exist on the matching domain tagged state (or be computed). Prevents Overview.List SchemaErrors when cancel states omit workflow lock fields like `activeRequest`.
|
|
27
|
+
- Updated dependencies [0fe925d]
|
|
28
|
+
- effect-app@4.0.0-beta.306
|
|
29
|
+
|
|
3
30
|
## 4.0.0-beta.305
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-app/infra",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.307",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"proper-lockfile": "^4.1.2",
|
|
16
16
|
"pure-rand": "8.4.0",
|
|
17
17
|
"query-string": "^9.4.0",
|
|
18
|
-
"effect-app": "4.0.0-beta.
|
|
18
|
+
"effect-app": "4.0.0-beta.307"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@azure/cosmos": "^4.9.3",
|
package/test/query.test.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import * as Context from "effect-app/Context"
|
|
5
5
|
import * as Effect from "effect-app/Effect"
|
|
6
6
|
import * as Layer from "effect-app/Layer"
|
|
7
|
-
import { and, computed, count, expr, make, one, or, order, page, project, projectComputed, type QueryEnd, type QueryProjection, type QueryWhere, relation, toFilter, where } from "effect-app/Model/query"
|
|
7
|
+
import { and, computed, count, expr, make, one, or, order, page, project, type ProjectableFromDomain, projectComputed, type QueryEnd, type QueryProjection, type QueryWhere, relation, toFilter, where } from "effect-app/Model/query"
|
|
8
8
|
import { makeRepo } from "effect-app/Model/Repository"
|
|
9
9
|
import { RepositoryRegistryLive } from "effect-app/Model/Repository/Registry"
|
|
10
10
|
import * as Option from "effect-app/Option"
|
|
@@ -662,9 +662,11 @@ it("projectComputed constrains projection schema to encoded repo fields and comp
|
|
|
662
662
|
)
|
|
663
663
|
|
|
664
664
|
make<Encoded>().pipe(
|
|
665
|
+
// @ts-expect-error missingField is neither an encoded repo field nor a computed projection
|
|
665
666
|
projectComputed(S.Struct({ missingField: S.String }), computed({}))
|
|
666
667
|
)
|
|
667
668
|
|
|
669
|
+
// Key presence only (not Encoded value types) — name: number is still projectable.
|
|
668
670
|
make<Encoded>().pipe(
|
|
669
671
|
projectComputed(
|
|
670
672
|
S.Struct({ name: S.Number }),
|
|
@@ -672,6 +674,8 @@ it("projectComputed constrains projection schema to encoded repo fields and comp
|
|
|
672
674
|
)
|
|
673
675
|
)
|
|
674
676
|
|
|
677
|
+
// Computed field *value* types are not yet constrained against the expression
|
|
678
|
+
// result (only key presence). Keeping this as a documentation call site.
|
|
675
679
|
make<Encoded>().pipe(
|
|
676
680
|
projectComputed(
|
|
677
681
|
S.Struct({ itemCount: S.String }),
|
|
@@ -737,12 +741,131 @@ it("projectComputed supports union projection schemas", () => {
|
|
|
737
741
|
])
|
|
738
742
|
})
|
|
739
743
|
|
|
744
|
+
/**
|
|
745
|
+
* MACS-SCANNER-API-KS class of bug: domain cancel omits pack/print ownership
|
|
746
|
+
* (`activeRequest`); a hand-built overview projection that still requires it on
|
|
747
|
+
* every branch must fail at the `projectComputed` call site, not in prod decode.
|
|
748
|
+
*/
|
|
749
|
+
it("projectComputed rejects state-owned fields required on the wrong tagged branch", () => {
|
|
750
|
+
const domain = S.Union([
|
|
751
|
+
S.Struct({
|
|
752
|
+
_tag: S.Literal("packing"),
|
|
753
|
+
id: S.String,
|
|
754
|
+
activeRequest: S.NullOr(S.String),
|
|
755
|
+
items: S.Array(S.Struct({ articleId: S.String }))
|
|
756
|
+
}),
|
|
757
|
+
S.Struct({
|
|
758
|
+
_tag: S.Literal("cancelled"),
|
|
759
|
+
id: S.String,
|
|
760
|
+
items: S.Array(S.Struct({ articleId: S.String }))
|
|
761
|
+
})
|
|
762
|
+
])
|
|
763
|
+
type DomainEnc = S.Codec.Encoded<typeof domain>
|
|
764
|
+
|
|
765
|
+
// Good: activeRequest only on packing; cancel omits it; articleCount is computed.
|
|
766
|
+
make<DomainEnc>().pipe(
|
|
767
|
+
projectComputed(
|
|
768
|
+
S.Union([
|
|
769
|
+
S.Struct({
|
|
770
|
+
_tag: S.Literal("packing"),
|
|
771
|
+
id: S.String,
|
|
772
|
+
activeRequest: S.NullOr(S.String),
|
|
773
|
+
articleCount: S.Number
|
|
774
|
+
}),
|
|
775
|
+
S.Struct({
|
|
776
|
+
_tag: S.Literal("cancelled"),
|
|
777
|
+
id: S.String,
|
|
778
|
+
articleCount: S.Number
|
|
779
|
+
})
|
|
780
|
+
]),
|
|
781
|
+
computed({
|
|
782
|
+
articleCount: relation<DomainEnc>("items").count()
|
|
783
|
+
})
|
|
784
|
+
)
|
|
785
|
+
)
|
|
786
|
+
|
|
787
|
+
make<DomainEnc>().pipe(
|
|
788
|
+
projectComputed(
|
|
789
|
+
S.Union([
|
|
790
|
+
S.Struct({
|
|
791
|
+
_tag: S.Literal("packing"),
|
|
792
|
+
id: S.String,
|
|
793
|
+
activeRequest: S.NullOr(S.String),
|
|
794
|
+
articleCount: S.Number
|
|
795
|
+
}),
|
|
796
|
+
S.Struct({
|
|
797
|
+
_tag: S.Literal("cancelled"),
|
|
798
|
+
id: S.String,
|
|
799
|
+
activeRequest: S.NullOr(S.String),
|
|
800
|
+
articleCount: S.Number
|
|
801
|
+
})
|
|
802
|
+
]),
|
|
803
|
+
// @ts-expect-error activeRequest is not on domain cancelled — cannot project it there
|
|
804
|
+
computed({
|
|
805
|
+
articleCount: relation<DomainEnc>("items").count()
|
|
806
|
+
})
|
|
807
|
+
)
|
|
808
|
+
)
|
|
809
|
+
})
|
|
810
|
+
|
|
811
|
+
it("ProjectableFromDomain distributes over tagged union Encoded", () => {
|
|
812
|
+
type DomainEnc =
|
|
813
|
+
| { readonly _tag: "packing"; readonly id: string; readonly activeRequest: string | null }
|
|
814
|
+
| { readonly _tag: "cancelled"; readonly id: string }
|
|
815
|
+
|
|
816
|
+
type Good =
|
|
817
|
+
| { readonly _tag: "packing"; readonly id: string; readonly activeRequest: string | null; readonly n: number }
|
|
818
|
+
| { readonly _tag: "cancelled"; readonly id: string; readonly n: number }
|
|
819
|
+
|
|
820
|
+
type Bad =
|
|
821
|
+
| { readonly _tag: "packing"; readonly id: string; readonly activeRequest: string | null }
|
|
822
|
+
| { readonly _tag: "cancelled"; readonly id: string; readonly activeRequest: string | null }
|
|
823
|
+
|
|
824
|
+
type GoodCheck = ProjectableFromDomain<Good, DomainEnc, "n">
|
|
825
|
+
type BadCheck = ProjectableFromDomain<Bad, DomainEnc>
|
|
826
|
+
|
|
827
|
+
const _good: GoodCheck = undefined as unknown
|
|
828
|
+
// @ts-expect-error cancelled branch requires activeRequest not present on domain cancelled
|
|
829
|
+
const _bad: BadCheck = undefined as unknown
|
|
830
|
+
void _good
|
|
831
|
+
void _bad
|
|
832
|
+
})
|
|
833
|
+
|
|
834
|
+
it("ProjectableFromDomain allows dual same-tag domain variants", () => {
|
|
835
|
+
// EasyLife packing/closed: two domain shapes share `_tag` with different fields.
|
|
836
|
+
type DomainEnc =
|
|
837
|
+
| { readonly _tag: "packing"; readonly id: string; readonly packages: readonly string[] }
|
|
838
|
+
| { readonly _tag: "packing"; readonly id: string; readonly units: readonly string[] }
|
|
839
|
+
| { readonly _tag: "initial"; readonly id: string }
|
|
840
|
+
|
|
841
|
+
type Good =
|
|
842
|
+
| { readonly _tag: "packing"; readonly id: string; readonly packages: readonly string[] }
|
|
843
|
+
| { readonly _tag: "packing"; readonly id: string; readonly units: readonly string[] }
|
|
844
|
+
|
|
845
|
+
// Flat multi-tag + state-only field must still fail (batchId not on initial).
|
|
846
|
+
type BadFlat = {
|
|
847
|
+
readonly _tag: "packing" | "initial"
|
|
848
|
+
readonly id: string
|
|
849
|
+
readonly packages: readonly string[]
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
type GoodCheck = ProjectableFromDomain<Good, DomainEnc>
|
|
853
|
+
type BadFlatCheck = ProjectableFromDomain<BadFlat, DomainEnc>
|
|
854
|
+
|
|
855
|
+
const _good: GoodCheck = undefined as unknown
|
|
856
|
+
// @ts-expect-error packages is not on domain initial; multi-tag flat intersection rejects it
|
|
857
|
+
const _badFlat: BadFlatCheck = undefined as unknown
|
|
858
|
+
void _good
|
|
859
|
+
void _badFlat
|
|
860
|
+
})
|
|
861
|
+
|
|
740
862
|
it("projection schema with computed fields fails without computed map", () => {
|
|
741
863
|
const baseSchema = S.Struct({
|
|
742
864
|
id: S.String,
|
|
743
865
|
items: S.Array(S.Struct({ value: S.Number }))
|
|
744
866
|
})
|
|
745
867
|
const query = make<S.Codec.Encoded<typeof baseSchema>>().pipe(
|
|
868
|
+
// @ts-expect-error missing computed keys are rejected; also not projectable from domain alone
|
|
746
869
|
projectComputed(S.Struct({ pickedCount: S.NonNegativeInt }), computed({}))
|
|
747
870
|
)
|
|
748
871
|
expect(() => toFilter(query, baseSchema)).toThrowError("Missing computed projections for schema keys")
|