@effect-app/infra 4.0.0-beta.305 → 4.0.0-beta.306

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @effect-app/infra
2
2
 
3
+ ## 4.0.0-beta.306
4
+
5
+ ### Patch Changes
6
+
7
+ - 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`.
8
+ - Updated dependencies [0fe925d]
9
+ - effect-app@4.0.0-beta.306
10
+
3
11
  ## 4.0.0-beta.305
4
12
 
5
13
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-app/infra",
3
- "version": "4.0.0-beta.305",
3
+ "version": "4.0.0-beta.306",
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.305"
18
+ "effect-app": "4.0.0-beta.306"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@azure/cosmos": "^4.9.3",
@@ -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,103 @@ 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
+
740
834
  it("projection schema with computed fields fails without computed map", () => {
741
835
  const baseSchema = S.Struct({
742
836
  id: S.String,
743
837
  items: S.Array(S.Struct({ value: S.Number }))
744
838
  })
745
839
  const query = make<S.Codec.Encoded<typeof baseSchema>>().pipe(
840
+ // @ts-expect-error missing computed keys are rejected; also not projectable from domain alone
746
841
  projectComputed(S.Struct({ pickedCount: S.NonNegativeInt }), computed({}))
747
842
  )
748
843
  expect(() => toFilter(query, baseSchema)).toThrowError("Missing computed projections for schema keys")