@effect-app/infra 4.0.0-beta.215 → 4.0.0-beta.217

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 (40) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/Model/Repository/internal/internal.d.ts +1 -1
  3. package/dist/Model/query/dsl.d.ts +41 -1
  4. package/dist/Model/query/dsl.d.ts.map +1 -1
  5. package/dist/Model/query/dsl.js +49 -1
  6. package/dist/Model/query/new-kid-interpreter.d.ts +28 -1
  7. package/dist/Model/query/new-kid-interpreter.d.ts.map +1 -1
  8. package/dist/Model/query/new-kid-interpreter.js +30 -1
  9. package/dist/QueueMaker/SQLQueue.d.ts +1 -1
  10. package/dist/QueueMaker/memQueue.d.ts +1 -1
  11. package/dist/QueueMaker/sbqueue.d.ts +1 -1
  12. package/dist/Store/Cosmos/query.d.ts +1 -1
  13. package/dist/Store/Cosmos/query.d.ts.map +1 -1
  14. package/dist/Store/Cosmos/query.js +30 -1
  15. package/dist/Store/Cosmos.d.ts +1 -1
  16. package/dist/Store/Memory.d.ts +1 -1
  17. package/dist/Store/Memory.d.ts.map +1 -1
  18. package/dist/Store/Memory.js +44 -1
  19. package/dist/Store/SQL/Pg.d.ts +1 -1
  20. package/dist/Store/SQL/query.d.ts +2 -2
  21. package/dist/Store/SQL/query.d.ts.map +1 -1
  22. package/dist/Store/SQL/query.js +54 -9
  23. package/dist/Store/SQL.d.ts +1 -1
  24. package/dist/Store/SQL.d.ts.map +1 -1
  25. package/dist/Store/SQL.js +3 -21
  26. package/dist/adapters/ServiceBus.d.ts +1 -1
  27. package/dist/adapters/logger.d.ts +1 -1
  28. package/dist/api/routing.d.ts +1 -1
  29. package/dist/otel.d.ts +1 -1
  30. package/package.json +3 -2
  31. package/src/Model/query/dsl.ts +99 -0
  32. package/src/Model/query/new-kid-interpreter.ts +62 -0
  33. package/src/Store/Cosmos/query.ts +33 -1
  34. package/src/Store/Memory.ts +40 -1
  35. package/src/Store/SQL/query.ts +58 -9
  36. package/src/Store/SQL.ts +3 -23
  37. package/test/dist/rawQuery.test.d.ts.map +1 -1
  38. package/test/query.test.ts +108 -3
  39. package/test/rawQuery.test.ts +24 -4
  40. package/test/sql-store.test.ts +166 -0
@@ -1,3 +1,4 @@
1
+ import { SqliteClient } from "@effect/sql-sqlite-node"
1
2
  import { describe, expect, it } from "@effect/vitest"
2
3
  import { Array, Config, Context, Effect, flow, Layer, ManagedRuntime, Redacted, References, Result, S, Struct } from "effect-app"
3
4
  import { LogLevels } from "effect-app/utils"
@@ -7,6 +8,7 @@ import { makeRepo } from "../src/Model/Repository/makeRepo.js"
7
8
  import { RepositoryRegistryLive } from "../src/Model/Repository/Registry.js"
8
9
  import { CosmosStoreLayer } from "../src/Store/Cosmos.js"
9
10
  import { MemoryStoreLive } from "../src/Store/Memory.js"
11
+ import { SQLiteStoreLayer } from "../src/Store/SQL.js"
10
12
 
