@effect-app/infra 0.48.0 → 0.49.1
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 +21 -0
- package/_cjs/_ext/Array.cjs.map +1 -1
- package/_cjs/api/defaultErrorHandler.cjs.map +1 -1
- package/_cjs/api/express/makeJsonSchema.cjs +2 -2
- package/_cjs/api/express/makeJsonSchema.cjs.map +1 -1
- package/_cjs/api/express/schema/jwt.cjs.map +1 -1
- package/_cjs/api/express/schema/requestHandler.cjs.map +1 -1
- package/_cjs/api/express/schema/routing.cjs.map +1 -1
- package/_cjs/api/reportError.cjs.map +1 -1
- package/_cjs/api/routing.cjs.map +1 -1
- package/_cjs/api/setupRequest.cjs.map +1 -1
- package/_cjs/api/writeDocs.cjs.map +1 -1
- package/_cjs/rateLimit.cjs.map +1 -1
- package/_cjs/services/Emailer/Sendgrid.cjs.map +1 -1
- package/_cjs/services/Emailer/fake.cjs.map +1 -1
- package/_cjs/services/Operations/live.cjs.map +1 -1
- package/_cjs/services/Operations/service.cjs.map +1 -1
- package/_cjs/services/QueueMaker/errors.cjs.map +1 -1
- package/_cjs/services/QueueMaker/memQueue.cjs.map +1 -1
- package/_cjs/services/QueueMaker/sbqueue.cjs.map +1 -1
- package/_cjs/services/Repository.cjs +8 -8
- package/_cjs/services/Repository.cjs.map +1 -1
- package/_cjs/services/RepositoryBase.cjs +13 -13
- package/_cjs/services/RepositoryBase.cjs.map +1 -1
- package/_cjs/services/RequestContextContainer.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos.cjs +9 -9
- package/_cjs/services/Store/Cosmos.cjs.map +1 -1
- package/_cjs/services/Store/Cosmos.test.cjs.map +1 -1
- package/_cjs/services/Store/Disk.cjs.map +1 -1
- package/_cjs/services/Store/Memory.cjs +42 -42
- package/_cjs/services/Store/Memory.cjs.map +1 -1
- package/_cjs/services/Store/Redis.cjs +13 -13
- package/_cjs/services/Store/Redis.cjs.map +1 -1
- package/_cjs/services/Store/codeFilter.test.cjs.map +1 -1
- package/_cjs/services/Store/index.cjs.map +1 -1
- package/_cjs/services/Store/service.cjs.map +1 -1
- package/_cjs/services/Store/utils.cjs +2 -3
- package/_cjs/services/Store/utils.cjs.map +1 -1
- package/_cjs/services/simpledb/cosmosdb.cjs +12 -4
- package/_cjs/services/simpledb/cosmosdb.cjs.map +1 -1
- package/_cjs/services/simpledb/diskdb.cjs.map +1 -1
- package/_cjs/services/simpledb/memdb.cjs.map +1 -1
- package/_cjs/services/simpledb/mongodb.cjs +15 -5
- package/_cjs/services/simpledb/mongodb.cjs.map +1 -1
- package/_cjs/services/simpledb/redisdb.cjs +13 -7
- package/_cjs/services/simpledb/redisdb.cjs.map +1 -1
- package/_cjs/services/simpledb/simpledb.cjs.map +1 -1
- package/_src/_ext/Array.ts +3 -2
- package/_src/api/defaultErrorHandler.ts +14 -12
- package/_src/api/express/makeJsonSchema.ts +6 -5
- package/_src/api/express/schema/jwt.ts +1 -1
- package/_src/api/express/schema/requestHandler.ts +112 -100
- package/_src/api/express/schema/routing.ts +61 -55
- package/_src/api/reportError.ts +16 -12
- package/_src/api/routing.ts +157 -135
- package/_src/api/setupRequest.ts +3 -1
- package/_src/api/writeDocs.ts +4 -3
- package/_src/rateLimit.ts +21 -14
- package/_src/services/Emailer/Sendgrid.ts +11 -10
- package/_src/services/Emailer/fake.ts +2 -1
- package/_src/services/Operations/live.ts +18 -12
- package/_src/services/Operations/service.ts +26 -17
- package/_src/services/QueueMaker/errors.ts +7 -6
- package/_src/services/QueueMaker/memQueue.ts +13 -11
- package/_src/services/QueueMaker/sbqueue.ts +16 -14
- package/_src/services/Repository.ts +53 -51
- package/_src/services/RepositoryBase.ts +33 -28
- package/_src/services/RequestContextContainer.ts +4 -3
- package/_src/services/Store/Cosmos.test.ts +31 -29
- package/_src/services/Store/Cosmos.ts +203 -180
- package/_src/services/Store/Disk.ts +19 -18
- package/_src/services/Store/Memory.ts +37 -32
- package/_src/services/Store/Redis.ts +31 -27
- package/_src/services/Store/codeFilter.test.ts +26 -16
- package/_src/services/Store/index.ts +26 -24
- package/_src/services/Store/service.ts +5 -5
- package/_src/services/Store/utils.ts +27 -24
- package/_src/services/simpledb/cosmosdb.ts +61 -51
- package/_src/services/simpledb/diskdb.ts +38 -31
- package/_src/services/simpledb/memdb.ts +25 -21
- package/_src/services/simpledb/mongodb.ts +40 -35
- package/_src/services/simpledb/redisdb.ts +66 -55
- package/_src/services/simpledb/simpledb.ts +32 -30
- package/dist/_ext/Array.d.ts.map +1 -1
- package/dist/_ext/Array.js +2 -2
- package/dist/api/defaultErrorHandler.d.ts.map +1 -1
- package/dist/api/defaultErrorHandler.js +5 -5
- package/dist/api/express/makeJsonSchema.d.ts +0 -1
- package/dist/api/express/makeJsonSchema.d.ts.map +1 -1
- package/dist/api/express/makeJsonSchema.js +4 -4
- package/dist/api/express/schema/jwt.js +2 -2
- package/dist/api/express/schema/requestHandler.d.ts.map +1 -1
- package/dist/api/express/schema/requestHandler.js +17 -17
- package/dist/api/express/schema/routing.d.ts.map +1 -1
- package/dist/api/express/schema/routing.js +13 -11
- package/dist/api/reportError.d.ts.map +1 -1
- package/dist/api/reportError.js +6 -6
- package/dist/api/routing.d.ts.map +1 -1
- package/dist/api/routing.js +29 -25
- package/dist/api/setupRequest.d.ts.map +1 -1
- package/dist/api/setupRequest.js +2 -2
- package/dist/api/writeDocs.d.ts.map +1 -1
- package/dist/api/writeDocs.js +5 -4
- package/dist/rateLimit.d.ts +4 -4
- package/dist/rateLimit.d.ts.map +1 -1
- package/dist/rateLimit.js +5 -4
- package/dist/services/Emailer/Sendgrid.d.ts.map +1 -1
- package/dist/services/Emailer/Sendgrid.js +9 -9
- package/dist/services/Emailer/fake.d.ts.map +1 -1
- package/dist/services/Emailer/fake.js +1 -1
- package/dist/services/Operations/live.d.ts.map +1 -1
- package/dist/services/Operations/live.js +11 -8
- package/dist/services/Operations/service.d.ts.map +1 -1
- package/dist/services/Operations/service.js +10 -4
- package/dist/services/QueueMaker/errors.d.ts.map +1 -1
- package/dist/services/QueueMaker/errors.js +5 -5
- package/dist/services/QueueMaker/memQueue.d.ts +1 -1
- package/dist/services/QueueMaker/memQueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/memQueue.js +5 -4
- package/dist/services/QueueMaker/sbqueue.d.ts.map +1 -1
- package/dist/services/QueueMaker/sbqueue.js +5 -5
- package/dist/services/Repository.d.ts +34 -35
- package/dist/services/Repository.d.ts.map +1 -1
- package/dist/services/Repository.js +16 -16
- package/dist/services/RepositoryBase.d.ts +4 -4
- package/dist/services/RepositoryBase.d.ts.map +1 -1
- package/dist/services/RepositoryBase.js +25 -22
- package/dist/services/RequestContextContainer.d.ts.map +1 -1
- package/dist/services/RequestContextContainer.js +3 -3
- package/dist/services/Store/Cosmos.d.ts +3 -3
- package/dist/services/Store/Cosmos.d.ts.map +1 -1
- package/dist/services/Store/Cosmos.js +53 -39
- package/dist/services/Store/Disk.d.ts.map +1 -1
- package/dist/services/Store/Disk.js +18 -18
- package/dist/services/Store/Memory.d.ts +2 -3
- package/dist/services/Store/Memory.d.ts.map +1 -1
- package/dist/services/Store/Memory.js +44 -44
- package/dist/services/Store/Redis.d.ts +4 -4
- package/dist/services/Store/Redis.d.ts.map +1 -1
- package/dist/services/Store/Redis.js +19 -17
- package/dist/services/Store/index.d.ts.map +1 -1
- package/dist/services/Store/index.js +4 -4
- package/dist/services/Store/service.d.ts +4 -5
- package/dist/services/Store/service.d.ts.map +1 -1
- package/dist/services/Store/service.js +3 -3
- package/dist/services/Store/utils.d.ts +2 -2
- package/dist/services/Store/utils.d.ts.map +1 -1
- package/dist/services/Store/utils.js +16 -14
- package/dist/services/simpledb/cosmosdb.d.ts.map +1 -1
- package/dist/services/simpledb/cosmosdb.js +16 -12
- package/dist/services/simpledb/diskdb.d.ts.map +1 -1
- package/dist/services/simpledb/diskdb.js +15 -15
- package/dist/services/simpledb/memdb.d.ts.map +1 -1
- package/dist/services/simpledb/memdb.js +6 -6
- package/dist/services/simpledb/mongodb.d.ts +5 -5
- package/dist/services/simpledb/mongodb.d.ts.map +1 -1
- package/dist/services/simpledb/mongodb.js +9 -9
- package/dist/services/simpledb/redisdb.d.ts +4 -4
- package/dist/services/simpledb/redisdb.d.ts.map +1 -1
- package/dist/services/simpledb/redisdb.js +18 -18
- package/dist/services/simpledb/simpledb.d.ts.map +1 -1
- package/dist/services/simpledb/simpledb.js +9 -9
- package/package.json +7 -7
|
@@ -15,7 +15,7 @@ export function somethingsWhere(
|
|
|
15
15
|
) => Where | [Where, ...Where[]],
|
|
16
16
|
mode?: "or" | "and"
|
|
17
17
|
) {
|
|
18
|
-
return makeSomethingFilter_(f => {
|
|
18
|
+
return makeSomethingFilter_((f) => {
|
|
19
19
|
const m = makeWhere ? makeWhere(f) : []
|
|
20
20
|
return ({
|
|
21
21
|
mode,
|
|
@@ -39,52 +39,54 @@ type Something = {
|
|
|
39
39
|
|
|
40
40
|
test("works", () => {
|
|
41
41
|
expect(buildWhereCosmosQuery(
|
|
42
|
-
somethingsWhere(_ => _("b", _ => "b2")),
|
|
42
|
+
somethingsWhere((_) => _("b", (_) => "b2")),
|
|
43
43
|
"Somethings",
|
|
44
44
|
"importedMarkerId",
|
|
45
45
|
undefined,
|
|
46
46
|
10
|
|
47
|
-
))
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
))
|
|
48
|
+
.toEqual({
|
|
49
|
+
"parameters": [
|
|
50
|
+
{
|
|
51
|
+
"name": "@id",
|
|
52
|
+
"value": "importedMarkerId"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "@v0",
|
|
56
|
+
"value": "b2"
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"query": `
|
|
59
60
|
SELECT f
|
|
60
61
|
FROM Somethings AS f
|
|
61
62
|
|
|
62
63
|
WHERE f.id != @id AND LOWER(f.b) = LOWER(@v0)
|
|
63
64
|
OFFSET 0 LIMIT 10`
|
|
64
|
-
|
|
65
|
+
})
|
|
65
66
|
|
|
66
67
|
expect(buildWhereCosmosQuery(
|
|
67
|
-
somethingsWhere(_ => _("d.-1.a", _ => _.$isnt("a2"))),
|
|
68
|
+
somethingsWhere((_) => _("d.-1.a", (_) => _.$isnt("a2"))),
|
|
68
69
|
"Somethings",
|
|
69
70
|
"importedMarkerId",
|
|
70
71
|
undefined,
|
|
71
72
|
10
|
|
72
|
-
))
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
))
|
|
74
|
+
.toEqual({
|
|
75
|
+
"parameters": [
|
|
76
|
+
{
|
|
77
|
+
"name": "@id",
|
|
78
|
+
"value": "importedMarkerId"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"name": "@v0",
|
|
82
|
+
"value": "a2"
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
"query": `
|
|
84
86
|
SELECT f
|
|
85
87
|
FROM Somethings AS f
|
|
86
88
|
JOIN d IN f.d
|
|
87
89
|
WHERE f.id != @id AND LOWER(d.a) <> LOWER(@v0)
|
|
88
90
|
OFFSET 0 LIMIT 10`
|
|
89
|
-
|
|
91
|
+
})
|
|
90
92
|
})
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import { OptimisticConcurrencyException } from "../../errors.js"
|
|
6
|
-
|
|
3
|
+
import { CosmosClient } from "@effect-app/infra-adapters/cosmos-client"
|
|
7
4
|
import { omit } from "@effect-app/prelude/utils"
|
|
8
|
-
|
|
5
|
+
import { OptimisticConcurrencyException } from "../../errors.js"
|
|
9
6
|
import type {
|
|
10
7
|
Filter,
|
|
11
8
|
FilterJoinSelect,
|
|
@@ -23,7 +20,7 @@ import { StoreMaker } from "./service.js"
|
|
|
23
20
|
// TODO: Retry operation when running into RU limit.
|
|
24
21
|
export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
25
22
|
return Effect.gen(function*($) {
|
|
26
|
-
const { db } = yield* $(CosmosClient
|
|
23
|
+
const { db } = yield* $(CosmosClient)
|
|
27
24
|
return {
|
|
28
25
|
make: <Id extends string, PM extends PersistenceModelType<Id>>(
|
|
29
26
|
name: string,
|
|
@@ -48,139 +45,146 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
48
45
|
const importedMarkerId = containerId
|
|
49
46
|
|
|
50
47
|
const bulkSet = (items: NonEmptyReadonlyArray<PM>) =>
|
|
51
|
-
Effect
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
()
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
48
|
+
Effect
|
|
49
|
+
.gen(function*($) {
|
|
50
|
+
// TODO: disable batching if need atomicity
|
|
51
|
+
// we delay and batch to keep low amount of RUs
|
|
52
|
+
const b = [...items].map(
|
|
53
|
+
(x) =>
|
|
54
|
+
[
|
|
55
|
+
x,
|
|
56
|
+
Option.fromNullable(x._etag).match(
|
|
57
|
+
() => ({
|
|
58
|
+
operationType: "Create" as const,
|
|
59
|
+
resourceBody: {
|
|
60
|
+
...omit(x, "_etag"),
|
|
61
|
+
_partitionKey: config?.partitionValue(x)
|
|
62
|
+
} as any,
|
|
63
|
+
partitionKey: config?.partitionValue(x)
|
|
64
|
+
}),
|
|
65
|
+
(eTag) => ({
|
|
66
|
+
operationType: "Replace" as const,
|
|
67
|
+
id: x.id,
|
|
68
|
+
resourceBody: {
|
|
69
|
+
...omit(x, "_etag"),
|
|
70
|
+
_partitionKey: config?.partitionValue(x)
|
|
71
|
+
} as any,
|
|
72
|
+
ifMatch: eTag,
|
|
73
|
+
partitionKey: config?.partitionValue(x)
|
|
74
|
+
})
|
|
75
|
+
)
|
|
76
|
+
] as const
|
|
77
|
+
)
|
|
78
|
+
const batches = b.chunk(config?.maxBulkSize ?? 10).toReadonlyArray
|
|
81
79
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
80
|
+
const batchResult = yield* $(
|
|
81
|
+
batches
|
|
82
|
+
.map((x, i) => [i, x] as const)
|
|
83
|
+
.forEachEffect(
|
|
84
|
+
([i, batch]) =>
|
|
85
|
+
Effect
|
|
86
|
+
.promise(() => bulk(batch.map(([, op]) => op)))
|
|
87
|
+
.delay(Duration.makeMillis(i === 0 ? 0 : 1100))
|
|
88
|
+
.flatMap((responses) =>
|
|
89
|
+
Effect.gen(function*($) {
|
|
90
|
+
const r = responses.find((x) => x.statusCode === 412 || x.statusCode === 404)
|
|
91
|
+
if (r) {
|
|
92
|
+
return yield* $(
|
|
93
|
+
Effect.fail(
|
|
94
|
+
new OptimisticConcurrencyException(
|
|
95
|
+
name,
|
|
96
|
+
JSON.stringify(r.resourceBody?.["id"])
|
|
97
|
+
)
|
|
97
98
|
)
|
|
98
99
|
)
|
|
100
|
+
}
|
|
101
|
+
const r2 = responses.find(
|
|
102
|
+
(x) => x.statusCode > 299 || x.statusCode < 200
|
|
99
103
|
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Effect.die(
|
|
107
|
-
new CosmosDbOperationError(
|
|
108
|
-
"not able to update record: " + r2.statusCode
|
|
104
|
+
if (r2) {
|
|
105
|
+
return yield* $(
|
|
106
|
+
Effect.die(
|
|
107
|
+
new CosmosDbOperationError(
|
|
108
|
+
"not able to update record: " + r2.statusCode
|
|
109
|
+
)
|
|
109
110
|
)
|
|
110
111
|
)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
112
|
+
}
|
|
113
|
+
return batch.map(([e], i) => ({
|
|
114
|
+
...e,
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
116
|
+
_etag: responses[i]!.eTag
|
|
117
|
+
}))
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
return batchResult.flat() as unknown as NonEmptyReadonlyArray<PM>
|
|
123
|
+
})
|
|
124
|
+
.instrument("cosmos.bulkSet")
|
|
124
125
|
.logAnnotate("cosmos.db", containerId)
|
|
125
126
|
|
|
126
127
|
const batchSet = (items: NonEmptyReadonlyArray<PM>) => {
|
|
127
|
-
return Effect
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
128
|
+
return Effect
|
|
129
|
+
.suspend(() => {
|
|
130
|
+
const batch = [...items].map(
|
|
131
|
+
(x) =>
|
|
132
|
+
[
|
|
133
|
+
x,
|
|
134
|
+
Option.fromNullable(x._etag).match(
|
|
135
|
+
() => ({
|
|
136
|
+
operationType: "Create" as const,
|
|
137
|
+
resourceBody: {
|
|
138
|
+
...omit(x, "_etag"),
|
|
139
|
+
_partitionKey: config?.partitionValue(x)
|
|
140
|
+
} as any
|
|
141
|
+
}),
|
|
142
|
+
(eTag) => ({
|
|
143
|
+
operationType: "Replace" as const,
|
|
144
|
+
id: x.id,
|
|
145
|
+
resourceBody: {
|
|
146
|
+
...omit(x, "_etag"),
|
|
147
|
+
_partitionKey: config?.partitionValue(x)
|
|
148
|
+
} as any,
|
|
149
|
+
ifMatch: eTag
|
|
150
|
+
})
|
|
151
|
+
)
|
|
152
|
+
] as const
|
|
153
|
+
)
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
const ex = batch.map(([, c]) => c)
|
|
156
|
+
|
|
157
|
+
return Effect
|
|
158
|
+
.promise(() => execBatch(ex, ex[0]?.resourceBody._partitionKey))
|
|
159
|
+
.flatMap((x) =>
|
|
160
|
+
Effect.gen(function*($) {
|
|
161
|
+
const result = x.result ?? []
|
|
162
|
+
const firstFailed = result.find(
|
|
163
|
+
(x: any) => x.statusCode > 299 || x.statusCode < 200
|
|
164
|
+
)
|
|
165
|
+
if (firstFailed) {
|
|
166
|
+
const code = firstFailed.statusCode ?? 0
|
|
167
|
+
if (code === 412 || code === 404) {
|
|
168
|
+
return yield* $(
|
|
169
|
+
Effect.fail(new OptimisticConcurrencyException(name, "batch"))
|
|
170
|
+
)
|
|
171
|
+
}
|
|
154
172
|
|
|
155
|
-
return Effect.promise(() => execBatch(ex, ex[0]?.resourceBody._partitionKey))
|
|
156
|
-
.flatMap(x =>
|
|
157
|
-
Effect.gen(function*($) {
|
|
158
|
-
const result = x.result ?? []
|
|
159
|
-
const firstFailed = result.find(
|
|
160
|
-
(x: any) => x.statusCode > 299 || x.statusCode < 200
|
|
161
|
-
)
|
|
162
|
-
if (firstFailed) {
|
|
163
|
-
const code = firstFailed.statusCode ?? 0
|
|
164
|
-
if (code === 412 || code === 404) {
|
|
165
173
|
return yield* $(
|
|
166
|
-
Effect.
|
|
174
|
+
Effect.die(
|
|
175
|
+
new CosmosDbOperationError("not able to update record: " + code)
|
|
176
|
+
)
|
|
167
177
|
)
|
|
168
178
|
}
|
|
169
179
|
|
|
170
|
-
return
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
...e,
|
|
179
|
-
_etag: result[i]?.eTag
|
|
180
|
-
})) as unknown as NonEmptyReadonlyArray<PM>
|
|
181
|
-
})
|
|
182
|
-
)
|
|
183
|
-
}).instrument("cosmos.batchSet")
|
|
180
|
+
return batch.map(([e], i) => ({
|
|
181
|
+
...e,
|
|
182
|
+
_etag: result[i]?.eTag
|
|
183
|
+
})) as unknown as NonEmptyReadonlyArray<PM>
|
|
184
|
+
})
|
|
185
|
+
)
|
|
186
|
+
})
|
|
187
|
+
.instrument("cosmos.batchSet")
|
|
184
188
|
.logAnnotate("cosmos.db", containerId)
|
|
185
189
|
}
|
|
186
190
|
|
|
@@ -189,44 +193,49 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
189
193
|
query: `SELECT * FROM ${name} f WHERE f.id != @id`,
|
|
190
194
|
parameters: [{ name: "@id", value: importedMarkerId }]
|
|
191
195
|
})
|
|
192
|
-
.tap(q => logQuery(q))
|
|
193
|
-
.flatMap(q =>
|
|
196
|
+
.tap((q) => logQuery(q))
|
|
197
|
+
.flatMap((q) =>
|
|
194
198
|
Effect.promise(() =>
|
|
195
|
-
container
|
|
199
|
+
container
|
|
200
|
+
.items
|
|
196
201
|
.query<PM>(q)
|
|
197
202
|
.fetchAll()
|
|
198
|
-
.then(({ resources }) => resources
|
|
203
|
+
.then(({ resources }) => resources)
|
|
199
204
|
)
|
|
200
|
-
)
|
|
205
|
+
)
|
|
206
|
+
.instrument("cosmos.all")
|
|
201
207
|
.logAnnotate("cosmos.db", containerId),
|
|
202
208
|
filterJoinSelect: <T extends object>(
|
|
203
209
|
filter: FilterJoinSelect,
|
|
204
210
|
cursor?: { skip?: number; limit?: number }
|
|
205
211
|
) =>
|
|
206
|
-
filter
|
|
207
|
-
.
|
|
212
|
+
filter
|
|
213
|
+
.keys
|
|
214
|
+
.forEachEffect((k) =>
|
|
208
215
|
Effect(buildFilterJoinSelectCosmosQuery(filter, k, name, cursor?.skip, cursor?.limit))
|
|
209
|
-
.tap(q => logQuery(q))
|
|
210
|
-
.flatMap(q =>
|
|
216
|
+
.tap((q) => logQuery(q))
|
|
217
|
+
.flatMap((q) =>
|
|
211
218
|
Effect.promise(() =>
|
|
212
|
-
container
|
|
219
|
+
container
|
|
220
|
+
.items
|
|
213
221
|
.query<T>(q)
|
|
214
222
|
.fetchAll()
|
|
215
|
-
.then(({ resources }) => resources
|
|
223
|
+
.then(({ resources }) => resources)
|
|
216
224
|
)
|
|
217
225
|
)
|
|
218
226
|
)
|
|
219
|
-
.map(a => {
|
|
227
|
+
.map((a) => {
|
|
220
228
|
const v = a
|
|
221
|
-
.flatMap(_ => _)
|
|
222
|
-
.map(x =>
|
|
229
|
+
.flatMap((_) => _)
|
|
230
|
+
.map((x) =>
|
|
223
231
|
spread(
|
|
224
232
|
x,
|
|
225
233
|
({ r, ...rest }: any) => ({ ...rest, ...r } as T & { _rootId: string })
|
|
226
234
|
)
|
|
227
235
|
)
|
|
228
|
-
return
|
|
229
|
-
})
|
|
236
|
+
return v
|
|
237
|
+
})
|
|
238
|
+
.instrument("cosmos.filterJoinSelect")
|
|
230
239
|
.logAnnotate("cosmos.db", containerId),
|
|
231
240
|
/**
|
|
232
241
|
* May return duplicate results for "join_find", when matching more than once.
|
|
@@ -238,43 +247,51 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
238
247
|
// This is a problem if one of the multiple joined arrays can be empty!
|
|
239
248
|
// https://stackoverflow.com/questions/60320780/azure-cosmosdb-sql-join-not-returning-results-when-the-child-contains-empty-arra
|
|
240
249
|
// so we use multiple queries instead.
|
|
241
|
-
? filter
|
|
242
|
-
.
|
|
250
|
+
? filter
|
|
251
|
+
.keys
|
|
252
|
+
.forEachEffect((k) =>
|
|
243
253
|
Effect(buildFindJoinCosmosQuery(filter, k, name, skip, limit))
|
|
244
|
-
.tap(q => logQuery(q))
|
|
245
|
-
.flatMap(q =>
|
|
254
|
+
.tap((q) => logQuery(q))
|
|
255
|
+
.flatMap((q) =>
|
|
246
256
|
Effect.promise(() =>
|
|
247
|
-
container
|
|
257
|
+
container
|
|
258
|
+
.items
|
|
248
259
|
.query<PM>(q)
|
|
249
260
|
.fetchAll()
|
|
250
|
-
.then(({ resources }) => resources
|
|
261
|
+
.then(({ resources }) => resources)
|
|
251
262
|
)
|
|
252
263
|
)
|
|
253
264
|
)
|
|
254
|
-
.map(_ => _.flatMap(_ => _))
|
|
265
|
+
.map((_) => _.flatMap((_) => _))
|
|
255
266
|
: Effect(buildCosmosQuery(filter, name, importedMarkerId, skip, limit))
|
|
256
|
-
.tap(q => logQuery(q))
|
|
257
|
-
.flatMap(q =>
|
|
267
|
+
.tap((q) => logQuery(q))
|
|
268
|
+
.flatMap((q) =>
|
|
258
269
|
Effect.promise(() =>
|
|
259
|
-
container
|
|
260
|
-
|
|
261
|
-
|
|
270
|
+
container
|
|
271
|
+
.items
|
|
272
|
+
.query<{ f: PM }>(
|
|
273
|
+
q
|
|
274
|
+
)
|
|
262
275
|
.fetchAll()
|
|
263
|
-
.then(({ resources }) => resources.map(_ => _.f)
|
|
276
|
+
.then(({ resources }) => resources.map((_) => _.f))
|
|
264
277
|
)
|
|
265
|
-
))
|
|
278
|
+
))
|
|
279
|
+
.instrument("cosmos.filter")
|
|
266
280
|
.logAnnotate("cosmos.db", containerId)
|
|
267
281
|
},
|
|
268
|
-
find: id =>
|
|
269
|
-
Effect
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
282
|
+
find: (id) =>
|
|
283
|
+
Effect
|
|
284
|
+
.promise(() =>
|
|
285
|
+
container
|
|
286
|
+
.item(id, config?.partitionValue({ id } as PM))
|
|
287
|
+
.read<PM>()
|
|
288
|
+
.then(({ resource }) => Option.fromNullable(resource))
|
|
289
|
+
)
|
|
290
|
+
.instrument("cosmos.find")
|
|
275
291
|
.logAnnotate("cosmos.db", containerId),
|
|
276
|
-
set: e =>
|
|
277
|
-
Option
|
|
292
|
+
set: (e) =>
|
|
293
|
+
Option
|
|
294
|
+
.fromNullable(e._etag)
|
|
278
295
|
.match(
|
|
279
296
|
() =>
|
|
280
297
|
Effect.promise(() =>
|
|
@@ -283,7 +300,7 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
283
300
|
_partitionKey: config?.partitionValue(e)
|
|
284
301
|
})
|
|
285
302
|
),
|
|
286
|
-
eTag =>
|
|
303
|
+
(eTag) =>
|
|
287
304
|
Effect.promise(() =>
|
|
288
305
|
container.item(e.id, config?.partitionValue(e)).replace(
|
|
289
306
|
{ ...e, _partitionKey: config?.partitionValue(e) },
|
|
@@ -296,7 +313,7 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
296
313
|
)
|
|
297
314
|
)
|
|
298
315
|
)
|
|
299
|
-
.flatMap(x => {
|
|
316
|
+
.flatMap((x) => {
|
|
300
317
|
if (x.statusCode === 412 || x.statusCode === 404) {
|
|
301
318
|
return Effect.fail(new OptimisticConcurrencyException(name, e.id))
|
|
302
319
|
}
|
|
@@ -317,7 +334,8 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
317
334
|
batchSet,
|
|
318
335
|
bulkSet,
|
|
319
336
|
remove: (e: PM) =>
|
|
320
|
-
Effect
|
|
337
|
+
Effect
|
|
338
|
+
.promise(() => container.item(e.id, config?.partitionValue(e)).delete())
|
|
321
339
|
.instrument("cosmos.remove")
|
|
322
340
|
.logAnnotate("cosmos.db", containerId)
|
|
323
341
|
}
|
|
@@ -338,7 +356,7 @@ export function makeCosmosStore({ prefix }: StorageConfig) {
|
|
|
338
356
|
const m = yield* $(seed)
|
|
339
357
|
yield* $(
|
|
340
358
|
Effect(m.toNonEmptyArray)
|
|
341
|
-
.flatMapOpt(a =>
|
|
359
|
+
.flatMapOpt((a) =>
|
|
342
360
|
s
|
|
343
361
|
.bulkSet(a)
|
|
344
362
|
.orDie
|
|
@@ -370,7 +388,8 @@ function logQuery(q: {
|
|
|
370
388
|
value: SupportedValues | readonly SupportedValues[]
|
|
371
389
|
}[]
|
|
372
390
|
}) {
|
|
373
|
-
return Effect
|
|
391
|
+
return Effect
|
|
392
|
+
.logDebug("cosmos query")
|
|
374
393
|
.apply(Effect.logAnnotates({
|
|
375
394
|
query: q.query,
|
|
376
395
|
parameters: JSON.stringify(
|
|
@@ -477,18 +496,21 @@ export function buildWhereCosmosQuery(
|
|
|
477
496
|
SELECT f
|
|
478
497
|
FROM ${name} AS f
|
|
479
498
|
${
|
|
480
|
-
filter
|
|
481
|
-
.
|
|
482
|
-
.
|
|
499
|
+
filter
|
|
500
|
+
.where
|
|
501
|
+
.filter((_) => _.key.includes(".-1."))
|
|
502
|
+
.map((_) => _.key.split(".-1.")[0])
|
|
503
|
+
.map((_) => `JOIN ${_} IN f.${_}`)
|
|
483
504
|
.uniq(Equivalence.string)
|
|
484
505
|
.join("\n")
|
|
485
506
|
}
|
|
486
507
|
WHERE f.id != @id AND ${
|
|
487
|
-
filter
|
|
488
|
-
.
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
{ ..._, f: "
|
|
508
|
+
filter
|
|
509
|
+
.where
|
|
510
|
+
.map((_) =>
|
|
511
|
+
_.key.includes(".-1.")
|
|
512
|
+
? { ..._, f: _.key.split(".-1.")[0], key: _.key.split(".-1.")[1]! }
|
|
513
|
+
: { ..._, f: "f" }
|
|
492
514
|
)
|
|
493
515
|
.map(
|
|
494
516
|
(x, i) =>
|
|
@@ -517,7 +539,8 @@ export function buildWhereCosmosQuery(
|
|
|
517
539
|
${lm}`,
|
|
518
540
|
parameters: [
|
|
519
541
|
{ name: "@id", value: importedMarkerId },
|
|
520
|
-
...filter
|
|
542
|
+
...filter
|
|
543
|
+
.where
|
|
521
544
|
.map((x, i) => ({
|
|
522
545
|
name: `@v${i}`,
|
|
523
546
|
value: x.value
|
|
@@ -539,9 +562,9 @@ export function buildCosmosQuery<PM>(
|
|
|
539
562
|
skip?: number,
|
|
540
563
|
limit?: number
|
|
541
564
|
) {
|
|
542
|
-
return filter.type === "startsWith"
|
|
543
|
-
filter.type === "endsWith"
|
|
544
|
-
filter.type === "contains"
|
|
565
|
+
return filter.type === "startsWith"
|
|
566
|
+
|| filter.type === "endsWith"
|
|
567
|
+
|| filter.type === "contains"
|
|
545
568
|
? buildLegacyCosmosQuery(filter, name, importedMarkerId, skip, limit)
|
|
546
569
|
: buildWhereCosmosQuery(filter, name, importedMarkerId, skip, limit)
|
|
547
570
|
}
|