envio 3.0.2 → 3.1.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/README.md +0 -1
- package/evm.schema.json +15 -8
- package/fuel.schema.json +19 -12
- package/index.d.ts +0 -2
- package/package.json +6 -7
- package/rescript.json +1 -1
- package/src/Batch.res +4 -214
- package/src/Batch.res.mjs +6 -165
- package/src/ChainFetcher.res +4 -5
- package/src/ChainFetcher.res.mjs +6 -7
- package/src/ChainManager.res +10 -9
- package/src/ChainManager.res.mjs +6 -10
- package/src/Config.res +9 -25
- package/src/Config.res.mjs +17 -27
- package/src/Core.res +7 -0
- package/src/Ctx.res +1 -0
- package/src/Env.res +0 -1
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +13 -123
- package/src/EventConfigBuilder.res.mjs +6 -73
- package/src/EventProcessing.res +5 -29
- package/src/EventProcessing.res.mjs +11 -20
- package/src/EventUtils.res +0 -27
- package/src/EventUtils.res.mjs +0 -24
- package/src/FetchState.res +1 -11
- package/src/FetchState.res.mjs +2 -16
- package/src/GlobalState.res +23 -37
- package/src/GlobalState.res.mjs +10 -38
- package/src/HandlerLoader.res +6 -5
- package/src/HandlerLoader.res.mjs +27 -9
- package/src/HandlerRegister.res +1 -12
- package/src/HandlerRegister.res.mjs +1 -6
- package/src/HandlerRegister.resi +1 -1
- package/src/Hasura.res +96 -32
- package/src/Hasura.res.mjs +93 -38
- package/src/InMemoryStore.res +181 -45
- package/src/InMemoryStore.res.mjs +143 -40
- package/src/InMemoryTable.res +147 -247
- package/src/InMemoryTable.res.mjs +131 -230
- package/src/Internal.res +10 -34
- package/src/Internal.res.mjs +9 -3
- package/src/LoadLayer.res +5 -5
- package/src/LoadLayer.res.mjs +5 -5
- package/src/Main.res +4 -6
- package/src/Main.res.mjs +26 -15
- package/src/Persistence.res +7 -132
- package/src/Persistence.res.mjs +1 -102
- package/src/PgStorage.res +57 -40
- package/src/PgStorage.res.mjs +60 -34
- package/src/ReorgDetection.res +35 -58
- package/src/ReorgDetection.res.mjs +21 -29
- package/src/SimulateItems.res.mjs +21 -3
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +1 -1
- package/src/TableIndices.res +9 -2
- package/src/TableIndices.res.mjs +7 -1
- package/src/TestIndexer.res +53 -60
- package/src/TestIndexer.res.mjs +77 -63
- package/src/TestIndexerProxyStorage.res +4 -14
- package/src/TestIndexerProxyStorage.res.mjs +1 -5
- package/src/UserContext.res +2 -4
- package/src/UserContext.res.mjs +4 -5
- package/src/Utils.res +0 -2
- package/src/Utils.res.mjs +0 -3
- package/src/bindings/ClickHouse.res +45 -38
- package/src/bindings/ClickHouse.res.mjs +16 -17
- package/src/bindings/Vitest.res +3 -0
- package/src/db/InternalTable.res +59 -18
- package/src/db/InternalTable.res.mjs +82 -51
- package/src/db/Table.res +9 -2
- package/src/db/Table.res.mjs +10 -7
- package/src/sources/EvmChain.res +32 -9
- package/src/sources/EvmChain.res.mjs +31 -4
- package/src/sources/HyperFuelSource.res +14 -57
- package/src/sources/HyperFuelSource.res.mjs +18 -38
- package/src/sources/HyperSync.res +36 -101
- package/src/sources/HyperSync.res.mjs +42 -96
- package/src/sources/HyperSync.resi +4 -22
- package/src/sources/HyperSyncClient.res +67 -245
- package/src/sources/HyperSyncClient.res.mjs +47 -46
- package/src/sources/HyperSyncSource.res +76 -147
- package/src/sources/HyperSyncSource.res.mjs +61 -114
- package/src/sources/RpcSource.res +43 -22
- package/src/sources/RpcSource.res.mjs +50 -35
- package/src/sources/SimulateSource.res +1 -7
- package/src/sources/SimulateSource.res.mjs +1 -7
- package/src/sources/Source.res +8 -1
- package/src/sources/SourceManager.res +9 -0
- package/src/sources/SourceManager.res.mjs +10 -0
- package/src/sources/SourceManager.resi +2 -0
- package/svm.schema.json +11 -4
package/src/InMemoryTable.res
CHANGED
|
@@ -1,55 +1,27 @@
|
|
|
1
|
-
type t<'key, 'val> = {
|
|
2
|
-
dict: dict<'val>,
|
|
3
|
-
hash: 'key => string,
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
let make = (~hash): t<'key, 'val> => {
|
|
7
|
-
dict: Dict.make(),
|
|
8
|
-
hash,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
let set = (self: t<'key, 'val>, key, value) => self.dict->Dict.set(key->self.hash, value)
|
|
12
|
-
|
|
13
|
-
let setByHash = (self: t<'key, 'val>, hash, value) => self.dict->Dict.set(hash, value)
|
|
14
|
-
|
|
15
|
-
let hasByHash = (self: t<'key, 'val>, hash) => {
|
|
16
|
-
self.dict->Utils.Dict.has(hash)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
let getUnsafeByHash = (self: t<'key, 'val>, hash) => {
|
|
20
|
-
self.dict->Dict.getUnsafe(hash)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let get = (self: t<'key, 'val>, key: 'key) =>
|
|
24
|
-
self.dict->Utils.Dict.dangerouslyGetNonOption(key->self.hash)
|
|
25
|
-
|
|
26
|
-
let values = (self: t<'key, 'val>) => self.dict->Dict.valuesToArray
|
|
27
|
-
|
|
28
|
-
let clone = (self: t<'key, 'val>) => {
|
|
29
|
-
...self,
|
|
30
|
-
dict: self.dict->Lodash.cloneDeep,
|
|
31
|
-
}
|
|
32
|
-
|
|
33
1
|
module Entity = {
|
|
34
2
|
type relatedEntityId = string
|
|
35
3
|
type indexWithRelatedIds = (TableIndices.Index.t, Utils.Set.t<relatedEntityId>)
|
|
36
|
-
|
|
37
|
-
type
|
|
38
|
-
|
|
39
|
-
type
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
4
|
+
// Keyed by TableIndices.Index.toString
|
|
5
|
+
type indicesSerializedToValue = dict<indexWithRelatedIds>
|
|
6
|
+
// Keyed by TableIndices.Index.getFieldName
|
|
7
|
+
type indexFieldNameToIndices = dict<indicesSerializedToValue>
|
|
8
|
+
|
|
9
|
+
type entityIndices = Utils.Set.t<TableIndices.Index.t>
|
|
10
|
+
type t = {
|
|
11
|
+
latestEntityChangeById: dict<Change.t<Internal.entity>>,
|
|
12
|
+
// Counts every recorded change (new latest ids and pushes to
|
|
13
|
+
// prevEntityChanges), kept in sync manually so InMemoryStore can gauge the
|
|
14
|
+
// store size without scanning every dict.
|
|
15
|
+
mutable changesCount: float,
|
|
16
|
+
prevEntityChanges: array<Change.t<Internal.entity>>,
|
|
17
|
+
indicesByEntityId: dict<entityIndices>,
|
|
46
18
|
fieldNameIndices: indexFieldNameToIndices,
|
|
47
19
|
}
|
|
48
20
|
|
|
49
21
|
// Helper to extract entity ID from any entity
|
|
50
22
|
exception UnexpectedIdNotDefinedOnEntity
|
|
51
|
-
let getEntityIdUnsafe = (entity:
|
|
52
|
-
switch (entity->(Utils.magic:
|
|
23
|
+
let getEntityIdUnsafe = (entity: Internal.entity): string =>
|
|
24
|
+
switch (entity->(Utils.magic: Internal.entity => {"id": option<string>}))["id"] {
|
|
53
25
|
| Some(id) => id
|
|
54
26
|
| None =>
|
|
55
27
|
UnexpectedIdNotDefinedOnEntity->ErrorHandling.mkLogAndRaise(
|
|
@@ -57,207 +29,176 @@ module Entity = {
|
|
|
57
29
|
)
|
|
58
30
|
}
|
|
59
31
|
|
|
32
|
+
let getOrCreateEntityIndices = (self: t, ~entityId) =>
|
|
33
|
+
switch self.indicesByEntityId->Utils.Dict.dangerouslyGetNonOption(entityId) {
|
|
34
|
+
| Some(s) => s
|
|
35
|
+
| None =>
|
|
36
|
+
let s = Utils.Set.make()
|
|
37
|
+
self.indicesByEntityId->Dict.set(entityId, s)
|
|
38
|
+
s
|
|
39
|
+
}
|
|
40
|
+
|
|
60
41
|
let makeIndicesSerializedToValue = (
|
|
61
42
|
~index,
|
|
62
43
|
~relatedEntityIds=Utils.Set.make(),
|
|
63
44
|
): indicesSerializedToValue => {
|
|
64
|
-
let empty = make(
|
|
65
|
-
empty->set(index, (index, relatedEntityIds))
|
|
45
|
+
let empty = Dict.make()
|
|
46
|
+
empty->Dict.set(index->TableIndices.Index.toString, (index, relatedEntityIds))
|
|
66
47
|
empty
|
|
67
48
|
}
|
|
68
49
|
|
|
69
|
-
let make = (): t
|
|
70
|
-
|
|
71
|
-
|
|
50
|
+
let make = (): t => {
|
|
51
|
+
latestEntityChangeById: Dict.make(),
|
|
52
|
+
changesCount: 0.,
|
|
53
|
+
prevEntityChanges: [],
|
|
54
|
+
indicesByEntityId: Dict.make(),
|
|
55
|
+
fieldNameIndices: Dict.make(),
|
|
72
56
|
}
|
|
73
57
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
58
|
+
// Drops the per-batch index state and rollback history, but keeps the
|
|
59
|
+
// already committed entities so the next batch can read them without
|
|
60
|
+
// hitting the database.
|
|
61
|
+
let resetButKeepLatestChanges = (self: t): t => {
|
|
62
|
+
...make(),
|
|
63
|
+
latestEntityChangeById: self.latestEntityChangeById,
|
|
64
|
+
// writeBatch already mutated this to subtract the dropped prevEntityChanges.
|
|
65
|
+
changesCount: self.changesCount,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let updateIndices = (self: t, ~entity: Internal.entity) => {
|
|
69
|
+
let entityId = entity->getEntityIdUnsafe
|
|
79
70
|
//Remove any invalid indices on entity
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
71
|
+
switch self.indicesByEntityId->Utils.Dict.dangerouslyGetNonOption(entityId) {
|
|
72
|
+
| None => ()
|
|
73
|
+
| Some(entityIndices) =>
|
|
74
|
+
entityIndices->Utils.Set.forEach(index => {
|
|
75
|
+
let fieldName = index->TableIndices.Index.getFieldName
|
|
76
|
+
let fieldValue =
|
|
77
|
+
entity
|
|
78
|
+
->(Utils.magic: Internal.entity => dict<TableIndices.FieldValue.t>)
|
|
79
|
+
->Dict.getUnsafe(fieldName)
|
|
80
|
+
if !(index->TableIndices.Index.evaluate(~fieldName, ~fieldValue)) {
|
|
81
|
+
entityIndices->Utils.Set.delete(index)->ignore
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
90
85
|
|
|
91
|
-
self.fieldNameIndices
|
|
86
|
+
self.fieldNameIndices
|
|
92
87
|
->Dict.keysToArray
|
|
93
88
|
->Array.forEach(fieldName => {
|
|
94
|
-
let indices = self.fieldNameIndices
|
|
89
|
+
let indices = self.fieldNameIndices->Dict.getUnsafe(fieldName)
|
|
95
90
|
// A missing key reads as `undefined`, which matches the `None` arm of
|
|
96
91
|
// `FieldValue.t` (`option<...>`). Mirror `addEmptyIndex` so nullable
|
|
97
92
|
// FK columns that were omitted on the set entity don't crash.
|
|
98
93
|
let fieldValue =
|
|
99
94
|
entity
|
|
100
|
-
->(Utils.magic:
|
|
95
|
+
->(Utils.magic: Internal.entity => dict<TableIndices.FieldValue.t>)
|
|
101
96
|
->Dict.getUnsafe(fieldName)
|
|
102
|
-
indices
|
|
103
|
-
->values
|
|
104
|
-
->Array.forEach(((index, relatedEntityIds)) => {
|
|
97
|
+
indices->Utils.Dict.forEach(((index, relatedEntityIds)) => {
|
|
105
98
|
if index->TableIndices.Index.evaluate(~fieldName, ~fieldValue) {
|
|
106
99
|
//Add entity id to indices and add index to entity indicies
|
|
107
|
-
relatedEntityIds->Utils.Set.add(
|
|
108
|
-
|
|
100
|
+
relatedEntityIds->Utils.Set.add(entityId)->ignore
|
|
101
|
+
self->getOrCreateEntityIndices(~entityId)->Utils.Set.add(index)->ignore
|
|
109
102
|
} else {
|
|
110
|
-
relatedEntityIds->Utils.Set.delete(
|
|
103
|
+
relatedEntityIds->Utils.Set.delete(entityId)->ignore
|
|
111
104
|
}
|
|
112
105
|
})
|
|
113
106
|
})
|
|
114
107
|
}
|
|
115
108
|
|
|
116
|
-
let deleteEntityFromIndices = (self: t
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
->
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
~allowOverWriteEntity=false,
|
|
134
|
-
) => {
|
|
135
|
-
let shouldWriteEntity =
|
|
136
|
-
allowOverWriteEntity ||
|
|
137
|
-
inMemTable.table.dict->Dict.get(key->inMemTable.table.hash)->Option.isNone
|
|
109
|
+
let deleteEntityFromIndices = (self: t, ~entityId: string) =>
|
|
110
|
+
switch self.indicesByEntityId->Utils.Dict.dangerouslyGetNonOption(entityId) {
|
|
111
|
+
| None => ()
|
|
112
|
+
| Some(entityIndices) =>
|
|
113
|
+
entityIndices->Utils.Set.forEach(index => {
|
|
114
|
+
switch self.fieldNameIndices
|
|
115
|
+
->Utils.Dict.dangerouslyGetNonOption(index->TableIndices.Index.getFieldName)
|
|
116
|
+
->Option.flatMap(indices =>
|
|
117
|
+
indices->Utils.Dict.dangerouslyGetNonOption(index->TableIndices.Index.toString)
|
|
118
|
+
) {
|
|
119
|
+
| Some((_index, relatedEntityIds)) =>
|
|
120
|
+
let _wasRemoved = relatedEntityIds->Utils.Set.delete(entityId)
|
|
121
|
+
| None => () //Unexpected index should exist if it is entityIndices
|
|
122
|
+
}
|
|
123
|
+
let _wasRemoved = entityIndices->Utils.Set.delete(index)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
138
126
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
127
|
+
let set = (inMemTable: t, ~committedCheckpointId, change: Change.t<Internal.entity>) => {
|
|
128
|
+
let entityId = change->Change.getEntityId
|
|
129
|
+
switch inMemTable.latestEntityChangeById->Utils.Dict.dangerouslyGetNonOption(entityId) {
|
|
130
|
+
| Some(prev) =>
|
|
131
|
+
let prevCheckpointId = prev->Change.getCheckpointId
|
|
132
|
+
if (
|
|
133
|
+
prevCheckpointId > committedCheckpointId &&
|
|
134
|
+
prevCheckpointId < change->Change.getCheckpointId
|
|
135
|
+
) {
|
|
136
|
+
inMemTable.prevEntityChanges->Array.push(prev)
|
|
137
|
+
inMemTable.changesCount = inMemTable.changesCount +. 1.
|
|
149
138
|
}
|
|
150
|
-
|
|
151
|
-
key->inMemTable.table.hash,
|
|
152
|
-
{
|
|
153
|
-
latest: entity,
|
|
154
|
-
status: Loaded,
|
|
155
|
-
entityIndices,
|
|
156
|
-
},
|
|
157
|
-
)
|
|
139
|
+
| None => inMemTable.changesCount = inMemTable.changesCount +. 1.
|
|
158
140
|
}
|
|
159
|
-
}
|
|
160
141
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
inMemTable
|
|
164
|
-
change: Change.t<'entity>,
|
|
165
|
-
~shouldSaveHistory,
|
|
166
|
-
~containsRollbackDiffChange=false,
|
|
167
|
-
) => {
|
|
168
|
-
//New entity row with only the latest update
|
|
169
|
-
@inline
|
|
170
|
-
let newStatus = () => Internal.Updated({
|
|
171
|
-
latestChange: change,
|
|
172
|
-
history: shouldSaveHistory
|
|
173
|
-
? [change]
|
|
174
|
-
: Utils.Array.immutableEmpty->(Utils.magic: array<unknown> => array<Change.t<'entity>>),
|
|
175
|
-
containsRollbackDiffChange,
|
|
176
|
-
})
|
|
177
|
-
let latest = switch change {
|
|
178
|
-
| Set({entity}) => Some(entity)
|
|
179
|
-
| Delete(_) => None
|
|
142
|
+
switch change {
|
|
143
|
+
| Set({entity}) => inMemTable->updateIndices(~entity)
|
|
144
|
+
| Delete({entityId}) => inMemTable->deleteEntityFromIndices(~entityId)
|
|
180
145
|
}
|
|
146
|
+
inMemTable.latestEntityChangeById->Dict.set(entityId, change)
|
|
147
|
+
}
|
|
181
148
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
149
|
+
// Only writes when the id isn't already present, so set always takes its
|
|
150
|
+
// None branch here (committedCheckpointId is never read).
|
|
151
|
+
let initValue = (
|
|
152
|
+
inMemTable: t,
|
|
153
|
+
~committedCheckpointId,
|
|
154
|
+
~key: string,
|
|
155
|
+
~entity: option<Internal.entity>,
|
|
156
|
+
) =>
|
|
157
|
+
if inMemTable.latestEntityChangeById->Utils.Dict.dangerouslyGetNonOption(key)->Option.isNone {
|
|
158
|
+
let change: Change.t<Internal.entity> = switch entity {
|
|
159
|
+
| Some(entity) =>
|
|
160
|
+
Set({entityId: key, entity, checkpointId: Internal.loadedFromDbCheckpointId})
|
|
161
|
+
| None => Delete({entityId: key, checkpointId: Internal.loadedFromDbCheckpointId})
|
|
188
162
|
}
|
|
189
|
-
|
|
190
|
-
let newStatus = Internal.Updated({
|
|
191
|
-
latestChange: change,
|
|
192
|
-
history: switch shouldSaveHistory {
|
|
193
|
-
// This prevents two db actions in the same event on the same entity from being recorded to the history table.
|
|
194
|
-
| true
|
|
195
|
-
if previous_values.latestChange->Change.getCheckpointId ===
|
|
196
|
-
change->Change.getCheckpointId =>
|
|
197
|
-
previous_values.history->Utils.Array.setIndexImmutable(
|
|
198
|
-
previous_values.history->Array.length - 1,
|
|
199
|
-
change,
|
|
200
|
-
)
|
|
201
|
-
| true => [...previous_values.history, change]
|
|
202
|
-
| false => previous_values.history
|
|
203
|
-
},
|
|
204
|
-
containsRollbackDiffChange: previous_values.containsRollbackDiffChange,
|
|
205
|
-
})
|
|
206
|
-
{latest, status: newStatus, entityIndices}
|
|
163
|
+
inMemTable->set(~committedCheckpointId, change)
|
|
207
164
|
}
|
|
208
165
|
|
|
166
|
+
let mapChangeToEntity = (change: Change.t<Internal.entity>) =>
|
|
209
167
|
switch change {
|
|
210
|
-
| Set({entity}) =>
|
|
211
|
-
|
|
212
|
-
| Delete({entityId}) =>
|
|
213
|
-
inMemTable->deleteEntityFromIndices(
|
|
214
|
-
~entityId,
|
|
215
|
-
~entityIndices=updatedEntityRecord.entityIndices,
|
|
216
|
-
)
|
|
168
|
+
| Set({entity}) => Some(entity)
|
|
169
|
+
| Delete(_) => None
|
|
217
170
|
}
|
|
218
|
-
inMemTable.table->setRow(change->Change.getEntityId, updatedEntityRecord)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
let rowToEntity = row => row.latest
|
|
222
|
-
|
|
223
|
-
let getRow = get
|
|
224
171
|
|
|
225
172
|
/** It returns option<option<'entity>> where the first option means
|
|
226
173
|
that the entity is not set to the in memory store,
|
|
227
174
|
and the second option means that the entity doesn't esist/deleted.
|
|
228
175
|
It's needed to prevent an additional round trips to the database for deleted entities. */
|
|
229
|
-
let getUnsafe = (inMemTable: t
|
|
176
|
+
let getUnsafe = (inMemTable: t) =>
|
|
230
177
|
(key: string) =>
|
|
231
|
-
inMemTable.
|
|
178
|
+
inMemTable.latestEntityChangeById
|
|
232
179
|
->Dict.getUnsafe(key)
|
|
233
|
-
->
|
|
180
|
+
->mapChangeToEntity
|
|
234
181
|
|
|
235
|
-
let hasIndex = (inMemTable: t
|
|
182
|
+
let hasIndex = (inMemTable: t, ~fieldName, ~operator: TableIndices.Operator.t) =>
|
|
236
183
|
fieldValueHash => {
|
|
237
|
-
switch inMemTable.fieldNameIndices
|
|
184
|
+
switch inMemTable.fieldNameIndices->Utils.Dict.dangerouslyGetNonOption(fieldName) {
|
|
238
185
|
| None => false
|
|
239
186
|
| Some(indicesSerializedToValue) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
indicesSerializedToValue.dict->Utils.Dict.dangerouslyGetNonOption(key) !== None
|
|
187
|
+
let key = TableIndices.Index.toStringByParts(~fieldName, ~operator, ~fieldValueHash)
|
|
188
|
+
indicesSerializedToValue->Utils.Dict.dangerouslyGetNonOption(key) !== None
|
|
243
189
|
}
|
|
244
190
|
}
|
|
245
191
|
}
|
|
246
192
|
|
|
247
|
-
let getUnsafeOnIndex = (
|
|
248
|
-
inMemTable: t<'entity>,
|
|
249
|
-
~fieldName,
|
|
250
|
-
~operator: TableIndices.Operator.t,
|
|
251
|
-
) => {
|
|
193
|
+
let getUnsafeOnIndex = (inMemTable: t, ~fieldName, ~operator: TableIndices.Operator.t) => {
|
|
252
194
|
let getEntity = inMemTable->getUnsafe
|
|
253
195
|
fieldValueHash => {
|
|
254
|
-
switch inMemTable.fieldNameIndices
|
|
196
|
+
switch inMemTable.fieldNameIndices->Utils.Dict.dangerouslyGetNonOption(fieldName) {
|
|
255
197
|
| None =>
|
|
256
198
|
JsError.throwWithMessage(`Unexpected error. Must have an index on field ${fieldName}`)
|
|
257
199
|
| Some(indicesSerializedToValue) => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
switch indicesSerializedToValue.dict->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
200
|
+
let key = TableIndices.Index.toStringByParts(~fieldName, ~operator, ~fieldValueHash)
|
|
201
|
+
switch indicesSerializedToValue->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
261
202
|
| None =>
|
|
262
203
|
JsError.throwWithMessage(
|
|
263
204
|
`Unexpected error. Must have an index for the value ${fieldValueHash} on field ${fieldName}`,
|
|
@@ -267,7 +208,7 @@ module Entity = {
|
|
|
267
208
|
relatedEntityIds
|
|
268
209
|
->Utils.Set.toArray
|
|
269
210
|
->Array.filterMap(entityId => {
|
|
270
|
-
switch
|
|
211
|
+
switch inMemTable.latestEntityChangeById->Dict.has(entityId) {
|
|
271
212
|
| true => getEntity(entityId)
|
|
272
213
|
| false => None
|
|
273
214
|
}
|
|
@@ -280,83 +221,42 @@ module Entity = {
|
|
|
280
221
|
}
|
|
281
222
|
}
|
|
282
223
|
|
|
283
|
-
let addEmptyIndex = (inMemTable: t
|
|
224
|
+
let addEmptyIndex = (inMemTable: t, ~index) => {
|
|
284
225
|
let fieldName = index->TableIndices.Index.getFieldName
|
|
285
226
|
let relatedEntityIds = Utils.Set.make()
|
|
286
227
|
|
|
287
|
-
inMemTable.
|
|
288
|
-
|
|
289
|
-
->Array.forEach(row => {
|
|
290
|
-
switch row->rowToEntity {
|
|
228
|
+
inMemTable.latestEntityChangeById->Utils.Dict.forEach(change => {
|
|
229
|
+
switch change->mapChangeToEntity {
|
|
291
230
|
| Some(entity) =>
|
|
292
231
|
let fieldValue =
|
|
293
232
|
entity
|
|
294
|
-
->(Utils.magic:
|
|
233
|
+
->(Utils.magic: Internal.entity => dict<TableIndices.FieldValue.t>)
|
|
295
234
|
->Dict.getUnsafe(fieldName)
|
|
296
235
|
if index->TableIndices.Index.evaluate(~fieldName, ~fieldValue) {
|
|
297
|
-
let
|
|
298
|
-
let _ =
|
|
236
|
+
let entityId = entity->getEntityIdUnsafe
|
|
237
|
+
let _ = inMemTable->getOrCreateEntityIndices(~entityId)->Utils.Set.add(index)
|
|
238
|
+
let _ = relatedEntityIds->Utils.Set.add(entityId)
|
|
299
239
|
}
|
|
300
240
|
| None => ()
|
|
301
241
|
}
|
|
302
242
|
})
|
|
303
|
-
switch inMemTable.fieldNameIndices->
|
|
243
|
+
switch inMemTable.fieldNameIndices->Utils.Dict.dangerouslyGetNonOption(fieldName) {
|
|
304
244
|
| None =>
|
|
305
|
-
inMemTable.fieldNameIndices->
|
|
306
|
-
|
|
245
|
+
inMemTable.fieldNameIndices->Dict.set(
|
|
246
|
+
fieldName,
|
|
307
247
|
makeIndicesSerializedToValue(~index, ~relatedEntityIds),
|
|
308
248
|
)
|
|
309
249
|
| Some(indicesSerializedToValue) =>
|
|
310
|
-
switch indicesSerializedToValue->
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
let addIdToIndex = (inMemTable: t<'entity>, ~index, ~entityId) =>
|
|
318
|
-
switch inMemTable.fieldNameIndices->getRow(index) {
|
|
319
|
-
| None =>
|
|
320
|
-
inMemTable.fieldNameIndices->setRow(
|
|
321
|
-
index,
|
|
322
|
-
makeIndicesSerializedToValue(
|
|
323
|
-
~index,
|
|
324
|
-
~relatedEntityIds=Utils.Set.make()->Utils.Set.add(entityId),
|
|
325
|
-
),
|
|
326
|
-
)
|
|
327
|
-
| Some(indicesSerializedToValue) =>
|
|
328
|
-
switch indicesSerializedToValue->getRow(index) {
|
|
250
|
+
switch indicesSerializedToValue->Utils.Dict.dangerouslyGetNonOption(
|
|
251
|
+
index->TableIndices.Index.toString,
|
|
252
|
+
) {
|
|
329
253
|
| None =>
|
|
330
|
-
indicesSerializedToValue->
|
|
331
|
-
|
|
254
|
+
indicesSerializedToValue->Dict.set(
|
|
255
|
+
index->TableIndices.Index.toString,
|
|
256
|
+
(index, relatedEntityIds),
|
|
257
|
+
)
|
|
258
|
+
| Some(_) => () //Should not happen, this means the index already exists
|
|
332
259
|
}
|
|
333
260
|
}
|
|
334
|
-
|
|
335
|
-
let updates = (inMemTable: t<'entity>) => {
|
|
336
|
-
inMemTable.table
|
|
337
|
-
->values
|
|
338
|
-
->Array.filterMap(v =>
|
|
339
|
-
switch v.status {
|
|
340
|
-
| Updated(update) => Some(update)
|
|
341
|
-
| Loaded => None
|
|
342
|
-
}
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
let values = (inMemTable: t<'entity>) => {
|
|
347
|
-
inMemTable.table
|
|
348
|
-
->values
|
|
349
|
-
->Array.filterMap(rowToEntity)
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
let clone = ({table, fieldNameIndices}: t<'entity>) => {
|
|
353
|
-
table: table->clone,
|
|
354
|
-
fieldNameIndices: {
|
|
355
|
-
...fieldNameIndices,
|
|
356
|
-
dict: fieldNameIndices.dict
|
|
357
|
-
->Dict.toArray
|
|
358
|
-
->Array.map(((k, v)) => (k, v->clone))
|
|
359
|
-
->Dict.fromArray,
|
|
360
|
-
},
|
|
361
261
|
}
|
|
362
262
|
}
|