11
13
  export const rt = ManagedRuntime.make(Layer.mergeAll(
12
14
  Layer.effect(
@@ -517,6 +519,22 @@ class OrderRepo extends Context.Service<OrderRepo>()(
517
519
  static readonly Test = this
518
520
  .layer
519
521
  .pipe(Layer.provide(Layer.merge(MemoryStoreLive, RepositoryRegistryLive)))
522
+
523
+ static readonly TestSqlite = this
524
+ .layer
525
+ .pipe(
526
+ Layer.provide(
527
+ Layer.merge(
528
+ SQLiteStoreLayer({
529
+ url: Redacted.make("sqlite://"),
530
+ prefix: "test_",
531
+ dbName: "test"
532
+ }),
533
+ RepositoryRegistryLive
534
+ )
535
+ ),
536
+ Layer.provide(SqliteClient.layer({ filename: ":memory:" }))
537
+ )
520
538
  }
521
539
 
522
540
  describe("scanner-style AllPickList computed projections", () => {
@@ -578,8 +596,9 @@ describe("scanner-style AllPickList computed projections", () => {
578
596
  })
579
597
  .pipe(setupRequestContextFromCurrent())
580
598
 
581
- it("works well in Memory", () =>
582
- test.pipe(Effect.provide(OrderRepo.Test), rt.runPromise))
599
+ it("works well in Memory", () => test.pipe(Effect.provide(OrderRepo.Test), rt.runPromise))
600
+
601
+ it("works well in SQLite", () => test.pipe(Effect.provide(OrderRepo.TestSqlite), rt.runPromise))
583
602
  })
584
603
 
585
604
  // Same but mimics the FULL controller projection: includes `items` array
@@ -626,8 +645,9 @@ describe("scanner-style AllPickList — items + computed combined", () => {
626
645
  })
627
646
  .pipe(setupRequestContextFromCurrent())
628
647
 
629
- it("works well in Memory", () =>
630
- test.pipe(Effect.provide(OrderRepo.Test), rt.runPromise))
648
+ it("works well in Memory", () => test.pipe(Effect.provide(OrderRepo.Test), rt.runPromise))
649
+
650
+ it("works well in SQLite", () => test.pipe(Effect.provide(OrderRepo.TestSqlite), rt.runPromise))
631
651
  })
632
652
 
633
653
  describe("removeByIds", () => {
@@ -345,6 +345,90 @@ describe("SQL query builder (SQLite dialect)", () => {
345
345
  expect(result.sql).toContain(`AS "totalWeight"`)
346
346
  })
347
347
 
348
+ it("computed relation-sum-expr projection (sqlite)", () => {
349
+ const result = buildWhereSQLQuery(
350
+ sqliteDialect,
351
+ "id",
352
+ [],
353
+ "users",
354
+ {},
355
+ [{
356
+ key: "totalWeighted",
357
+ computed: {
358
+ _tag: "relation-sum-expr",
359
+ path: "items",
360
+ expression: {
361
+ _tag: "mul",
362
+ left: { _tag: "field", field: "weight" },
363
+ right: { _tag: "field", field: "tradeUnit.amount" }
364
+ },
365
+ filter: []
366
+ }
367
+ }]
368
+ )
369
+ expect(result.sql).toContain(
370
+ `COALESCE(SUM((CAST(json_extract(_items.value, '$.weight') AS REAL) * CAST(json_extract(_items.value, '$.tradeUnit.amount') AS REAL))), 0)`
371
+ )
372
+ expect(result.sql).toContain(`AS "totalWeighted"`)
373
+ })
374
+
375
+ it("computed relation-sum-expr-by projection (sqlite)", () => {
376
+ const result = buildWhereSQLQuery(
377
+ sqliteDialect,
378
+ "id",
379
+ [],
380
+ "users",
381
+ {},
382
+ [{
383
+ key: "totalsByUnit",
384
+ computed: {
385
+ _tag: "relation-sum-expr-by",
386
+ path: "items",
387
+ expression: {
388
+ _tag: "mul",
389
+ left: { _tag: "field", field: "weight" },
390
+ right: { _tag: "field", field: "tradeUnit.amount" }
391
+ },
392
+ unit: "tradeUnit.unit",
393
+ filter: []
394
+ }
395
+ }]
396
+ )
397
+ expect(result.sql).toContain(`json_group_array(json_object('unit', __unit, 'total', __total))`)
398
+ expect(result.sql).toContain(`GROUP BY json_extract(_items.value, '$.tradeUnit.unit')`)
399
+ expect(result.sql).toContain(`AS "totalsByUnit"`)
400
+ })
401
+
402
+ it("computed relation-sum-expr-normalized projection (sqlite)", () => {
403
+ const result = buildWhereSQLQuery(
404
+ sqliteDialect,
405
+ "id",
406
+ [],
407
+ "users",
408
+ {},
409
+ [{
410
+ key: "totalKg",
411
+ computed: {
412
+ _tag: "relation-sum-expr-normalized",
413
+ path: "items",
414
+ expression: {
415
+ _tag: "mul",
416
+ left: { _tag: "field", field: "weight" },
417
+ right: { _tag: "field", field: "tradeUnit.amount" }
418
+ },
419
+ unit: "tradeUnit.unit",
420
+ toBase: "kg",
421
+ factors: { g: 0.001 },
422
+ filter: []
423
+ }
424
+ }]
425
+ )
426
+ expect(result.sql).toContain(
427
+ `CASE json_extract(_items.value, '$.tradeUnit.unit') WHEN 'kg' THEN 1 WHEN 'g' THEN 0.001 ELSE NULL END`
428
+ )
429
+ expect(result.sql).toContain(`AS "totalKg"`)
430
+ })
431
+
348
432
  it("computed relation-collect (non-distinct) projection (sqlite)", () => {
349
433
  const result = buildWhereSQLQuery(
350
434
  sqliteDialect,
@@ -515,6 +599,88 @@ describe("SQL query builder (PostgreSQL dialect)", () => {
515
599
  expect(result.sql).toContain(`AS "totalWeight"`)
516
600
  })
517
601
 
602
+ it("computed relation-sum-expr (pg)", () => {
603
+ const result = buildWhereSQLQuery(
604
+ pgDialect,
605
+ "id",
606
+ [],
607
+ "users",
608
+ {},
609
+ [{
610
+ key: "totalWeighted",
611
+ computed: {
612
+ _tag: "relation-sum-expr",
613
+ path: "items",
614
+ expression: {
615
+ _tag: "mul",
616
+ left: { _tag: "field", field: "weight" },
617
+ right: { _tag: "field", field: "tradeUnit.amount" }
618
+ },
619
+ filter: []
620
+ }
621
+ }]
622
+ )
623
+ expect(result.sql).toContain(
624
+ `COALESCE(SUM(((_items->>'weight')::numeric * (_items->'tradeUnit'->>'amount')::numeric)), 0)`
625
+ )
626
+ expect(result.sql).toContain(`AS "totalWeighted"`)
627
+ })
628
+
629
+ it("computed relation-sum-expr-by (pg)", () => {
630
+ const result = buildWhereSQLQuery(
631
+ pgDialect,
632
+ "id",
633
+ [],
634
+ "users",
635
+ {},
636
+ [{
637
+ key: "totalsByUnit",
638
+ computed: {
639
+ _tag: "relation-sum-expr-by",
640
+ path: "items",
641
+ expression: {
642
+ _tag: "mul",
643
+ left: { _tag: "field", field: "weight" },
644
+ right: { _tag: "field", field: "tradeUnit.amount" }
645
+ },
646
+ unit: "tradeUnit.unit",
647
+ filter: []
648
+ }
649
+ }]
650
+ )
651
+ expect(result.sql).toContain(`jsonb_agg(jsonb_build_object('unit', __unit, 'total', __total))`)
652
+ expect(result.sql).toContain(`GROUP BY _items->'tradeUnit'->>'unit'`)
653
+ expect(result.sql).toContain(`AS "totalsByUnit"`)
654
+ })
655
+
656
+ it("computed relation-sum-expr-normalized (pg)", () => {
657
+ const result = buildWhereSQLQuery(
658
+ pgDialect,
659
+ "id",
660
+ [],
661
+ "users",
662
+ {},
663
+ [{
664
+ key: "totalKg",
665
+ computed: {
666
+ _tag: "relation-sum-expr-normalized",
667
+ path: "items",
668
+ expression: {
669
+ _tag: "mul",
670
+ left: { _tag: "field", field: "weight" },
671
+ right: { _tag: "field", field: "tradeUnit.amount" }
672
+ },
673
+ unit: "tradeUnit.unit",
674
+ toBase: "kg",
675
+ factors: { g: 0.001 },
676
+ filter: []
677
+ }
678
+ }]
679
+ )
680
+ expect(result.sql).toContain(`CASE _items->'tradeUnit'->>'unit' WHEN 'kg' THEN 1 WHEN 'g' THEN 0.001 ELSE NULL END`)
681
+ expect(result.sql).toContain(`AS "totalKg"`)
682
+ })
683
+
518
684
  it("computed relation-collect (pg jsonb_agg)", () => {
519
685
  const result = buildWhereSQLQuery(
520
686
  pgDialect,