envio 3.0.0-alpha.2 → 3.0.0-alpha.20
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/README.md +164 -30
- package/bin.mjs +49 -0
- package/evm.schema.json +79 -169
- package/fuel.schema.json +50 -21
- package/index.d.ts +497 -1
- package/index.js +4 -0
- package/package.json +42 -31
- package/rescript.json +4 -1
- package/src/Batch.res +11 -8
- package/src/Batch.res.mjs +11 -9
- package/src/ChainFetcher.res +531 -0
- package/src/ChainFetcher.res.mjs +339 -0
- package/src/ChainManager.res +190 -0
- package/src/ChainManager.res.mjs +166 -0
- package/src/Change.res +3 -3
- package/src/Config.gen.ts +19 -0
- package/src/Config.res +737 -22
- package/src/Config.res.mjs +703 -26
- package/src/{Indexer.res → Ctx.res} +1 -1
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +30 -74
- package/src/Env.res.mjs +25 -87
- package/src/Envio.gen.ts +3 -1
- package/src/Envio.res +20 -9
- package/src/EventProcessing.res +469 -0
- package/src/EventProcessing.res.mjs +337 -0
- package/src/EvmTypes.gen.ts +6 -0
- package/src/EvmTypes.res +1 -0
- package/src/FetchState.res +1256 -639
- package/src/FetchState.res.mjs +1135 -612
- package/src/GlobalState.res +1190 -0
- package/src/GlobalState.res.mjs +1183 -0
- package/src/GlobalStateManager.res +68 -0
- package/src/GlobalStateManager.res.mjs +75 -0
- package/src/GlobalStateManager.resi +7 -0
- package/src/HandlerLoader.res +89 -0
- package/src/HandlerLoader.res.mjs +79 -0
- package/src/HandlerRegister.res +357 -0
- package/src/HandlerRegister.res.mjs +299 -0
- package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
- package/src/Hasura.res +111 -175
- package/src/Hasura.res.mjs +88 -150
- package/src/InMemoryStore.res +1 -1
- package/src/InMemoryStore.res.mjs +3 -3
- package/src/InMemoryTable.res +1 -1
- package/src/InMemoryTable.res.mjs +1 -1
- package/src/Internal.gen.ts +4 -0
- package/src/Internal.res +230 -12
- package/src/Internal.res.mjs +115 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/LogSelection.res +33 -27
- package/src/LogSelection.res.mjs +6 -0
- package/src/Logging.res +21 -7
- package/src/Logging.res.mjs +16 -8
- package/src/Main.res +377 -0
- package/src/Main.res.mjs +339 -0
- package/src/Persistence.res +7 -21
- package/src/Persistence.res.mjs +3 -3
- package/src/PgStorage.gen.ts +10 -0
- package/src/PgStorage.res +116 -69
- package/src/PgStorage.res.d.mts +5 -0
- package/src/PgStorage.res.mjs +93 -50
- package/src/Prometheus.res +294 -224
- package/src/Prometheus.res.mjs +353 -340
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/Sink.res +4 -2
- package/src/Sink.res.mjs +2 -1
- package/src/TableIndices.res +0 -1
- package/src/TestIndexer.res +692 -0
- package/src/TestIndexer.res.mjs +527 -0
- package/src/TestIndexerProxyStorage.res +205 -0
- package/src/TestIndexerProxyStorage.res.mjs +151 -0
- package/src/TopicFilter.res +1 -1
- package/src/Types.ts +1 -1
- package/src/UserContext.res +424 -0
- package/src/UserContext.res.mjs +279 -0
- package/src/Utils.res +97 -26
- package/src/Utils.res.mjs +91 -44
- package/src/bindings/BigInt.res +10 -0
- package/src/bindings/BigInt.res.mjs +15 -0
- package/src/bindings/ClickHouse.res +120 -23
- package/src/bindings/ClickHouse.res.mjs +118 -28
- package/src/bindings/DateFns.res +74 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/bindings/EventSource.res +8 -1
- package/src/bindings/EventSource.res.mjs +8 -1
- package/src/bindings/Express.res +1 -0
- package/src/bindings/Hrtime.res +14 -1
- package/src/bindings/Hrtime.res.mjs +22 -2
- package/src/bindings/Hrtime.resi +4 -0
- package/src/bindings/Lodash.res +0 -1
- package/src/bindings/NodeJs.res +49 -3
- package/src/bindings/NodeJs.res.mjs +11 -3
- package/src/bindings/Pino.res +24 -10
- package/src/bindings/Pino.res.mjs +14 -8
- package/src/bindings/Postgres.gen.ts +8 -0
- package/src/bindings/Postgres.res +5 -1
- package/src/bindings/Postgres.res.d.mts +5 -0
- package/src/bindings/PromClient.res +0 -10
- package/src/bindings/PromClient.res.mjs +0 -3
- package/src/bindings/Vitest.res +142 -0
- package/src/bindings/Vitest.res.mjs +9 -0
- package/src/bindings/WebSocket.res +27 -0
- package/src/bindings/WebSocket.res.mjs +2 -0
- package/src/bindings/Yargs.res +8 -0
- package/src/bindings/Yargs.res.mjs +2 -0
- package/src/db/EntityHistory.res +7 -7
- package/src/db/EntityHistory.res.mjs +9 -9
- package/src/db/InternalTable.res +59 -111
- package/src/db/InternalTable.res.mjs +73 -104
- package/src/db/Table.res +27 -8
- package/src/db/Table.res.mjs +25 -14
- package/src/sources/Evm.res +84 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +94 -0
- package/src/sources/EvmChain.res.mjs +60 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +38 -0
- package/src/sources/FuelSDK.res.mjs +29 -0
- package/src/sources/HyperFuel.res +2 -2
- package/src/sources/HyperFuel.resi +1 -1
- package/src/sources/HyperFuelClient.res +2 -2
- package/src/sources/HyperFuelSource.res +33 -13
- package/src/sources/HyperFuelSource.res.mjs +24 -16
- package/src/sources/HyperSync.res +36 -6
- package/src/sources/HyperSync.res.mjs +9 -7
- package/src/sources/HyperSync.resi +4 -0
- package/src/sources/HyperSyncClient.res +1 -1
- package/src/sources/HyperSyncHeightStream.res +47 -116
- package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
- package/src/sources/HyperSyncSource.res +118 -139
- package/src/sources/HyperSyncSource.res.mjs +104 -121
- package/src/sources/Rpc.res +86 -14
- package/src/sources/Rpc.res.mjs +101 -9
- package/src/sources/RpcSource.res +621 -364
- package/src/sources/RpcSource.res.mjs +843 -410
- package/src/sources/RpcWebSocketHeightStream.res +181 -0
- package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
- package/src/sources/Source.res +7 -5
- package/src/sources/SourceManager.res +325 -225
- package/src/sources/SourceManager.res.mjs +314 -171
- package/src/sources/SourceManager.resi +17 -6
- package/src/sources/Svm.res +81 -0
- package/src/sources/Svm.res.mjs +90 -0
- package/src/tui/Tui.res +247 -0
- package/src/tui/Tui.res.mjs +337 -0
- package/src/tui/bindings/Ink.res +371 -0
- package/src/tui/bindings/Ink.res.mjs +72 -0
- package/src/tui/bindings/Style.res +123 -0
- package/src/tui/bindings/Style.res.mjs +2 -0
- package/src/tui/components/BufferedProgressBar.res +40 -0
- package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
- package/src/tui/components/CustomHooks.res +122 -0
- package/src/tui/components/CustomHooks.res.mjs +179 -0
- package/src/tui/components/Messages.res +41 -0
- package/src/tui/components/Messages.res.mjs +75 -0
- package/src/tui/components/SyncETA.res +174 -0
- package/src/tui/components/SyncETA.res.mjs +263 -0
- package/src/tui/components/TuiData.res +47 -0
- package/src/tui/components/TuiData.res.mjs +34 -0
- package/svm.schema.json +112 -0
- package/bin.js +0 -48
- package/src/EventRegister.res +0 -241
- package/src/EventRegister.res.mjs +0 -240
- package/src/bindings/Ethers.gen.ts +0 -14
- package/src/bindings/Ethers.res +0 -204
- package/src/bindings/Ethers.res.mjs +0 -130
- /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
package/src/Hasura.res
CHANGED
|
@@ -46,19 +46,6 @@ let trackTablesRoute = Rest.route(() => {
|
|
|
46
46
|
responses,
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
let createSelectPermissionRoute = Rest.route(() => {
|
|
50
|
-
method: Post,
|
|
51
|
-
path: "",
|
|
52
|
-
input: s => {
|
|
53
|
-
let _ = s.field("type", S.literal("pg_create_select_permission"))
|
|
54
|
-
{
|
|
55
|
-
"args": s.field("args", S.json(~validate=false)),
|
|
56
|
-
"auth": s->auth,
|
|
57
|
-
}
|
|
58
|
-
},
|
|
59
|
-
responses,
|
|
60
|
-
})
|
|
61
|
-
|
|
62
49
|
let rawBodyRoute = Rest.route(() => {
|
|
63
50
|
method: Post,
|
|
64
51
|
path: "",
|
|
@@ -71,36 +58,33 @@ let rawBodyRoute = Rest.route(() => {
|
|
|
71
58
|
responses,
|
|
72
59
|
})
|
|
73
60
|
|
|
74
|
-
let
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
61
|
+
let sendOperation = async (~endpoint, ~auth, ~operation: Js.Json.t) => {
|
|
62
|
+
let maxRetries = 3
|
|
63
|
+
let rec retry = async (~attempt) => {
|
|
64
|
+
try {
|
|
65
|
+
let _ = await rawBodyRoute->Rest.fetch(
|
|
66
|
+
{
|
|
67
|
+
"bodyString": operation->Js.Json.stringify,
|
|
68
|
+
"auth": auth,
|
|
69
|
+
},
|
|
70
|
+
~client=Rest.client(endpoint),
|
|
71
|
+
)
|
|
72
|
+
} catch {
|
|
73
|
+
| exn =>
|
|
74
|
+
if attempt < maxRetries {
|
|
75
|
+
let backoffMs = Js.Math.pow_float(~base=2.0, ~exp=attempt->Belt.Int.toFloat)->Belt.Float.toInt * 1000
|
|
76
|
+
await Time.resolvePromiseAfterDelay(~delayMilliseconds=backoffMs)
|
|
77
|
+
await retry(~attempt=attempt + 1)
|
|
78
|
+
} else {
|
|
79
|
+
Logging.warn({
|
|
80
|
+
"msg": "Hasura configuration request failed. Indexing will still work - but you may have issues querying data via GraphQL.",
|
|
81
|
+
"err": exn->Utils.prettifyExn,
|
|
82
|
+
})
|
|
83
|
+
}
|
|
82
84
|
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
s.status(200)
|
|
87
|
-
s.data(S.json(~validate=false))
|
|
88
|
-
},
|
|
89
|
-
],
|
|
90
|
-
})
|
|
91
|
-
let bulkKeepGoingErrorsSchema = S.array(
|
|
92
|
-
S.union([
|
|
93
|
-
S.object(s => {
|
|
94
|
-
s.tag("message", "success")
|
|
95
|
-
None
|
|
96
|
-
}),
|
|
97
|
-
S.object(s => {
|
|
98
|
-
Some(s.field("error", S.string))
|
|
99
|
-
}),
|
|
100
|
-
]),
|
|
101
|
-
)->S.transform(_ => {
|
|
102
|
-
parser: a => Belt.Array.keepMapU(a, a => a),
|
|
103
|
-
})
|
|
85
|
+
}
|
|
86
|
+
await retry(~attempt=0)
|
|
87
|
+
}
|
|
104
88
|
|
|
105
89
|
let clearHasuraMetadata = async (~endpoint, ~auth) => {
|
|
106
90
|
try {
|
|
@@ -113,7 +97,7 @@ let clearHasuraMetadata = async (~endpoint, ~auth) => {
|
|
|
113
97
|
} catch {
|
|
114
98
|
| exn =>
|
|
115
99
|
Logging.error({
|
|
116
|
-
"msg": `
|
|
100
|
+
"msg": `There was an issue clearing metadata in hasura - indexing may still work - but you may have issues querying the data in hasura.`,
|
|
117
101
|
"err": exn->Utils.prettifyExn,
|
|
118
102
|
})
|
|
119
103
|
}
|
|
@@ -154,44 +138,47 @@ let trackTables = async (~endpoint, ~auth, ~pgSchema, ~tableNames: array<string>
|
|
|
154
138
|
} catch {
|
|
155
139
|
| exn =>
|
|
156
140
|
Logging.error({
|
|
157
|
-
"msg": `
|
|
141
|
+
"msg": `There was an issue tracking tables in hasura - indexing may still work - but you may have issues querying the data in hasura.`,
|
|
158
142
|
"tableNames": tableNames,
|
|
159
143
|
"err": exn->Utils.prettifyExn,
|
|
160
144
|
})
|
|
161
145
|
}
|
|
162
146
|
}
|
|
163
147
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
let createSelectPermissionOperation = (
|
|
148
|
+
let createSelectPermission = async (
|
|
149
|
+
~endpoint,
|
|
150
|
+
~auth,
|
|
170
151
|
~tableName: string,
|
|
171
152
|
~pgSchema,
|
|
172
153
|
~responseLimit,
|
|
173
154
|
~aggregateEntities,
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
|
|
155
|
+
) => {
|
|
156
|
+
await sendOperation(
|
|
157
|
+
~endpoint,
|
|
158
|
+
~auth,
|
|
159
|
+
~operation={
|
|
160
|
+
"type": "pg_create_select_permission",
|
|
161
|
+
"args": {
|
|
162
|
+
"table": {
|
|
163
|
+
"schema": pgSchema,
|
|
164
|
+
"name": tableName,
|
|
165
|
+
},
|
|
166
|
+
"role": "public",
|
|
167
|
+
"source": "default",
|
|
168
|
+
"permission": {
|
|
169
|
+
"columns": "*",
|
|
170
|
+
"filter": Js.Obj.empty(),
|
|
171
|
+
"limit": responseLimit,
|
|
172
|
+
"allow_aggregations": aggregateEntities->Js.Array2.includes(tableName),
|
|
173
|
+
},
|
|
189
174
|
},
|
|
190
175
|
}->(Utils.magic: 'a => Js.Json.t),
|
|
191
|
-
|
|
176
|
+
)
|
|
192
177
|
}
|
|
193
178
|
|
|
194
|
-
let
|
|
179
|
+
let createEntityRelationship = async (
|
|
180
|
+
~endpoint,
|
|
181
|
+
~auth,
|
|
195
182
|
~pgSchema,
|
|
196
183
|
~tableName: string,
|
|
197
184
|
~relationshipType: string,
|
|
@@ -199,73 +186,33 @@ let createEntityRelationshipOperation = (
|
|
|
199
186
|
~objectName: string,
|
|
200
187
|
~mappedEntity: string,
|
|
201
188
|
~isDerivedFrom: bool,
|
|
202
|
-
)
|
|
189
|
+
) => {
|
|
203
190
|
let derivedFromTo = isDerivedFrom ? `"id": "${relationalKey}"` : `"${relationalKey}_id" : "id"`
|
|
204
191
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
192
|
+
await sendOperation(
|
|
193
|
+
~endpoint,
|
|
194
|
+
~auth,
|
|
195
|
+
~operation={
|
|
196
|
+
"type": `pg_create_${relationshipType}_relationship`,
|
|
197
|
+
"args": {
|
|
198
|
+
"table": {
|
|
199
|
+
"schema": pgSchema,
|
|
200
|
+
"name": tableName,
|
|
201
|
+
},
|
|
202
|
+
"name": objectName,
|
|
203
|
+
"source": "default",
|
|
204
|
+
"using": {
|
|
205
|
+
"manual_configuration": {
|
|
206
|
+
"remote_table": {
|
|
207
|
+
"schema": pgSchema,
|
|
208
|
+
"name": mappedEntity,
|
|
209
|
+
},
|
|
210
|
+
"column_mapping": Js.Json.parseExn(`{${derivedFromTo}}`),
|
|
219
211
|
},
|
|
220
|
-
"column_mapping": Js.Json.parseExn(`{${derivedFromTo}}`),
|
|
221
212
|
},
|
|
222
213
|
},
|
|
223
214
|
}->(Utils.magic: 'a => Js.Json.t),
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
let executeBulkKeepGoing = async (~endpoint, ~auth, ~operations: array<bulkOperation>) => {
|
|
228
|
-
if operations->Js.Array2.length === 0 {
|
|
229
|
-
Logging.trace("No hasura bulk configuration operations to execute")
|
|
230
|
-
} else {
|
|
231
|
-
try {
|
|
232
|
-
let result = await bulkKeepGoingRoute->Rest.fetch(
|
|
233
|
-
{
|
|
234
|
-
"auth": auth,
|
|
235
|
-
"args": operations->(Utils.magic: 'a => Js.Json.t),
|
|
236
|
-
},
|
|
237
|
-
~client=Rest.client(endpoint),
|
|
238
|
-
)
|
|
239
|
-
|
|
240
|
-
let errors = try {
|
|
241
|
-
result->S.parseJsonOrThrow(bulkKeepGoingErrorsSchema)
|
|
242
|
-
} catch {
|
|
243
|
-
| S.Raised(error) => [error->S.Error.message]
|
|
244
|
-
| exn => [exn->Utils.prettifyExn->Utils.magic]
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
switch errors {
|
|
248
|
-
| [] =>
|
|
249
|
-
Logging.trace({
|
|
250
|
-
"msg": "Hasura configuration completed",
|
|
251
|
-
"operations": operations->Js.Array2.length,
|
|
252
|
-
})
|
|
253
|
-
| _ =>
|
|
254
|
-
Logging.warn({
|
|
255
|
-
"msg": "Hasura configuration completed with errors. Indexing will still work - but you may have issues querying data via GraphQL.",
|
|
256
|
-
"errors": errors,
|
|
257
|
-
"operations": operations->Js.Array2.length,
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
} catch {
|
|
261
|
-
| exn =>
|
|
262
|
-
Logging.error({
|
|
263
|
-
"msg": `EE809: There was an issue executing bulk operations in hasura - indexing may still work - but you may have issues querying the data in hasura.`,
|
|
264
|
-
"operations": operations->Js.Array2.length,
|
|
265
|
-
"err": exn->Utils.prettifyExn,
|
|
266
|
-
})
|
|
267
|
-
}
|
|
268
|
-
}
|
|
215
|
+
)
|
|
269
216
|
}
|
|
270
217
|
|
|
271
218
|
let trackDatabase = async (
|
|
@@ -291,64 +238,53 @@ let trackDatabase = async (
|
|
|
291
238
|
|
|
292
239
|
await trackTables(~endpoint, ~auth, ~pgSchema, ~tableNames)
|
|
293
240
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
tableNames->Js.Array2.forEach(tableName => {
|
|
299
|
-
allOperations
|
|
300
|
-
->Js.Array2.push(
|
|
301
|
-
createSelectPermissionOperation(~tableName, ~pgSchema, ~responseLimit, ~aggregateEntities),
|
|
302
|
-
)
|
|
303
|
-
->ignore
|
|
304
|
-
})
|
|
241
|
+
for i in 0 to tableNames->Js.Array2.length - 1 {
|
|
242
|
+
let tableName = tableNames->Js.Array2.unsafe_get(i)
|
|
243
|
+
await createSelectPermission(~endpoint, ~auth, ~tableName, ~pgSchema, ~responseLimit, ~aggregateEntities)
|
|
244
|
+
}
|
|
305
245
|
|
|
306
|
-
|
|
307
|
-
|
|
246
|
+
for i in 0 to userEntities->Js.Array2.length - 1 {
|
|
247
|
+
let entityConfig = userEntities->Js.Array2.unsafe_get(i)
|
|
308
248
|
let {tableName} = entityConfig.table
|
|
309
249
|
|
|
310
250
|
//Set array relationships
|
|
311
|
-
entityConfig.table
|
|
312
|
-
->
|
|
313
|
-
|
|
251
|
+
let derivedFromFields = entityConfig.table->Table.getDerivedFromFields
|
|
252
|
+
for j in 0 to derivedFromFields->Js.Array2.length - 1 {
|
|
253
|
+
let derivedFromField = derivedFromFields->Js.Array2.unsafe_get(j)
|
|
314
254
|
//determines the actual name of the underlying relational field (if it's an entity mapping then suffixes _id for eg.)
|
|
315
255
|
let relationalFieldName =
|
|
316
256
|
schema->Schema.getDerivedFromFieldName(derivedFromField)->Utils.unwrapResultExn
|
|
317
257
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
),
|
|
258
|
+
await createEntityRelationship(
|
|
259
|
+
~endpoint,
|
|
260
|
+
~auth,
|
|
261
|
+
~pgSchema,
|
|
262
|
+
~tableName,
|
|
263
|
+
~relationshipType="array",
|
|
264
|
+
~isDerivedFrom=true,
|
|
265
|
+
~objectName=derivedFromField.fieldName,
|
|
266
|
+
~relationalKey=relationalFieldName,
|
|
267
|
+
~mappedEntity=derivedFromField.derivedFromEntity,
|
|
329
268
|
)
|
|
330
|
-
|
|
331
|
-
})
|
|
269
|
+
}
|
|
332
270
|
|
|
333
271
|
//Set object relationships
|
|
334
|
-
entityConfig.table
|
|
335
|
-
->
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
),
|
|
272
|
+
let linkedEntityFields = entityConfig.table->Table.getLinkedEntityFields
|
|
273
|
+
for j in 0 to linkedEntityFields->Js.Array2.length - 1 {
|
|
274
|
+
let (field, linkedEntityName) = linkedEntityFields->Js.Array2.unsafe_get(j)
|
|
275
|
+
await createEntityRelationship(
|
|
276
|
+
~endpoint,
|
|
277
|
+
~auth,
|
|
278
|
+
~pgSchema,
|
|
279
|
+
~tableName,
|
|
280
|
+
~relationshipType="object",
|
|
281
|
+
~isDerivedFrom=false,
|
|
282
|
+
~objectName=field.fieldName,
|
|
283
|
+
~relationalKey=field.fieldName,
|
|
284
|
+
~mappedEntity=linkedEntityName,
|
|
348
285
|
)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
})
|
|
286
|
+
}
|
|
287
|
+
}
|
|
352
288
|
|
|
353
|
-
|
|
289
|
+
Logging.info("Hasura configuration completed")
|
|
354
290
|
}
|
package/src/Hasura.res.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Rest from "./vendored/Rest.res.mjs";
|
|
4
|
+
import * as Time from "./Time.res.mjs";
|
|
4
5
|
import * as Table from "./db/Table.res.mjs";
|
|
5
6
|
import * as Utils from "./Utils.res.mjs";
|
|
6
7
|
import * as Schema from "./db/Schema.res.mjs";
|
|
@@ -60,21 +61,6 @@ function trackTablesRoute() {
|
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
function createSelectPermissionRoute() {
|
|
64
|
-
return {
|
|
65
|
-
method: "POST",
|
|
66
|
-
path: "",
|
|
67
|
-
input: (function (s) {
|
|
68
|
-
s.field("type", S$RescriptSchema.literal("pg_create_select_permission"));
|
|
69
|
-
return {
|
|
70
|
-
args: s.field("args", S$RescriptSchema.json(false)),
|
|
71
|
-
auth: auth(s)
|
|
72
|
-
};
|
|
73
|
-
}),
|
|
74
|
-
responses: responses
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
64
|
function rawBodyRoute() {
|
|
79
65
|
return {
|
|
80
66
|
method: "POST",
|
|
@@ -89,41 +75,31 @@ function rawBodyRoute() {
|
|
|
89
75
|
};
|
|
90
76
|
}
|
|
91
77
|
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
78
|
+
async function sendOperation(endpoint, auth, operation) {
|
|
79
|
+
var retry = async function (attempt) {
|
|
80
|
+
try {
|
|
81
|
+
await Rest.$$fetch(rawBodyRoute, {
|
|
82
|
+
bodyString: JSON.stringify(operation),
|
|
83
|
+
auth: auth
|
|
84
|
+
}, Rest.client(endpoint, undefined));
|
|
85
|
+
return ;
|
|
86
|
+
}
|
|
87
|
+
catch (raw_exn){
|
|
88
|
+
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
89
|
+
if (attempt >= 3) {
|
|
90
|
+
return Logging.warn({
|
|
91
|
+
msg: "Hasura configuration request failed. Indexing will still work - but you may have issues querying data via GraphQL.",
|
|
92
|
+
err: Utils.prettifyExn(exn)
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
var backoffMs = Math.imul(Math.pow(2.0, attempt) | 0, 1000);
|
|
96
|
+
await Time.resolvePromiseAfterDelay(backoffMs);
|
|
97
|
+
return await retry(attempt + 1 | 0);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
return await retry(0);
|
|
108
101
|
}
|
|
109
102
|
|
|
110
|
-
var bulkKeepGoingErrorsSchema = S$RescriptSchema.transform(S$RescriptSchema.array(S$RescriptSchema.union([
|
|
111
|
-
S$RescriptSchema.object(function (s) {
|
|
112
|
-
s.tag("message", "success");
|
|
113
|
-
}),
|
|
114
|
-
S$RescriptSchema.object(function (s) {
|
|
115
|
-
return s.f("error", S$RescriptSchema.string);
|
|
116
|
-
})
|
|
117
|
-
])), (function (param) {
|
|
118
|
-
return {
|
|
119
|
-
p: (function (a) {
|
|
120
|
-
return Belt_Array.keepMapU(a, (function (a) {
|
|
121
|
-
return a;
|
|
122
|
-
}));
|
|
123
|
-
})
|
|
124
|
-
};
|
|
125
|
-
}));
|
|
126
|
-
|
|
127
103
|
async function clearHasuraMetadata(endpoint, auth) {
|
|
128
104
|
try {
|
|
129
105
|
var result = await Rest.$$fetch(clearMetadataRoute, auth, Rest.client(endpoint, undefined));
|
|
@@ -134,7 +110,7 @@ async function clearHasuraMetadata(endpoint, auth) {
|
|
|
134
110
|
catch (raw_exn){
|
|
135
111
|
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
136
112
|
return Logging.error({
|
|
137
|
-
msg: "
|
|
113
|
+
msg: "There was an issue clearing metadata in hasura - indexing may still work - but you may have issues querying the data in hasura.",
|
|
138
114
|
err: Utils.prettifyExn(exn)
|
|
139
115
|
});
|
|
140
116
|
}
|
|
@@ -169,95 +145,55 @@ async function trackTables(endpoint, auth, pgSchema, tableNames) {
|
|
|
169
145
|
catch (raw_exn){
|
|
170
146
|
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
171
147
|
return Logging.error({
|
|
172
|
-
msg: "
|
|
148
|
+
msg: "There was an issue tracking tables in hasura - indexing may still work - but you may have issues querying the data in hasura.",
|
|
173
149
|
tableNames: tableNames,
|
|
174
150
|
err: Utils.prettifyExn(exn)
|
|
175
151
|
});
|
|
176
152
|
}
|
|
177
153
|
}
|
|
178
154
|
|
|
179
|
-
function
|
|
180
|
-
return {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
155
|
+
async function createSelectPermission(endpoint, auth, tableName, pgSchema, responseLimit, aggregateEntities) {
|
|
156
|
+
return await sendOperation(endpoint, auth, {
|
|
157
|
+
type: "pg_create_select_permission",
|
|
158
|
+
args: {
|
|
159
|
+
table: {
|
|
160
|
+
schema: pgSchema,
|
|
161
|
+
name: tableName
|
|
162
|
+
},
|
|
163
|
+
role: "public",
|
|
164
|
+
source: "default",
|
|
165
|
+
permission: {
|
|
166
|
+
columns: "*",
|
|
167
|
+
filter: {},
|
|
168
|
+
limit: responseLimit,
|
|
169
|
+
allow_aggregations: aggregateEntities.includes(tableName)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
});
|
|
197
173
|
}
|
|
198
174
|
|
|
199
|
-
function
|
|
175
|
+
async function createEntityRelationship(endpoint, auth, pgSchema, tableName, relationshipType, relationalKey, objectName, mappedEntity, isDerivedFrom) {
|
|
200
176
|
var derivedFromTo = isDerivedFrom ? "\"id\": \"" + relationalKey + "\"" : "\"" + relationalKey + "_id\" : \"id\"";
|
|
201
|
-
return {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
schema: pgSchema,
|
|
206
|
-
name: tableName
|
|
207
|
-
},
|
|
208
|
-
name: objectName,
|
|
209
|
-
source: "default",
|
|
210
|
-
using: {
|
|
211
|
-
manual_configuration: {
|
|
212
|
-
remote_table: {
|
|
177
|
+
return await sendOperation(endpoint, auth, {
|
|
178
|
+
type: "pg_create_" + relationshipType + "_relationship",
|
|
179
|
+
args: {
|
|
180
|
+
table: {
|
|
213
181
|
schema: pgSchema,
|
|
214
|
-
name:
|
|
182
|
+
name: tableName
|
|
215
183
|
},
|
|
216
|
-
|
|
184
|
+
name: objectName,
|
|
185
|
+
source: "default",
|
|
186
|
+
using: {
|
|
187
|
+
manual_configuration: {
|
|
188
|
+
remote_table: {
|
|
189
|
+
schema: pgSchema,
|
|
190
|
+
name: mappedEntity
|
|
191
|
+
},
|
|
192
|
+
column_mapping: JSON.parse("{" + derivedFromTo + "}")
|
|
193
|
+
}
|
|
194
|
+
}
|
|
217
195
|
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async function executeBulkKeepGoing(endpoint, auth, operations) {
|
|
224
|
-
if (operations.length === 0) {
|
|
225
|
-
return Logging.trace("No hasura bulk configuration operations to execute");
|
|
226
|
-
}
|
|
227
|
-
try {
|
|
228
|
-
var result = await Rest.$$fetch(bulkKeepGoingRoute, {
|
|
229
|
-
auth: auth,
|
|
230
|
-
args: operations
|
|
231
|
-
}, Rest.client(endpoint, undefined));
|
|
232
|
-
var errors;
|
|
233
|
-
try {
|
|
234
|
-
errors = S$RescriptSchema.parseJsonOrThrow(result, bulkKeepGoingErrorsSchema);
|
|
235
|
-
}
|
|
236
|
-
catch (raw_error){
|
|
237
|
-
var error = Caml_js_exceptions.internalToOCamlException(raw_error);
|
|
238
|
-
errors = error.RE_EXN_ID === S$RescriptSchema.Raised ? [S$RescriptSchema.$$Error.message(error._1)] : [Utils.prettifyExn(error)];
|
|
239
|
-
}
|
|
240
|
-
if (errors.length !== 0) {
|
|
241
|
-
return Logging.warn({
|
|
242
|
-
msg: "Hasura configuration completed with errors. Indexing will still work - but you may have issues querying data via GraphQL.",
|
|
243
|
-
errors: errors,
|
|
244
|
-
operations: operations.length
|
|
245
|
-
});
|
|
246
|
-
} else {
|
|
247
|
-
return Logging.trace({
|
|
248
|
-
msg: "Hasura configuration completed",
|
|
249
|
-
operations: operations.length
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
catch (raw_exn){
|
|
254
|
-
var exn = Caml_js_exceptions.internalToOCamlException(raw_exn);
|
|
255
|
-
return Logging.error({
|
|
256
|
-
msg: "EE809: There was an issue executing bulk operations in hasura - indexing may still work - but you may have issues querying the data in hasura.",
|
|
257
|
-
operations: operations.length,
|
|
258
|
-
err: Utils.prettifyExn(exn)
|
|
259
|
-
});
|
|
260
|
-
}
|
|
196
|
+
});
|
|
261
197
|
}
|
|
262
198
|
|
|
263
199
|
async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEntities, responseLimit, schema) {
|
|
@@ -276,23 +212,28 @@ async function trackDatabase(endpoint, auth, pgSchema, userEntities, aggregateEn
|
|
|
276
212
|
Logging.info("Tracking tables in Hasura");
|
|
277
213
|
await clearHasuraMetadata(endpoint, auth);
|
|
278
214
|
await trackTables(endpoint, auth, pgSchema, tableNames);
|
|
279
|
-
var
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
userEntities.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
215
|
+
for(var i = 0 ,i_finish = tableNames.length; i < i_finish; ++i){
|
|
216
|
+
var tableName = tableNames[i];
|
|
217
|
+
await createSelectPermission(endpoint, auth, tableName, pgSchema, responseLimit, aggregateEntities);
|
|
218
|
+
}
|
|
219
|
+
for(var i$1 = 0 ,i_finish$1 = userEntities.length; i$1 < i_finish$1; ++i$1){
|
|
220
|
+
var entityConfig = userEntities[i$1];
|
|
221
|
+
var match = entityConfig.table;
|
|
222
|
+
var tableName$1 = match.tableName;
|
|
223
|
+
var derivedFromFields = Table.getDerivedFromFields(entityConfig.table);
|
|
224
|
+
for(var j = 0 ,j_finish = derivedFromFields.length; j < j_finish; ++j){
|
|
225
|
+
var derivedFromField = derivedFromFields[j];
|
|
226
|
+
var relationalFieldName = Utils.unwrapResultExn(Schema.getDerivedFromFieldName(schema, derivedFromField));
|
|
227
|
+
await createEntityRelationship(endpoint, auth, pgSchema, tableName$1, "array", relationalFieldName, derivedFromField.fieldName, derivedFromField.derivedFromEntity, true);
|
|
228
|
+
}
|
|
229
|
+
var linkedEntityFields = Table.getLinkedEntityFields(entityConfig.table);
|
|
230
|
+
for(var j$1 = 0 ,j_finish$1 = linkedEntityFields.length; j$1 < j_finish$1; ++j$1){
|
|
231
|
+
var match$1 = linkedEntityFields[j$1];
|
|
232
|
+
var field = match$1[0];
|
|
233
|
+
await createEntityRelationship(endpoint, auth, pgSchema, tableName$1, "object", field.fieldName, field.fieldName, match$1[1], false);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return Logging.info("Hasura configuration completed");
|
|
296
237
|
}
|
|
297
238
|
|
|
298
239
|
export {
|
|
@@ -300,15 +241,12 @@ export {
|
|
|
300
241
|
responses ,
|
|
301
242
|
clearMetadataRoute ,
|
|
302
243
|
trackTablesRoute ,
|
|
303
|
-
createSelectPermissionRoute ,
|
|
304
244
|
rawBodyRoute ,
|
|
305
|
-
|
|
306
|
-
bulkKeepGoingErrorsSchema ,
|
|
245
|
+
sendOperation ,
|
|
307
246
|
clearHasuraMetadata ,
|
|
308
247
|
trackTables ,
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
executeBulkKeepGoing ,
|
|
248
|
+
createSelectPermission ,
|
|
249
|
+
createEntityRelationship ,
|
|
312
250
|
trackDatabase ,
|
|
313
251
|
}
|
|
314
|
-
/*
|
|
252
|
+
/* Rest Not a pure module */
|
package/src/InMemoryStore.res
CHANGED
|
@@ -100,7 +100,7 @@ let isRollingBack = (inMemoryStore: t) => inMemoryStore.rollbackTargetCheckpoint
|
|
|
100
100
|
|
|
101
101
|
let setBatchDcs = (inMemoryStore: t, ~batch: Batch.t, ~shouldSaveHistory) => {
|
|
102
102
|
let inMemTable =
|
|
103
|
-
inMemoryStore->getInMemTable(~entityConfig=InternalTable.DynamicContractRegistry.
|
|
103
|
+
inMemoryStore->getInMemTable(~entityConfig=InternalTable.DynamicContractRegistry.entityConfig)
|
|
104
104
|
|
|
105
105
|
let itemIdx = ref(0)
|
|
106
106
|
|