envio 3.5.0-alpha.3 → 3.5.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/package.json +6 -6
- package/src/Batch.res +8 -8
- package/src/Batch.res.mjs +4 -3
- package/src/BatchProcessing.res +17 -7
- package/src/BatchProcessing.res.mjs +8 -4
- package/src/ChainFetching.res +20 -19
- package/src/ChainFetching.res.mjs +14 -14
- package/src/ChainId.res +58 -0
- package/src/ChainId.res.mjs +49 -0
- package/src/ChainId.resi +27 -0
- package/src/ChainMap.res +12 -26
- package/src/ChainMap.res.mjs +5 -41
- package/src/ChainMap.resi +5 -20
- package/src/ChainMetadata.res +1 -1
- package/src/ChainMetadata.res.mjs +3 -2
- package/src/ChainState.res +35 -20
- package/src/ChainState.res.mjs +34 -11
- package/src/ChainState.resi +2 -0
- package/src/Config.res +41 -24
- package/src/Config.res.mjs +17 -14
- package/src/ContractRegisterContext.res +1 -1
- package/src/ContractRegisterContext.res.mjs +1 -1
- package/src/Core.res +1 -0
- package/src/CrossChainState.res +61 -16
- package/src/CrossChainState.res.mjs +37 -13
- package/src/CrossChainState.resi +3 -2
- package/src/Env.res +0 -3
- package/src/Env.res.mjs +0 -3
- package/src/EventConfigBuilder.res +1 -1
- package/src/EventProcessing.res +4 -4
- package/src/EventProcessing.res.mjs +5 -5
- package/src/FetchState.res +261 -89
- package/src/FetchState.res.mjs +187 -63
- package/src/FinalizeBackfill.res +33 -6
- package/src/FinalizeBackfill.res.mjs +19 -1
- package/src/HandlerRegister.res +8 -8
- package/src/HandlerRegister.res.mjs +5 -4
- package/src/HandlerRegister.resi +1 -1
- package/src/InMemoryStore.res +4 -0
- package/src/InMemoryStore.res.mjs +1 -1
- package/src/IndexerLoop.res +9 -2
- package/src/IndexerLoop.res.mjs +8 -1
- package/src/IndexerState.res +41 -24
- package/src/IndexerState.res.mjs +36 -17
- package/src/IndexerState.resi +9 -7
- package/src/Internal.res +19 -17
- package/src/Internal.res.mjs +18 -9
- package/src/LoadLayer.res +1 -1
- package/src/LoadLayer.res.mjs +2 -1
- package/src/LogSelection.res +2 -2
- package/src/Main.res +7 -11
- package/src/Main.res.mjs +4 -6
- package/src/Metrics.res +6 -6
- package/src/Metrics.res.mjs +4 -3
- package/src/Persistence.res +15 -7
- package/src/PgStorage.res +284 -258
- package/src/PgStorage.res.mjs +181 -208
- package/src/RawEvent.res +1 -2
- package/src/RawEvent.res.mjs +1 -1
- package/src/Rollback.res +18 -20
- package/src/Rollback.res.mjs +9 -9
- package/src/RollbackCommit.res +2 -2
- package/src/RollbackCommit.res.mjs +3 -3
- package/src/SafeCheckpointTracking.res +2 -2
- package/src/SimulateDeadInputTracker.res +17 -21
- package/src/SimulateDeadInputTracker.res.mjs +9 -8
- package/src/SimulateItems.res +8 -10
- package/src/SimulateItems.res.mjs +9 -10
- package/src/Sink.res +2 -2
- package/src/Sink.res.mjs +3 -2
- package/src/TestIndexer.res +11 -14
- package/src/TestIndexer.res.mjs +14 -10
- package/src/UserContext.res +2 -2
- package/src/UserContext.res.mjs +2 -1
- package/src/Utils.res +0 -4
- package/src/Utils.res.mjs +1 -6
- package/src/bindings/ClickHouse.res +20 -2
- package/src/bindings/ClickHouse.res.mjs +25 -14
- package/src/db/EntityHistory.res +1 -1
- package/src/db/IndexCatalog.res +248 -0
- package/src/db/IndexCatalog.res.mjs +222 -0
- package/src/db/IndexDefinition.res +131 -0
- package/src/db/IndexDefinition.res.mjs +138 -0
- package/src/db/IndexManager.res +145 -0
- package/src/db/IndexManager.res.mjs +130 -0
- package/src/db/InternalTable.res +50 -26
- package/src/db/InternalTable.res.mjs +32 -24
- package/src/db/Table.res +11 -1
- package/src/db/Table.res.mjs +9 -4
- package/src/sources/AddressSet.res +5 -4
- package/src/sources/AddressStore.res +25 -14
- package/src/sources/AddressStore.res.mjs +10 -12
- package/src/sources/Evm.res +2 -2
- package/src/sources/Evm.res.mjs +1 -1
- package/src/sources/EvmChain.res +3 -3
- package/src/sources/EvmChain.res.mjs +3 -3
- package/src/sources/EvmHyperSyncSource.res +7 -7
- package/src/sources/EvmHyperSyncSource.res.mjs +6 -6
- package/src/sources/Fuel.res +2 -2
- package/src/sources/Fuel.res.mjs +1 -1
- package/src/sources/FuelHyperSyncClient.res +3 -0
- package/src/sources/FuelHyperSyncClient.res.mjs +1 -0
- package/src/sources/FuelHyperSyncSource.res +5 -7
- package/src/sources/FuelHyperSyncSource.res.mjs +5 -5
- package/src/sources/HyperSync.resi +2 -2
- package/src/sources/HyperSyncClient.res +5 -0
- package/src/sources/HyperSyncClient.res.mjs +1 -0
- package/src/sources/RpcSource.res +13 -14
- package/src/sources/RpcSource.res.mjs +13 -12
- package/src/sources/SimulateSource.res +42 -15
- package/src/sources/SimulateSource.res.mjs +27 -9
- package/src/sources/Source.res +1 -5
- package/src/sources/SourceManager.res +12 -12
- package/src/sources/SourceManager.res.mjs +11 -10
- package/src/sources/SourceManager.resi +2 -2
- package/src/sources/Svm.res +4 -5
- package/src/sources/Svm.res.mjs +5 -4
- package/src/sources/SvmHyperSyncClient.res +3 -0
- package/src/sources/SvmHyperSyncClient.res.mjs +1 -0
- package/src/sources/SvmHyperSyncSource.res +4 -4
- package/src/sources/SvmHyperSyncSource.res.mjs +3 -3
- package/src/tui/Tui.res +1 -1
- package/src/tui/Tui.res.mjs +2 -1
- package/src/tui/components/CustomHooks.res +5 -4
- package/src/tui/components/CustomHooks.res.mjs +4 -2
- package/src/db/IndexRegistry.res +0 -219
- package/src/db/IndexRegistry.res.mjs +0 -195
package/src/db/IndexRegistry.res
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
// An in-memory mirror of the indexes PostgreSQL holds for the indexer schema.
|
|
2
|
-
// Postgres stays authoritative: the registry is loaded from pg_catalog at
|
|
3
|
-
// startup/resume and afterwards only grows — optimistically, right after a
|
|
4
|
-
// CREATE INDEX we issued succeeds. Only one Indexer instance writes to the
|
|
5
|
-
// schema, so no catalog refresh is needed between those two points.
|
|
6
|
-
|
|
7
|
-
let btree = "btree"
|
|
8
|
-
|
|
9
|
-
type column = {
|
|
10
|
-
name: string,
|
|
11
|
-
direction: Table.indexFieldDirection,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
let fromIndexFields = (indexFields: array<Table.compositeIndexField>) =>
|
|
15
|
-
indexFields->Array.map(({fieldName, direction}) => {name: fieldName, direction})
|
|
16
|
-
|
|
17
|
-
// Identity of an index is table + ordered columns + direction + method. Names
|
|
18
|
-
// are deliberately not part of it: the catalog is matched on what the index
|
|
19
|
-
// actually covers, not on how it was spelled.
|
|
20
|
-
let makeKey = (~tableName, ~columns: array<column>, ~method) =>
|
|
21
|
-
`${tableName}|${method}|${columns
|
|
22
|
-
->Array.map(({name, direction}) =>
|
|
23
|
-
switch direction {
|
|
24
|
-
| Table.Asc => name
|
|
25
|
-
| Desc => name ++ " DESC"
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
->Array.joinUnsafe(",")}`
|
|
29
|
-
|
|
30
|
-
type catalogRow = {
|
|
31
|
-
tableName: string,
|
|
32
|
-
indexName: string,
|
|
33
|
-
method: string,
|
|
34
|
-
// 1/0 rather than a bool: postgres.js hands booleans back inconsistently
|
|
35
|
-
// depending on the driver's type resolution, so the query casts it.
|
|
36
|
-
isValid: int,
|
|
37
|
-
// 1 only for an index the indexer could have created: plain btree over plain
|
|
38
|
-
// columns. A unique or partial index carries a definition our key doesn't
|
|
39
|
-
// capture, so it can never be one of ours to rebuild.
|
|
40
|
-
isPlain: int,
|
|
41
|
-
columns: array<string>,
|
|
42
|
-
// "ASC"/"DESC" per column, in the same order as `columns`.
|
|
43
|
-
directions: array<string>,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let catalogRowsSchema = S.array(
|
|
47
|
-
S.object((s): catalogRow => {
|
|
48
|
-
tableName: s.field("tableName", S.string),
|
|
49
|
-
indexName: s.field("indexName", S.string),
|
|
50
|
-
method: s.field("method", S.string),
|
|
51
|
-
isValid: s.field("isValid", S.int),
|
|
52
|
-
isPlain: s.field("isPlain", S.int),
|
|
53
|
-
columns: s.field("columns", S.array(S.string)),
|
|
54
|
-
directions: s.field("directions", S.array(S.string)),
|
|
55
|
-
}),
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
// One row per index, with its key columns aggregated in ordinal order.
|
|
59
|
-
// INCLUDE columns are excluded (they don't affect what the index can serve),
|
|
60
|
-
// and expression columns come back as their printed definition so an
|
|
61
|
-
// expression index can never be mistaken for a plain-column one.
|
|
62
|
-
let makeCatalogQuery = (~pgSchema) =>
|
|
63
|
-
`SELECT
|
|
64
|
-
t.relname AS "tableName",
|
|
65
|
-
i.relname AS "indexName",
|
|
66
|
-
am.amname AS "method",
|
|
67
|
-
CASE WHEN ix.indisvalid AND ix.indisready THEN 1 ELSE 0 END AS "isValid",
|
|
68
|
-
CASE
|
|
69
|
-
WHEN ix.indisunique OR ix.indpred IS NOT NULL OR ix.indexprs IS NOT NULL THEN 0
|
|
70
|
-
ELSE 1
|
|
71
|
-
END AS "isPlain",
|
|
72
|
-
array_agg(
|
|
73
|
-
CASE WHEN k.attnum = 0
|
|
74
|
-
THEN pg_get_indexdef(ix.indexrelid, k.ord::int, true)
|
|
75
|
-
ELSE a.attname
|
|
76
|
-
END ORDER BY k.ord
|
|
77
|
-
) AS "columns",
|
|
78
|
-
array_agg(
|
|
79
|
-
CASE WHEN (ix.indoption[k.ord - 1] & 1) = 1 THEN 'DESC' ELSE 'ASC' END ORDER BY k.ord
|
|
80
|
-
) AS "directions"
|
|
81
|
-
FROM pg_index ix
|
|
82
|
-
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
83
|
-
JOIN pg_class t ON t.oid = ix.indrelid
|
|
84
|
-
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
85
|
-
JOIN pg_am am ON am.oid = i.relam
|
|
86
|
-
JOIN LATERAL unnest(ix.indkey) WITH ORDINALITY AS k(attnum, ord) ON k.ord <= ix.indnkeyatts
|
|
87
|
-
LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
|
|
88
|
-
WHERE n.nspname = '${pgSchema}'
|
|
89
|
-
GROUP BY t.relname, i.relname, am.amname, ix.indisvalid, ix.indisready,
|
|
90
|
-
ix.indisunique, ix.indpred, ix.indexprs;`
|
|
91
|
-
|
|
92
|
-
// What we know about an index that came back invalid, enough to decide whether
|
|
93
|
-
// rebuilding it would produce the index we actually wanted.
|
|
94
|
-
type invalidIndex = {
|
|
95
|
-
key: string,
|
|
96
|
-
isRepairable: bool,
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
type t = {
|
|
100
|
-
keys: Utils.Set.t<string>,
|
|
101
|
-
// Every index Postgres reports as invalid, by name. Kept because
|
|
102
|
-
// `CREATE INDEX IF NOT EXISTS` matches on name: with an invalid index already
|
|
103
|
-
// under the name we want, the DDL is a silent no-op and we'd register a key
|
|
104
|
-
// for something the planner refuses to use.
|
|
105
|
-
invalidByName: dict<invalidIndex>,
|
|
106
|
-
// Keyed by index key so identical concurrent requests await one build.
|
|
107
|
-
inflight: dict<promise<unit>>,
|
|
108
|
-
// Tail of the build chain per table, so two different indexes on the same
|
|
109
|
-
// table are built one after the other rather than at once.
|
|
110
|
-
tableQueue: dict<promise<unit>>,
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
let make = () => {
|
|
114
|
-
keys: Utils.Set.make(),
|
|
115
|
-
invalidByName: Dict.make(),
|
|
116
|
-
inflight: Dict.make(),
|
|
117
|
-
tableQueue: Dict.make(),
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
let has = (registry, key) => registry.keys->Utils.Set.has(key)
|
|
121
|
-
|
|
122
|
-
let add = (registry, key) => registry.keys->Utils.Set.add(key)->ignore
|
|
123
|
-
|
|
124
|
-
let size = registry => registry.keys->Utils.Set.size
|
|
125
|
-
|
|
126
|
-
let toArray = registry => registry.keys->Utils.Set.toArray->Array.toSorted(String.compare)
|
|
127
|
-
|
|
128
|
-
// A plain CREATE INDEX either commits or leaves nothing behind, so an index can
|
|
129
|
-
// only be invalid because something before us left it that way — the startup
|
|
130
|
-
// snapshot stays accurate until the next restart.
|
|
131
|
-
let getInvalid = (registry, name) => registry.invalidByName->Utils.Dict.dangerouslyGetNonOption(name)
|
|
132
|
-
|
|
133
|
-
let clearInvalidName = (registry, name) => registry.invalidByName->Utils.Dict.deleteInPlace(name)
|
|
134
|
-
|
|
135
|
-
// Replaces the whole registry with what the catalog reports. Returns the names
|
|
136
|
-
// of indexes Postgres flagged invalid (eg a CREATE INDEX CONCURRENTLY that died
|
|
137
|
-
// midway). They stay out of the registry, so the next request that needs one
|
|
138
|
-
// repairs it.
|
|
139
|
-
let reload = (registry, ~rows: array<catalogRow>) => {
|
|
140
|
-
registry.keys->Utils.Set.clear
|
|
141
|
-
registry.invalidByName
|
|
142
|
-
->Dict.keysToArray
|
|
143
|
-
->Array.forEach(name => registry.invalidByName->Utils.Dict.deleteInPlace(name))
|
|
144
|
-
let invalidIndexNames = []
|
|
145
|
-
rows->Array.forEach(row => {
|
|
146
|
-
let key = makeKey(
|
|
147
|
-
~tableName=row.tableName,
|
|
148
|
-
~columns=row.columns->Array.mapWithIndex((name, idx) => {
|
|
149
|
-
name,
|
|
150
|
-
direction: switch row.directions->Array.get(idx) {
|
|
151
|
-
| Some("DESC") => Table.Desc
|
|
152
|
-
| _ => Asc
|
|
153
|
-
},
|
|
154
|
-
}),
|
|
155
|
-
~method=row.method,
|
|
156
|
-
)
|
|
157
|
-
if row.isValid === 0 {
|
|
158
|
-
invalidIndexNames->Array.push(row.indexName)->ignore
|
|
159
|
-
registry.invalidByName->Dict.set(row.indexName, {key, isRepairable: row.isPlain === 1})
|
|
160
|
-
} else {
|
|
161
|
-
registry->add(key)
|
|
162
|
-
}
|
|
163
|
-
})
|
|
164
|
-
invalidIndexNames
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Runs `build` unless the index is already registered. The key is added only
|
|
168
|
-
// after `build` resolves, so a failed build leaves the registry untouched and
|
|
169
|
-
// the next request retries.
|
|
170
|
-
let ensure = (registry, ~key, ~tableName, ~build) =>
|
|
171
|
-
if registry->has(key) {
|
|
172
|
-
Promise.resolve()
|
|
173
|
-
} else {
|
|
174
|
-
switch registry.inflight->Utils.Dict.dangerouslyGetNonOption(key) {
|
|
175
|
-
| Some(promise) => promise
|
|
176
|
-
| None =>
|
|
177
|
-
let tail = switch registry.tableQueue->Utils.Dict.dangerouslyGetNonOption(tableName) {
|
|
178
|
-
| Some(tail) => tail
|
|
179
|
-
| None => Promise.resolve()
|
|
180
|
-
}
|
|
181
|
-
let promise =
|
|
182
|
-
tail
|
|
183
|
-
// The queued build may have been satisfied while waiting behind another
|
|
184
|
-
// one on the same table (eg a finalize pass created it).
|
|
185
|
-
->Promise.then(() => registry->has(key) ? Promise.resolve() : build())
|
|
186
|
-
->Promise.thenResolve(() => registry->add(key))
|
|
187
|
-
registry.inflight->Dict.set(key, promise)
|
|
188
|
-
registry.tableQueue->Dict.set(tableName, promise->Utils.Promise.silentCatch)
|
|
189
|
-
promise->Promise.finally(() => registry.inflight->Utils.Dict.deleteInPlace(key))
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
let pgMaxIdentifierLength = 63
|
|
194
|
-
|
|
195
|
-
// Postgres truncates identifiers past 63 characters on its own. Doing it here
|
|
196
|
-
// instead keeps the name we emit, log and read back from the catalog identical
|
|
197
|
-
// to the one it stores. Descriptions are ASCII (GraphQL names are), so
|
|
198
|
-
// characters and Postgres' byte limit line up.
|
|
199
|
-
let truncateIndexName = description =>
|
|
200
|
-
description->String.length > pgMaxIdentifierLength
|
|
201
|
-
? description->String.slice(~start=0, ~end=pgMaxIdentifierLength)
|
|
202
|
-
: description
|
|
203
|
-
|
|
204
|
-
// Two distinct descriptions can collapse onto one truncated name — and the
|
|
205
|
-
// second `CREATE INDEX IF NOT EXISTS` would then be skipped without a trace,
|
|
206
|
-
// leaving the registry claiming an index that doesn't exist.
|
|
207
|
-
let validateIndexNamesOrThrow = (descriptions: array<string>) => {
|
|
208
|
-
let byName = Dict.make()
|
|
209
|
-
descriptions->Array.forEach(description => {
|
|
210
|
-
let name = description->truncateIndexName
|
|
211
|
-
switch byName->Utils.Dict.dangerouslyGetNonOption(name) {
|
|
212
|
-
| Some(existing) if existing !== description =>
|
|
213
|
-
JsError.throwWithMessage(
|
|
214
|
-
`Index names "${existing}" and "${description}" both truncate to "${name}" at PostgreSQL's ${pgMaxIdentifierLength->Int.toString}-character identifier limit. Rename a field or an entity so the generated index names stay distinct.`,
|
|
215
|
-
)
|
|
216
|
-
| _ => byName->Dict.set(name, description)
|
|
217
|
-
}
|
|
218
|
-
})
|
|
219
|
-
}
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Utils from "../Utils.res.mjs";
|
|
4
|
-
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
5
|
-
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
6
|
-
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
7
|
-
|
|
8
|
-
function fromIndexFields(indexFields) {
|
|
9
|
-
return indexFields.map(param => ({
|
|
10
|
-
name: param.fieldName,
|
|
11
|
-
direction: param.direction
|
|
12
|
-
}));
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function makeKey(tableName, columns, method) {
|
|
16
|
-
return tableName + `|` + method + `|` + columns.map(param => {
|
|
17
|
-
let name = param.name;
|
|
18
|
-
if (param.direction === "Asc") {
|
|
19
|
-
return name;
|
|
20
|
-
} else {
|
|
21
|
-
return name + " DESC";
|
|
22
|
-
}
|
|
23
|
-
}).join(",");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
let catalogRowsSchema = S$RescriptSchema.array(S$RescriptSchema.object(s => ({
|
|
27
|
-
tableName: s.f("tableName", S$RescriptSchema.string),
|
|
28
|
-
indexName: s.f("indexName", S$RescriptSchema.string),
|
|
29
|
-
method: s.f("method", S$RescriptSchema.string),
|
|
30
|
-
isValid: s.f("isValid", S$RescriptSchema.int),
|
|
31
|
-
isPlain: s.f("isPlain", S$RescriptSchema.int),
|
|
32
|
-
columns: s.f("columns", S$RescriptSchema.array(S$RescriptSchema.string)),
|
|
33
|
-
directions: s.f("directions", S$RescriptSchema.array(S$RescriptSchema.string))
|
|
34
|
-
})));
|
|
35
|
-
|
|
36
|
-
function makeCatalogQuery(pgSchema) {
|
|
37
|
-
return `SELECT
|
|
38
|
-
t.relname AS "tableName",
|
|
39
|
-
i.relname AS "indexName",
|
|
40
|
-
am.amname AS "method",
|
|
41
|
-
CASE WHEN ix.indisvalid AND ix.indisready THEN 1 ELSE 0 END AS "isValid",
|
|
42
|
-
CASE
|
|
43
|
-
WHEN ix.indisunique OR ix.indpred IS NOT NULL OR ix.indexprs IS NOT NULL THEN 0
|
|
44
|
-
ELSE 1
|
|
45
|
-
END AS "isPlain",
|
|
46
|
-
array_agg(
|
|
47
|
-
CASE WHEN k.attnum = 0
|
|
48
|
-
THEN pg_get_indexdef(ix.indexrelid, k.ord::int, true)
|
|
49
|
-
ELSE a.attname
|
|
50
|
-
END ORDER BY k.ord
|
|
51
|
-
) AS "columns",
|
|
52
|
-
array_agg(
|
|
53
|
-
CASE WHEN (ix.indoption[k.ord - 1] & 1) = 1 THEN 'DESC' ELSE 'ASC' END ORDER BY k.ord
|
|
54
|
-
) AS "directions"
|
|
55
|
-
FROM pg_index ix
|
|
56
|
-
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
57
|
-
JOIN pg_class t ON t.oid = ix.indrelid
|
|
58
|
-
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
59
|
-
JOIN pg_am am ON am.oid = i.relam
|
|
60
|
-
JOIN LATERAL unnest(ix.indkey) WITH ORDINALITY AS k(attnum, ord) ON k.ord <= ix.indnkeyatts
|
|
61
|
-
LEFT JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
|
|
62
|
-
WHERE n.nspname = '` + pgSchema + `'
|
|
63
|
-
GROUP BY t.relname, i.relname, am.amname, ix.indisvalid, ix.indisready,
|
|
64
|
-
ix.indisunique, ix.indpred, ix.indexprs;`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function make() {
|
|
68
|
-
return {
|
|
69
|
-
keys: new Set(),
|
|
70
|
-
invalidByName: {},
|
|
71
|
-
inflight: {},
|
|
72
|
-
tableQueue: {}
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function has(registry, key) {
|
|
77
|
-
return registry.keys.has(key);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function add(registry, key) {
|
|
81
|
-
registry.keys.add(key);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function size(registry) {
|
|
85
|
-
return registry.keys.size;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function toArray(registry) {
|
|
89
|
-
return Array.from(registry.keys).toSorted(Primitive_string.compare);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function getInvalid(registry, name) {
|
|
93
|
-
return registry.invalidByName[name];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function clearInvalidName(registry, name) {
|
|
97
|
-
Utils.Dict.deleteInPlace(registry.invalidByName, name);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function reload(registry, rows) {
|
|
101
|
-
registry.keys.clear();
|
|
102
|
-
Object.keys(registry.invalidByName).forEach(name => Utils.Dict.deleteInPlace(registry.invalidByName, name));
|
|
103
|
-
let invalidIndexNames = [];
|
|
104
|
-
rows.forEach(row => {
|
|
105
|
-
let key = makeKey(row.tableName, row.columns.map((name, idx) => {
|
|
106
|
-
let match = row.directions[idx];
|
|
107
|
-
let tmp;
|
|
108
|
-
tmp = match === "DESC" ? "Desc" : "Asc";
|
|
109
|
-
return {
|
|
110
|
-
name: name,
|
|
111
|
-
direction: tmp
|
|
112
|
-
};
|
|
113
|
-
}), row.method);
|
|
114
|
-
if (row.isValid === 0) {
|
|
115
|
-
invalidIndexNames.push(row.indexName);
|
|
116
|
-
registry.invalidByName[row.indexName] = {
|
|
117
|
-
key: key,
|
|
118
|
-
isRepairable: row.isPlain === 1
|
|
119
|
-
};
|
|
120
|
-
return;
|
|
121
|
-
} else {
|
|
122
|
-
return add(registry, key);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
return invalidIndexNames;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function ensure(registry, key, tableName, build) {
|
|
129
|
-
if (registry.keys.has(key)) {
|
|
130
|
-
return Promise.resolve();
|
|
131
|
-
}
|
|
132
|
-
let promise = registry.inflight[key];
|
|
133
|
-
if (promise !== undefined) {
|
|
134
|
-
return promise;
|
|
135
|
-
}
|
|
136
|
-
let tail = registry.tableQueue[tableName];
|
|
137
|
-
let tail$1 = tail !== undefined ? tail : Promise.resolve();
|
|
138
|
-
let promise$1 = tail$1.then(() => {
|
|
139
|
-
if (registry.keys.has(key)) {
|
|
140
|
-
return Promise.resolve();
|
|
141
|
-
} else {
|
|
142
|
-
return build();
|
|
143
|
-
}
|
|
144
|
-
}).then(() => add(registry, key));
|
|
145
|
-
registry.inflight[key] = promise$1;
|
|
146
|
-
registry.tableQueue[tableName] = Utils.$$Promise.silentCatch(promise$1);
|
|
147
|
-
return promise$1.finally(() => Utils.Dict.deleteInPlace(registry.inflight, key));
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function truncateIndexName(description) {
|
|
151
|
-
if (description.length > 63) {
|
|
152
|
-
return description.slice(0, 63);
|
|
153
|
-
} else {
|
|
154
|
-
return description;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function validateIndexNamesOrThrow(descriptions) {
|
|
159
|
-
let byName = {};
|
|
160
|
-
descriptions.forEach(description => {
|
|
161
|
-
let name = truncateIndexName(description);
|
|
162
|
-
let existing = byName[name];
|
|
163
|
-
if (existing !== undefined && existing !== description) {
|
|
164
|
-
return Stdlib_JsError.throwWithMessage(`Index names "` + existing + `" and "` + description + `" both truncate to "` + name + `" at PostgreSQL's ` + (63).toString() + `-character identifier limit. Rename a field or an entity so the generated index names stay distinct.`);
|
|
165
|
-
} else {
|
|
166
|
-
byName[name] = description;
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
let btree = "btree";
|
|
173
|
-
|
|
174
|
-
let pgMaxIdentifierLength = 63;
|
|
175
|
-
|
|
176
|
-
export {
|
|
177
|
-
btree,
|
|
178
|
-
fromIndexFields,
|
|
179
|
-
makeKey,
|
|
180
|
-
catalogRowsSchema,
|
|
181
|
-
makeCatalogQuery,
|
|
182
|
-
make,
|
|
183
|
-
has,
|
|
184
|
-
add,
|
|
185
|
-
size,
|
|
186
|
-
toArray,
|
|
187
|
-
getInvalid,
|
|
188
|
-
clearInvalidName,
|
|
189
|
-
reload,
|
|
190
|
-
ensure,
|
|
191
|
-
pgMaxIdentifierLength,
|
|
192
|
-
truncateIndexName,
|
|
193
|
-
validateIndexNamesOrThrow,
|
|
194
|
-
}
|
|
195
|
-
/* catalogRowsSchema Not a pure module */
|