envio 2.26.0-alpha.9 → 2.26.0-rc.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/evm.schema.json +0 -7
- package/fuel.schema.json +0 -7
- package/index.d.ts +0 -2
- package/package.json +5 -5
- package/src/Envio.gen.ts +1 -3
- package/src/Envio.res +0 -3
- package/src/Envio.res.js +0 -2
- package/src/FetchState.res +4 -1
- package/src/Internal.res +0 -1
- package/src/Logging.res +0 -8
- package/src/Logging.res.js +0 -29
- package/src/Persistence.res +19 -46
- package/src/Persistence.res.js +13 -23
- package/src/PgStorage.res +84 -214
- package/src/PgStorage.res.js +54 -153
- package/src/Utils.res +0 -17
- package/src/db/EntityHistory.res +28 -5
- package/src/db/EntityHistory.res.js +23 -4
- package/src/db/Table.res +61 -3
- package/src/db/Table.res.js +42 -3
package/src/PgStorage.res
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
let
|
|
1
|
+
let makeCreateIndexSql = (~tableName, ~indexFields, ~pgSchema) => {
|
|
2
2
|
let indexName = tableName ++ "_" ++ indexFields->Js.Array2.joinWith("_")
|
|
3
3
|
let index = indexFields->Belt.Array.map(idx => `"${idx}"`)->Js.Array2.joinWith(", ")
|
|
4
4
|
`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${pgSchema}"."${tableName}"(${index});`
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
let
|
|
7
|
+
let makeCreateTableIndicesSql = (table: Table.table, ~pgSchema) => {
|
|
8
8
|
open Belt
|
|
9
9
|
let tableName = table.tableName
|
|
10
10
|
let createIndex = indexField =>
|
|
11
|
-
|
|
11
|
+
makeCreateIndexSql(~tableName, ~indexFields=[indexField], ~pgSchema)
|
|
12
12
|
let createCompositeIndex = indexFields => {
|
|
13
|
-
|
|
13
|
+
makeCreateIndexSql(~tableName, ~indexFields, ~pgSchema)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
let singleIndices = table->Table.getSingleIndices
|
|
@@ -20,7 +20,7 @@ let makeCreateTableIndicesQuery = (table: Table.table, ~pgSchema) => {
|
|
|
20
20
|
compositeIndices->Array.map(createCompositeIndex)->Js.Array2.joinWith("\n")
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
let
|
|
23
|
+
let makeCreateTableSql = (table: Table.table, ~pgSchema) => {
|
|
24
24
|
open Belt
|
|
25
25
|
let fieldsMapped =
|
|
26
26
|
table
|
|
@@ -58,7 +58,7 @@ let makeInitializeTransaction = (
|
|
|
58
58
|
~generalTables=[],
|
|
59
59
|
~entities=[],
|
|
60
60
|
~enums=[],
|
|
61
|
-
~
|
|
61
|
+
~cleanRun=false,
|
|
62
62
|
) => {
|
|
63
63
|
let allTables = generalTables->Array.copy
|
|
64
64
|
let allEntityTables = []
|
|
@@ -71,15 +71,12 @@ let makeInitializeTransaction = (
|
|
|
71
71
|
|
|
72
72
|
let query = ref(
|
|
73
73
|
(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
? ""
|
|
79
|
-
: `DROP SCHEMA IF EXISTS "${pgSchema}" CASCADE;
|
|
80
|
-
CREATE SCHEMA "${pgSchema}";\n`
|
|
74
|
+
cleanRun
|
|
75
|
+
? `DROP SCHEMA IF EXISTS "${pgSchema}" CASCADE;
|
|
76
|
+
CREATE SCHEMA "${pgSchema}";`
|
|
77
|
+
: `CREATE SCHEMA IF NOT EXISTS "${pgSchema}";`
|
|
81
78
|
) ++
|
|
82
|
-
`GRANT ALL ON SCHEMA "${pgSchema}" TO
|
|
79
|
+
`GRANT ALL ON SCHEMA "${pgSchema}" TO ${pgUser};
|
|
83
80
|
GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
|
|
84
81
|
)
|
|
85
82
|
|
|
@@ -90,17 +87,31 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
|
|
|
90
87
|
->Js.Array2.map(v => `'${v->(Utils.magic: Internal.enum => string)}'`)
|
|
91
88
|
->Js.Array2.joinWith(", ")});`
|
|
92
89
|
|
|
93
|
-
query :=
|
|
90
|
+
query :=
|
|
91
|
+
query.contents ++
|
|
92
|
+
"\n" ++ if cleanRun {
|
|
93
|
+
// Direct creation when cleanRunting (faster)
|
|
94
|
+
enumCreateQuery
|
|
95
|
+
} else {
|
|
96
|
+
// Wrap with conditional check only when not cleanRunting
|
|
97
|
+
`IF NOT EXISTS (
|
|
98
|
+
SELECT 1 FROM pg_type
|
|
99
|
+
WHERE typname = '${enumConfig.name->Js.String2.toLowerCase}'
|
|
100
|
+
AND typnamespace = (SELECT oid FROM pg_namespace WHERE nspname = '${pgSchema}')
|
|
101
|
+
) THEN
|
|
102
|
+
${enumCreateQuery}
|
|
103
|
+
END IF;`
|
|
104
|
+
}
|
|
94
105
|
})
|
|
95
106
|
|
|
96
107
|
// Batch all table creation first (optimal for PostgreSQL)
|
|
97
108
|
allTables->Js.Array2.forEach((table: Table.table) => {
|
|
98
|
-
query := query.contents ++ "\n" ++
|
|
109
|
+
query := query.contents ++ "\n" ++ makeCreateTableSql(table, ~pgSchema)
|
|
99
110
|
})
|
|
100
111
|
|
|
101
112
|
// Then batch all indices (better performance when tables exist)
|
|
102
113
|
allTables->Js.Array2.forEach((table: Table.table) => {
|
|
103
|
-
let indices =
|
|
114
|
+
let indices = makeCreateTableIndicesSql(table, ~pgSchema)
|
|
104
115
|
if indices !== "" {
|
|
105
116
|
query := query.contents ++ "\n" ++ indices
|
|
106
117
|
}
|
|
@@ -120,7 +131,7 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
|
|
|
120
131
|
query :=
|
|
121
132
|
query.contents ++
|
|
122
133
|
"\n" ++
|
|
123
|
-
|
|
134
|
+
makeCreateIndexSql(
|
|
124
135
|
~tableName=derivedFromField.derivedFromEntity,
|
|
125
136
|
~indexFields=[indexField],
|
|
126
137
|
~pgSchema,
|
|
@@ -128,26 +139,28 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
|
|
|
128
139
|
})
|
|
129
140
|
})
|
|
130
141
|
|
|
131
|
-
[
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
[
|
|
143
|
+
// Return optimized queries - main DDL in DO block, functions separate
|
|
144
|
+
// Note: DO $$ BEGIN wrapper is only needed for PL/pgSQL conditionals (IF NOT EXISTS)
|
|
145
|
+
// Reset case uses direct DDL (faster), non-cleanRun case uses conditionals (safer)
|
|
146
|
+
cleanRun || enums->Utils.Array.isEmpty
|
|
147
|
+
? query.contents
|
|
148
|
+
: `DO $$ BEGIN ${query.contents} END $$;`,
|
|
149
|
+
// Functions query (separate as they can't be in DO block)
|
|
150
|
+
]->Js.Array2.concat(functionsQuery.contents !== "" ? [functionsQuery.contents] : [])
|
|
134
151
|
}
|
|
135
152
|
|
|
136
|
-
let
|
|
153
|
+
let makeLoadByIdSql = (~pgSchema, ~tableName) => {
|
|
137
154
|
`SELECT * FROM "${pgSchema}"."${tableName}" WHERE id = $1 LIMIT 1;`
|
|
138
155
|
}
|
|
139
156
|
|
|
140
|
-
let
|
|
141
|
-
`SELECT * FROM "${pgSchema}"."${tableName}" WHERE "${fieldName}" ${operator} $1;`
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
let makeLoadByIdsQuery = (~pgSchema, ~tableName) => {
|
|
157
|
+
let makeLoadByIdsSql = (~pgSchema, ~tableName) => {
|
|
145
158
|
`SELECT * FROM "${pgSchema}"."${tableName}" WHERE id = ANY($1::text[]);`
|
|
146
159
|
}
|
|
147
160
|
|
|
148
|
-
let
|
|
161
|
+
let makeInsertUnnestSetSql = (~pgSchema, ~table: Table.table, ~itemSchema, ~isRawEvents) => {
|
|
149
162
|
let {quotedFieldNames, quotedNonPrimaryFieldNames, arrayFieldTypes} =
|
|
150
|
-
table->Table.toSqlParams(~schema=itemSchema
|
|
163
|
+
table->Table.toSqlParams(~schema=itemSchema)
|
|
151
164
|
|
|
152
165
|
let primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table)
|
|
153
166
|
|
|
@@ -175,9 +188,8 @@ SELECT * FROM unnest(${arrayFieldTypes
|
|
|
175
188
|
} ++ ";"
|
|
176
189
|
}
|
|
177
190
|
|
|
178
|
-
let
|
|
179
|
-
let {quotedFieldNames, quotedNonPrimaryFieldNames} =
|
|
180
|
-
table->Table.toSqlParams(~schema=itemSchema, ~pgSchema)
|
|
191
|
+
let makeInsertValuesSetSql = (~pgSchema, ~table: Table.table, ~itemSchema, ~itemsCount) => {
|
|
192
|
+
let {quotedFieldNames, quotedNonPrimaryFieldNames} = table->Table.toSqlParams(~schema=itemSchema)
|
|
181
193
|
|
|
182
194
|
let primaryKeyFieldNames = Table.getPrimaryKeyFieldNames(table)
|
|
183
195
|
let fieldsCount = quotedFieldNames->Array.length
|
|
@@ -224,13 +236,12 @@ VALUES${placeholders.contents}` ++
|
|
|
224
236
|
// they are always guaranteed to be an object.
|
|
225
237
|
// FIXME what about Fuel params?
|
|
226
238
|
let rawEventsTableName = "raw_events"
|
|
227
|
-
let eventSyncStateTableName = "event_sync_state"
|
|
228
239
|
|
|
229
240
|
// Constants for chunking
|
|
230
241
|
let maxItemsPerQuery = 500
|
|
231
242
|
|
|
232
243
|
let makeTableBatchSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema: S.t<'item>) => {
|
|
233
|
-
let {dbSchema, hasArrayField} = table->Table.toSqlParams(~schema=itemSchema
|
|
244
|
+
let {dbSchema, hasArrayField} = table->Table.toSqlParams(~schema=itemSchema)
|
|
234
245
|
let isRawEvents = table.tableName === rawEventsTableName
|
|
235
246
|
|
|
236
247
|
// Should experiment how much it'll affect performance
|
|
@@ -242,7 +253,7 @@ let makeTableBatchSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema: S.t<'
|
|
|
242
253
|
|
|
243
254
|
if isRawEvents || !hasArrayField {
|
|
244
255
|
{
|
|
245
|
-
"
|
|
256
|
+
"sql": makeInsertUnnestSetSql(~pgSchema, ~table, ~itemSchema, ~isRawEvents),
|
|
246
257
|
"convertOrThrow": S.compile(
|
|
247
258
|
S.unnest(dbSchema),
|
|
248
259
|
~input=Value,
|
|
@@ -254,12 +265,7 @@ let makeTableBatchSetQuery = (~pgSchema, ~table: Table.table, ~itemSchema: S.t<'
|
|
|
254
265
|
}
|
|
255
266
|
} else {
|
|
256
267
|
{
|
|
257
|
-
"
|
|
258
|
-
~pgSchema,
|
|
259
|
-
~table,
|
|
260
|
-
~itemSchema,
|
|
261
|
-
~itemsCount=maxItemsPerQuery,
|
|
262
|
-
),
|
|
268
|
+
"sql": makeInsertValuesSetSql(~pgSchema, ~table, ~itemSchema, ~itemsCount=maxItemsPerQuery),
|
|
263
269
|
"convertOrThrow": S.compile(
|
|
264
270
|
S.unnest(itemSchema)->S.preprocess(_ => {
|
|
265
271
|
serializer: Utils.Array.flatten->Utils.magic,
|
|
@@ -285,35 +291,6 @@ let chunkArray = (arr: array<'a>, ~chunkSize) => {
|
|
|
285
291
|
chunks
|
|
286
292
|
}
|
|
287
293
|
|
|
288
|
-
let removeInvalidUtf8InPlace = entities =>
|
|
289
|
-
entities->Js.Array2.forEach(item => {
|
|
290
|
-
let dict = item->(Utils.magic: 'a => dict<unknown>)
|
|
291
|
-
dict->Utils.Dict.forEachWithKey((key, value) => {
|
|
292
|
-
if value->Js.typeof === "string" {
|
|
293
|
-
let value = value->(Utils.magic: unknown => string)
|
|
294
|
-
// We mutate here, since we don't care
|
|
295
|
-
// about the original value with \x00 anyways.
|
|
296
|
-
//
|
|
297
|
-
// This is unsafe, but we rely that it'll use
|
|
298
|
-
// the mutated reference on retry.
|
|
299
|
-
// TODO: Test it properly after we start using
|
|
300
|
-
// in-memory PGLite for indexer test framework.
|
|
301
|
-
dict->Js.Dict.set(
|
|
302
|
-
key,
|
|
303
|
-
value
|
|
304
|
-
->Utils.String.replaceAll("\x00", "")
|
|
305
|
-
->(Utils.magic: string => unknown),
|
|
306
|
-
)
|
|
307
|
-
}
|
|
308
|
-
})
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
let pgEncodingErrorSchema = S.object(s =>
|
|
312
|
-
s.tag("message", `invalid byte sequence for encoding "UTF8": 0x00`)
|
|
313
|
-
)
|
|
314
|
-
|
|
315
|
-
exception PgEncodingError({table: Table.table})
|
|
316
|
-
|
|
317
294
|
// WeakMap for caching table batch set queries
|
|
318
295
|
let setQueryCache = Utils.WeakMap.make()
|
|
319
296
|
let setOrThrow = async (sql, ~items, ~table: Table.table, ~itemSchema, ~pgSchema) => {
|
|
@@ -321,7 +298,7 @@ let setOrThrow = async (sql, ~items, ~table: Table.table, ~itemSchema, ~pgSchema
|
|
|
321
298
|
()
|
|
322
299
|
} else {
|
|
323
300
|
// Get or create cached query for this table
|
|
324
|
-
let
|
|
301
|
+
let query = switch setQueryCache->Utils.WeakMap.get(table) {
|
|
325
302
|
| Some(cached) => cached
|
|
326
303
|
| None => {
|
|
327
304
|
let newQuery = makeTableBatchSetQuery(
|
|
@@ -334,31 +311,50 @@ let setOrThrow = async (sql, ~items, ~table: Table.table, ~itemSchema, ~pgSchema
|
|
|
334
311
|
}
|
|
335
312
|
}
|
|
336
313
|
|
|
314
|
+
let sqlQuery = query["sql"]
|
|
315
|
+
|
|
337
316
|
try {
|
|
338
|
-
|
|
339
|
-
|
|
317
|
+
let payload =
|
|
318
|
+
query["convertOrThrow"](items->(Utils.magic: array<'item> => array<unknown>))->(
|
|
319
|
+
Utils.magic: unknown => array<unknown>
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
if query["isInsertValues"] {
|
|
323
|
+
let fieldsCount = switch itemSchema->S.classify {
|
|
324
|
+
| S.Object({items}) => items->Array.length
|
|
325
|
+
| _ => Js.Exn.raiseError("Expected an object schema for table")
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Chunk the items for VALUES-based queries
|
|
329
|
+
// We need to multiply by fields count,
|
|
330
|
+
// because we flattened our entity values with S.unnest
|
|
331
|
+
// to optimize the query execution.
|
|
332
|
+
let maxChunkSize = maxItemsPerQuery * fieldsCount
|
|
333
|
+
let chunks = chunkArray(payload, ~chunkSize=maxChunkSize)
|
|
340
334
|
let responses = []
|
|
341
335
|
chunks->Js.Array2.forEach(chunk => {
|
|
342
336
|
let chunkSize = chunk->Array.length
|
|
343
|
-
let isFullChunk = chunkSize ===
|
|
337
|
+
let isFullChunk = chunkSize === maxChunkSize
|
|
344
338
|
|
|
345
339
|
let response = sql->Postgres.preparedUnsafe(
|
|
346
340
|
// Either use the sql query for full chunks from cache
|
|
347
341
|
// or create a new one for partial chunks on the fly.
|
|
348
342
|
isFullChunk
|
|
349
|
-
?
|
|
350
|
-
:
|
|
351
|
-
|
|
343
|
+
? sqlQuery
|
|
344
|
+
: makeInsertValuesSetSql(
|
|
345
|
+
~pgSchema,
|
|
346
|
+
~table,
|
|
347
|
+
~itemSchema,
|
|
348
|
+
~itemsCount=chunkSize / fieldsCount,
|
|
349
|
+
),
|
|
350
|
+
chunk->Utils.magic,
|
|
352
351
|
)
|
|
353
352
|
responses->Js.Array2.push(response)->ignore
|
|
354
353
|
})
|
|
355
354
|
let _ = await Promise.all(responses)
|
|
356
355
|
} else {
|
|
357
356
|
// Use UNNEST approach for single query
|
|
358
|
-
await sql->Postgres.preparedUnsafe(
|
|
359
|
-
data["query"],
|
|
360
|
-
data["convertOrThrow"](items->(Utils.magic: array<'item> => array<unknown>)),
|
|
361
|
-
)
|
|
357
|
+
await sql->Postgres.preparedUnsafe(sqlQuery, payload->Obj.magic)
|
|
362
358
|
}
|
|
363
359
|
} catch {
|
|
364
360
|
| S.Raised(_) as exn =>
|
|
@@ -379,81 +375,23 @@ let setOrThrow = async (sql, ~items, ~table: Table.table, ~itemSchema, ~pgSchema
|
|
|
379
375
|
}
|
|
380
376
|
}
|
|
381
377
|
|
|
382
|
-
let setEntityHistoryOrThrow = (
|
|
383
|
-
sql,
|
|
384
|
-
~entityHistory: EntityHistory.t<'entity>,
|
|
385
|
-
~rows: array<EntityHistory.historyRow<'entity>>,
|
|
386
|
-
~shouldCopyCurrentEntity=?,
|
|
387
|
-
~shouldRemoveInvalidUtf8=false,
|
|
388
|
-
) => {
|
|
389
|
-
rows
|
|
390
|
-
->Belt.Array.map(historyRow => {
|
|
391
|
-
let row = historyRow->S.reverseConvertToJsonOrThrow(entityHistory.schema)
|
|
392
|
-
if shouldRemoveInvalidUtf8 {
|
|
393
|
-
[row]->removeInvalidUtf8InPlace
|
|
394
|
-
}
|
|
395
|
-
entityHistory.insertFn(
|
|
396
|
-
sql,
|
|
397
|
-
row,
|
|
398
|
-
~shouldCopyCurrentEntity=switch shouldCopyCurrentEntity {
|
|
399
|
-
| Some(v) => v
|
|
400
|
-
| None => {
|
|
401
|
-
let containsRollbackDiffChange =
|
|
402
|
-
historyRow.containsRollbackDiffChange->Belt.Option.getWithDefault(false)
|
|
403
|
-
!containsRollbackDiffChange
|
|
404
|
-
}
|
|
405
|
-
},
|
|
406
|
-
)
|
|
407
|
-
})
|
|
408
|
-
->Promise.all
|
|
409
|
-
->(Utils.magic: promise<array<unit>> => promise<unit>)
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
type schemaTableName = {
|
|
413
|
-
@as("table_name")
|
|
414
|
-
tableName: string,
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
let makeSchemaTableNamesQuery = (~pgSchema) => {
|
|
418
|
-
`SELECT table_name FROM information_schema.tables WHERE table_schema = '${pgSchema}';`
|
|
419
|
-
}
|
|
420
|
-
|
|
421
378
|
let make = (~sql: Postgres.sql, ~pgSchema, ~pgUser): Persistence.storage => {
|
|
422
379
|
let isInitialized = async () => {
|
|
423
|
-
let
|
|
380
|
+
let schemas =
|
|
424
381
|
await sql->Postgres.unsafe(
|
|
425
|
-
`SELECT
|
|
382
|
+
`SELECT schema_name FROM information_schema.schemata WHERE schema_name = '${pgSchema}';`,
|
|
426
383
|
)
|
|
427
|
-
|
|
384
|
+
schemas->Utils.Array.notEmpty
|
|
428
385
|
}
|
|
429
386
|
|
|
430
|
-
let initialize = async (~entities=[], ~generalTables=[], ~enums=[]) => {
|
|
431
|
-
let schemaTableNames: array<schemaTableName> =
|
|
432
|
-
await sql->Postgres.unsafe(makeSchemaTableNamesQuery(~pgSchema))
|
|
433
|
-
|
|
434
|
-
// The initialization query will completely drop the schema and recreate it from scratch.
|
|
435
|
-
// So we need to check if the schema is not used for anything else than envio.
|
|
436
|
-
if (
|
|
437
|
-
// Should pass with existing schema with no tables
|
|
438
|
-
// This might happen when used with public schema
|
|
439
|
-
// which is automatically created by postgres.
|
|
440
|
-
schemaTableNames->Utils.Array.notEmpty &&
|
|
441
|
-
// Otherwise should throw if there's a table, but no envio specific one
|
|
442
|
-
// This means that the schema is used for something else than envio.
|
|
443
|
-
!(schemaTableNames->Js.Array2.some(table => table.tableName === eventSyncStateTableName))
|
|
444
|
-
) {
|
|
445
|
-
Js.Exn.raiseError(
|
|
446
|
-
`Cannot run Envio migrations on PostgreSQL schema "${pgSchema}" because it contains non-Envio tables. Running migrations would delete all data in this schema.\n\nTo resolve this:\n1. If you want to use this schema, first backup any important data, then drop it with: "pnpm envio local db-migrate down"\n2. Or specify a different schema name by setting the "ENVIO_PG_PUBLIC_SCHEMA" environment variable\n3. Or manually drop the schema in your database if you're certain the data is not needed.`,
|
|
447
|
-
)
|
|
448
|
-
}
|
|
449
|
-
|
|
387
|
+
let initialize = async (~entities=[], ~generalTables=[], ~enums=[], ~cleanRun=false) => {
|
|
450
388
|
let queries = makeInitializeTransaction(
|
|
451
389
|
~pgSchema,
|
|
452
390
|
~pgUser,
|
|
453
391
|
~generalTables,
|
|
454
392
|
~entities,
|
|
455
393
|
~enums,
|
|
456
|
-
~
|
|
394
|
+
~cleanRun,
|
|
457
395
|
)
|
|
458
396
|
// Execute all queries within a single transaction for integrity
|
|
459
397
|
let _ = await sql->Postgres.beginSql(sql => {
|
|
@@ -461,37 +399,17 @@ let make = (~sql: Postgres.sql, ~pgSchema, ~pgUser): Persistence.storage => {
|
|
|
461
399
|
})
|
|
462
400
|
}
|
|
463
401
|
|
|
464
|
-
let loadEffectCaches = async () => {
|
|
465
|
-
let schemaTableNames: array<schemaTableName> =
|
|
466
|
-
await sql->Postgres.unsafe(makeSchemaTableNamesQuery(~pgSchema))
|
|
467
|
-
schemaTableNames->Belt.Array.keepMapU(schemaTableName => {
|
|
468
|
-
if schemaTableName.tableName->Js.String2.startsWith("effect_cache_") {
|
|
469
|
-
Some(
|
|
470
|
-
(
|
|
471
|
-
{
|
|
472
|
-
name: schemaTableName.tableName,
|
|
473
|
-
size: 0,
|
|
474
|
-
table: None,
|
|
475
|
-
}: Persistence.effectCache
|
|
476
|
-
),
|
|
477
|
-
)
|
|
478
|
-
} else {
|
|
479
|
-
None
|
|
480
|
-
}
|
|
481
|
-
})
|
|
482
|
-
}
|
|
483
|
-
|
|
484
402
|
let loadByIdsOrThrow = async (~ids, ~table: Table.table, ~rowsSchema) => {
|
|
485
403
|
switch await (
|
|
486
404
|
switch ids {
|
|
487
405
|
| [_] =>
|
|
488
406
|
sql->Postgres.preparedUnsafe(
|
|
489
|
-
|
|
407
|
+
makeLoadByIdSql(~pgSchema, ~tableName=table.tableName),
|
|
490
408
|
ids->Obj.magic,
|
|
491
409
|
)
|
|
492
410
|
| _ =>
|
|
493
411
|
sql->Postgres.preparedUnsafe(
|
|
494
|
-
|
|
412
|
+
makeLoadByIdsSql(~pgSchema, ~tableName=table.tableName),
|
|
495
413
|
[ids]->Obj.magic,
|
|
496
414
|
)
|
|
497
415
|
}
|
|
@@ -516,52 +434,6 @@ let make = (~sql: Postgres.sql, ~pgSchema, ~pgUser): Persistence.storage => {
|
|
|
516
434
|
}
|
|
517
435
|
}
|
|
518
436
|
|
|
519
|
-
let loadByFieldOrThrow = async (
|
|
520
|
-
~fieldName: string,
|
|
521
|
-
~fieldSchema,
|
|
522
|
-
~fieldValue,
|
|
523
|
-
~operator: Persistence.operator,
|
|
524
|
-
~table: Table.table,
|
|
525
|
-
~rowsSchema,
|
|
526
|
-
) => {
|
|
527
|
-
let params = try [fieldValue->S.reverseConvertToJsonOrThrow(fieldSchema)]->Obj.magic catch {
|
|
528
|
-
| exn =>
|
|
529
|
-
raise(
|
|
530
|
-
Persistence.StorageError({
|
|
531
|
-
message: `Failed loading "${table.tableName}" from storage by field "${fieldName}". Couldn't serialize provided value.`,
|
|
532
|
-
reason: exn,
|
|
533
|
-
}),
|
|
534
|
-
)
|
|
535
|
-
}
|
|
536
|
-
switch await sql->Postgres.preparedUnsafe(
|
|
537
|
-
makeLoadByFieldQuery(
|
|
538
|
-
~pgSchema,
|
|
539
|
-
~tableName=table.tableName,
|
|
540
|
-
~fieldName,
|
|
541
|
-
~operator=(operator :> string),
|
|
542
|
-
),
|
|
543
|
-
params,
|
|
544
|
-
) {
|
|
545
|
-
| exception exn =>
|
|
546
|
-
raise(
|
|
547
|
-
Persistence.StorageError({
|
|
548
|
-
message: `Failed loading "${table.tableName}" from storage by field "${fieldName}"`,
|
|
549
|
-
reason: exn,
|
|
550
|
-
}),
|
|
551
|
-
)
|
|
552
|
-
| rows =>
|
|
553
|
-
try rows->S.parseOrThrow(rowsSchema) catch {
|
|
554
|
-
| exn =>
|
|
555
|
-
raise(
|
|
556
|
-
Persistence.StorageError({
|
|
557
|
-
message: `Failed to parse "${table.tableName}" loaded from storage by ids`,
|
|
558
|
-
reason: exn,
|
|
559
|
-
}),
|
|
560
|
-
)
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
437
|
let setOrThrow = (
|
|
566
438
|
type item,
|
|
567
439
|
~items: array<item>,
|
|
@@ -580,8 +452,6 @@ let make = (~sql: Postgres.sql, ~pgSchema, ~pgUser): Persistence.storage => {
|
|
|
580
452
|
{
|
|
581
453
|
isInitialized,
|
|
582
454
|
initialize,
|
|
583
|
-
loadByFieldOrThrow,
|
|
584
|
-
loadEffectCaches,
|
|
585
455
|
loadByIdsOrThrow,
|
|
586
456
|
setOrThrow,
|
|
587
457
|
}
|