envio 3.15.0-subgraph → 3.16.0-subgraph
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 +40 -34
- package/evm.schema.json +3 -3
- package/fuel.schema.json +2 -2
- package/index.d.ts +3 -3
- package/licenses/README.md +1 -1
- package/package.json +8 -8
- package/src/Batch.res.mjs +5 -5
- package/src/BatchProcessing.res +1 -0
- package/src/BatchProcessing.res.mjs +1 -0
- package/src/ChainFetching.res +1 -6
- package/src/ChainFetching.res.mjs +1 -1
- package/src/ChainState.res +48 -7
- package/src/ChainState.res.mjs +21 -8
- package/src/Clock.res +57 -0
- package/src/Clock.res.mjs +72 -0
- package/src/Config.res +16 -4
- package/src/Config.res.mjs +5 -3
- package/src/Core.res +4 -40
- package/src/CrossChainState.res +10 -6
- package/src/CrossChainState.res.mjs +1 -1
- package/src/EffectState.res +10 -2
- package/src/EffectState.res.mjs +8 -4
- package/src/EffectState.resi +3 -1
- package/src/EntityId.res +2 -7
- package/src/EntityId.res.mjs +1 -8
- package/src/EntityTables.res +4 -1
- package/src/EntityTables.res.mjs +1 -1
- package/src/Env.res +4 -0
- package/src/Env.res.mjs +5 -0
- package/src/FetchState.res +157 -69
- package/src/FetchState.res.mjs +112 -47
- package/src/FinalizeBackfill.res +2 -4
- package/src/FinalizeBackfill.res.mjs +3 -4
- package/src/InMemoryTable.res +17 -16
- package/src/InMemoryTable.res.mjs +14 -15
- package/src/IndexerState.res +28 -4
- package/src/IndexerState.res.mjs +19 -6
- package/src/IndexerState.resi +4 -0
- package/src/Internal.res +0 -49
- package/src/Internal.res.mjs +1 -80
- package/src/LoadLayer.res +17 -10
- package/src/LoadLayer.res.mjs +11 -8
- package/src/Main.res.mjs +1 -1
- package/src/Persistence.res +3 -23
- package/src/Persistence.res.mjs +3 -3
- package/src/PreloadLookahead.res +42 -24
- package/src/PreloadLookahead.res.mjs +51 -30
- package/src/Rollback.res +0 -1
- package/src/Rollback.res.mjs +1 -1
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +1 -1
- package/src/StagedRows.res +106 -0
- package/src/StagedRows.res.mjs +102 -0
- package/src/Staging.res +32 -14
- package/src/Staging.res.mjs +17 -20
- package/src/Storage.res +278 -973
- package/src/Storage.res.mjs +218 -720
- package/src/Supervisor.res +75 -56
- package/src/Supervisor.res.mjs +55 -26
- package/src/SyncWrites.res +24 -18
- package/src/SyncWrites.res.mjs +11 -11
- package/src/TestIndexer.res +22 -27
- package/src/TestIndexer.res.mjs +20 -17
- package/src/Throttler.res +15 -8
- package/src/Throttler.res.mjs +9 -6
- package/src/Throttler.resi +1 -1
- package/src/UserContext.res +13 -4
- package/src/UserContext.res.mjs +5 -5
- package/src/Utils.res +0 -6
- package/src/Utils.res.mjs +0 -5
- package/src/Writing.res +0 -1
- package/src/Writing.res.mjs +1 -1
- package/src/bindings/ClickHouse.res +0 -322
- package/src/bindings/ClickHouse.res.mjs +0 -338
- package/src/bindings/StorageClient.res +107 -174
- package/src/bindings/StorageClient.res.mjs +19 -8
- package/src/bindings/Vitest.res +0 -26
- package/src/bindings/Vitest.res.mjs +0 -3
- package/src/db/Table.res +24 -150
- package/src/db/Table.res.mjs +38 -272
- package/src/sources/ChainSources.res +2 -0
- package/src/sources/ChainSources.res.mjs +2 -2
- package/src/sources/EvmChain.res +3 -0
- package/src/sources/EvmChain.res.mjs +4 -2
- package/src/sources/EvmHyperSyncSource.res +2 -2
- package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
- package/src/sources/EvmRpcClient.res +13 -3
- package/src/sources/EvmRpcClient.res.mjs +4 -3
- package/src/sources/EvmRpcWs.res +4 -3
- package/src/sources/EvmRpcWs.res.mjs +2 -2
- package/src/sources/HeightFeed.res +31 -10
- package/src/sources/HeightFeed.res.mjs +10 -6
- package/src/sources/HeightStream.res +32 -17
- package/src/sources/HeightStream.res.mjs +10 -10
- package/src/sources/HyperSyncSSE.res +4 -6
- package/src/sources/HyperSyncSSE.res.mjs +2 -2
- package/src/sources/RpcSource.res +10 -1
- package/src/sources/RpcSource.res.mjs +4 -3
- package/src/sources/Source.res +3 -0
- package/src/sources/SourceManager.res +85 -104
- package/src/sources/SourceManager.res.mjs +18 -37
- package/src/sources/SourceManager.resi +3 -5
- package/src/sources/StartBlockResolver.res +1 -0
- package/src/sources/StartBlockResolver.res.mjs +4 -3
- package/src/sources/SvmHyperSyncSource.res +2 -2
- package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
- package/src/subgraph/graph-ts.ts +87 -28
- package/src/subgraph/runtime.ts +0 -1
- package/src/subgraph/scope.ts +0 -1
- package/svm.schema.json +3 -3
- package/src/PgWriting.res +0 -36
- package/src/PgWriting.res.mjs +0 -34
- package/src/db/IndexDefinition.res +0 -47
- package/src/db/IndexDefinition.res.mjs +0 -60
package/src/subgraph/graph-ts.ts
CHANGED
|
@@ -1406,11 +1406,16 @@ function toRow(entityType: string, entity: Entity, id?: string): Record<string,
|
|
|
1406
1406
|
// others (`check_invalid_fields` refuses them from 0.0.8 on).
|
|
1407
1407
|
if (fields !== undefined && !fields.has(entry.key)) continue;
|
|
1408
1408
|
const column = refFields.has(entry.key) ? `${entry.key}_id` : entry.key;
|
|
1409
|
-
// An id is a string column whatever the subgraph declared it as, and so is
|
|
1410
|
-
// a relation, which carries one. Every other `Bytes` field is a bytes
|
|
1411
|
-
// column, which is what `bytes_type: uint8array` makes of it.
|
|
1412
|
-
const isId = entry.key === "id" || refFields.has(entry.key) || listFields.has(entry.key);
|
|
1413
1409
|
const declared = schema.entityFieldTypes[entityType]?.[entry.key];
|
|
1410
|
+
// An id, a relation and a stored list of entities hold ids: bytes when the
|
|
1411
|
+
// id they name is `Bytes`, text otherwise. Every other `Bytes` field is a
|
|
1412
|
+
// bytes column, which is what `bytes_type: uint8array` makes of it.
|
|
1413
|
+
const idColumn =
|
|
1414
|
+
entry.key === "id" || refFields.has(entry.key) || listFields.has(entry.key)
|
|
1415
|
+
? declaredKind(schema, declared) === "Bytes"
|
|
1416
|
+
? "bytes"
|
|
1417
|
+
: "text"
|
|
1418
|
+
: undefined;
|
|
1414
1419
|
if (
|
|
1415
1420
|
declared?.nullableElements &&
|
|
1416
1421
|
entry.value.kind === ValueKind.ARRAY &&
|
|
@@ -1426,17 +1431,17 @@ function toRow(entityType: string, entity: Entity, id?: string): Record<string,
|
|
|
1426
1431
|
row[column] =
|
|
1427
1432
|
timestampFields.has(entry.key) && entry.value.kind !== ValueKind.NULL
|
|
1428
1433
|
? new Date(Number(entry.value.toTimestamp() / 1000n))
|
|
1429
|
-
: fromValue(entry.value,
|
|
1434
|
+
: fromValue(entry.value, idColumn);
|
|
1430
1435
|
}
|
|
1431
1436
|
return row;
|
|
1432
1437
|
}
|
|
1433
1438
|
|
|
1434
|
-
function fromValue(value: Value,
|
|
1439
|
+
function fromValue(value: Value, idColumn?: "bytes" | "text"): unknown {
|
|
1435
1440
|
switch (value.kind) {
|
|
1436
1441
|
case ValueKind.NULL:
|
|
1437
1442
|
return null;
|
|
1438
1443
|
case ValueKind.BYTES:
|
|
1439
|
-
return
|
|
1444
|
+
return idColumn === "text" ? value.toBytes().toHexString() : Uint8Array.from(value.toBytes());
|
|
1440
1445
|
case ValueKind.BIGINT:
|
|
1441
1446
|
return value.toBigInt().valueOf();
|
|
1442
1447
|
case ValueKind.INT8:
|
|
@@ -1445,9 +1450,9 @@ function fromValue(value: Value, isId = false): unknown {
|
|
|
1445
1450
|
case ValueKind.BIGDECIMAL:
|
|
1446
1451
|
return value.toBigDecimal().value;
|
|
1447
1452
|
case ValueKind.ARRAY:
|
|
1448
|
-
return value.toArray().map((item) => fromValue(item,
|
|
1453
|
+
return value.toArray().map((item) => fromValue(item, idColumn));
|
|
1449
1454
|
case ValueKind.STRING:
|
|
1450
|
-
return withoutNul(value.data);
|
|
1455
|
+
return idColumn === "bytes" ? graphIdToStoredId("Bytes", withoutNul(value.data)) : withoutNul(value.data);
|
|
1451
1456
|
default:
|
|
1452
1457
|
return value.data;
|
|
1453
1458
|
}
|
|
@@ -1508,8 +1513,7 @@ function toValue(value: unknown, kind?: string): Value {
|
|
|
1508
1513
|
if (Array.isArray(value)) return Value.fromArray(value.map((item) => toValue(item, kind)));
|
|
1509
1514
|
switch (kind) {
|
|
1510
1515
|
case "Bytes":
|
|
1511
|
-
// A bytes column reads back as the bytes themselves
|
|
1512
|
-
// declared `Bytes` is stored as text, and reads back hex.
|
|
1516
|
+
// A bytes column reads back as the bytes themselves.
|
|
1513
1517
|
if (value instanceof Uint8Array) return Value.fromBytes(Bytes.fromUint8Array(value));
|
|
1514
1518
|
return typeof value === "string" ? Value.fromBytes(Bytes.fromHexString(value)) : Value.fromNull();
|
|
1515
1519
|
case "BigInt":
|
|
@@ -1685,15 +1689,54 @@ export function resetRegisterStore(): void {
|
|
|
1685
1689
|
* needs it spelled out — a list column refuses a missing value.
|
|
1686
1690
|
*/
|
|
1687
1691
|
function withUnsetAsNull(scope: Scope, entityType: string, row: Record<string, unknown>) {
|
|
1688
|
-
const
|
|
1689
|
-
for (const [field, declared] of Object.entries(scope.schema.entityFieldTypes[entityType] ?? {})) {
|
|
1690
|
-
if (declared.derivedFrom) continue;
|
|
1691
|
-
const column = refFields.has(field) ? `${field}_id` : field;
|
|
1692
|
+
for (const column of storedColumnsOfEntity(scope, entityType)) {
|
|
1692
1693
|
if (!(column in row)) row[column] = null;
|
|
1693
1694
|
}
|
|
1694
1695
|
return row;
|
|
1695
1696
|
}
|
|
1696
1697
|
|
|
1698
|
+
const columnsBySchema = new WeakMap<object, Map<string, string[]>>();
|
|
1699
|
+
|
|
1700
|
+
/** An entity's stored columns: a reference field's is `<field>_id`, a derived one has none. */
|
|
1701
|
+
function storedColumnsOfEntity(scope: Scope, entityType: string): string[] {
|
|
1702
|
+
let byType = columnsBySchema.get(scope.schema);
|
|
1703
|
+
if (!byType) {
|
|
1704
|
+
byType = new Map();
|
|
1705
|
+
columnsBySchema.set(scope.schema, byType);
|
|
1706
|
+
}
|
|
1707
|
+
let columns = byType.get(entityType);
|
|
1708
|
+
if (!columns) {
|
|
1709
|
+
const refFields = new Set(scope.schema.entityRefFields[entityType] ?? []);
|
|
1710
|
+
columns = Object.entries(scope.schema.entityFieldTypes[entityType] ?? {})
|
|
1711
|
+
.filter(([, declared]) => !declared.derivedFrom)
|
|
1712
|
+
.map(([field]) => (refFields.has(field) ? `${field}_id` : field));
|
|
1713
|
+
byType.set(entityType, columns);
|
|
1714
|
+
}
|
|
1715
|
+
return columns;
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1718
|
+
/**
|
|
1719
|
+
* graph-ts names an entity by a string, a `Bytes` id by its hex; graph-node
|
|
1720
|
+
* stores that id as the bytes, so `0xAB` and `0xab` are one entity. `kind` is
|
|
1721
|
+
* the column's declared kind, a relation's being its target's id kind.
|
|
1722
|
+
*/
|
|
1723
|
+
function graphIdToStoredId(kind: string | undefined, id: string): unknown {
|
|
1724
|
+
if (kind !== "Bytes") return id;
|
|
1725
|
+
const digits = id.startsWith("0x") || id.startsWith("0X") ? id.slice(2) : id;
|
|
1726
|
+
if (digits.length % 2 !== 0 || !HEX_DIGITS.test(digits)) {
|
|
1727
|
+
throw new Error(`Envio Subgraph: \`${id}\` names an entity whose id is Bytes, and isn't hex.`);
|
|
1728
|
+
}
|
|
1729
|
+
return new Uint8Array(Buffer.from(digits, "hex"));
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
function storedIdToGraphId(id: unknown): string {
|
|
1733
|
+
return id instanceof Uint8Array ? toHex(id) : String(id);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
function entityIdToStoredId(scope: Scope, entityType: string, id: string): unknown {
|
|
1737
|
+
return graphIdToStoredId(scope.schema.entityFieldTypes[entityType]?.id?.kind, withoutNul(id));
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1697
1740
|
/**
|
|
1698
1741
|
* graph-node's EntityCache::set validates a save: an update that sets every
|
|
1699
1742
|
* non-nullable field passes as it is (a null counts as set), otherwise it is
|
|
@@ -1752,26 +1795,29 @@ function fileAccess(scope: Scope, entityType: string, id: string): boolean | nul
|
|
|
1752
1795
|
|
|
1753
1796
|
const storeImpl = {
|
|
1754
1797
|
get(entityType: string, id: string): Entity | null {
|
|
1755
|
-
id = withoutNul(id);
|
|
1756
1798
|
const scope = currentScope();
|
|
1799
|
+
const storedId = entityIdToStoredId(scope, entityType, id);
|
|
1800
|
+
id = storedIdToGraphId(storedId);
|
|
1757
1801
|
if (fileAccess(scope, entityType, id) === false) return null;
|
|
1758
1802
|
if (scope.mode === "register") return registerRead(scope, entityType, id, false);
|
|
1759
|
-
return toEntity(entityType, entityContext(entityType).getSync(
|
|
1803
|
+
return toEntity(entityType, entityContext(entityType).getSync(storedId));
|
|
1760
1804
|
},
|
|
1761
1805
|
get_in_block(entityType: string, id: string): Entity | null {
|
|
1762
|
-
id = withoutNul(id);
|
|
1763
1806
|
const scope = currentScope();
|
|
1807
|
+
const storedId = entityIdToStoredId(scope, entityType, id);
|
|
1808
|
+
id = storedIdToGraphId(storedId);
|
|
1764
1809
|
if (fileAccess(scope, entityType, id) === false) return null;
|
|
1765
1810
|
if (scope.mode === "register") return registerRead(scope, entityType, id, true);
|
|
1766
|
-
return toEntity(entityType, entityContext(entityType).getInBlockSync(
|
|
1811
|
+
return toEntity(entityType, entityContext(entityType).getInBlockSync(storedId));
|
|
1767
1812
|
},
|
|
1768
1813
|
set(entityType: string, id: string, data: Entity): void {
|
|
1769
|
-
id = withoutNul(id);
|
|
1770
1814
|
const scope = currentScope();
|
|
1815
|
+
const storedId = entityIdToStoredId(scope, entityType, id);
|
|
1816
|
+
id = storedIdToGraphId(storedId);
|
|
1771
1817
|
const own = fileAccess(scope, entityType, id);
|
|
1772
1818
|
if (scope.file) scope.file.written.add(`${entityType}\u0000${id}`);
|
|
1773
1819
|
const row = toRow(entityType, data, id);
|
|
1774
|
-
row.id =
|
|
1820
|
+
row.id = storedId;
|
|
1775
1821
|
// graph-node merges a save onto the stored entity (EntityCache::set is an
|
|
1776
1822
|
// Update, merged by merge_remove_null_fields): a field this instance
|
|
1777
1823
|
// doesn't set keeps its stored value, an explicit null clears it. ENS's
|
|
@@ -1792,20 +1838,27 @@ const storeImpl = {
|
|
|
1792
1838
|
}
|
|
1793
1839
|
// A file data source's first write of an id is a new entity of its own,
|
|
1794
1840
|
// whatever a chain handler stored under the same id.
|
|
1795
|
-
|
|
1841
|
+
// A save that sets every column leaves the merge nothing to keep, so the
|
|
1842
|
+
// store isn't read: for an insert-only entity that read was a database
|
|
1843
|
+
// lookup and a second preload round per event.
|
|
1844
|
+
const replacesWhole =
|
|
1845
|
+
!scope.schema.skipDuplicateEntities.includes(entityType) &&
|
|
1846
|
+
storedColumnsOfEntity(scope, entityType).every((column) => column in row);
|
|
1847
|
+
const stored = own === false || replacesWhole ? undefined : table.getSync(storedId);
|
|
1796
1848
|
assertRequiredFields(scope, entityType, id, data, stored);
|
|
1797
1849
|
// graph-node inserts a skipDuplicates type with ON CONFLICT DO NOTHING, so
|
|
1798
1850
|
// an id an earlier block stored keeps that block's write; saves within
|
|
1799
1851
|
// this block merge in its entity cache first.
|
|
1800
|
-
if (stored && scope.schema.skipDuplicateEntities.includes(entityType) && !table.getInBlockSync(
|
|
1852
|
+
if (stored && scope.schema.skipDuplicateEntities.includes(entityType) && !table.getInBlockSync(storedId)) return;
|
|
1801
1853
|
table.set(stored ? { ...stored, ...row } : withUnsetAsNull(scope, entityType, row));
|
|
1802
1854
|
},
|
|
1803
1855
|
remove(entityType: string, id: string): void {
|
|
1804
|
-
id = withoutNul(id);
|
|
1805
1856
|
const scope = currentScope();
|
|
1857
|
+
const storedId = entityIdToStoredId(scope, entityType, id);
|
|
1858
|
+
id = storedIdToGraphId(storedId);
|
|
1806
1859
|
if (fileAccess(scope, entityType, id) === false) return;
|
|
1807
1860
|
if (scope.mode === "register") return registerWrite(scope, entityType, id, null);
|
|
1808
|
-
entityContext(entityType).deleteUnsafe(
|
|
1861
|
+
entityContext(entityType).deleteUnsafe(storedId);
|
|
1809
1862
|
},
|
|
1810
1863
|
/**
|
|
1811
1864
|
* `graph codegen` names the entity the derived field is declared on and the
|
|
@@ -1833,10 +1886,15 @@ const storeImpl = {
|
|
|
1833
1886
|
const back = schema.entityRefFields[target]?.includes(declared.derivedFrom)
|
|
1834
1887
|
? `${declared.derivedFrom}_id`
|
|
1835
1888
|
: declared.derivedFrom;
|
|
1836
|
-
const
|
|
1889
|
+
const backKind = declaredKind(schema, schema.entityFieldTypes[target]?.[declared.derivedFrom]);
|
|
1890
|
+
const rows = entityContext(target).getWhereSync({
|
|
1891
|
+
[back]: { _eq: graphIdToStoredId(backKind, withoutNul(id)) },
|
|
1892
|
+
});
|
|
1837
1893
|
// A file data source sees the related entities it wrote, and no others.
|
|
1838
1894
|
const visible = file
|
|
1839
|
-
? rows.filter(
|
|
1895
|
+
? rows.filter(
|
|
1896
|
+
(row: any) => file.entities.has(target) && file.written.has(`${target}\u0000${storedIdToGraphId(row.id)}`),
|
|
1897
|
+
)
|
|
1840
1898
|
: rows;
|
|
1841
1899
|
// graph-node answers in key order (`EntityCache::load_related` walks a
|
|
1842
1900
|
// BTreeSet of entity keys): by id, as the id's type orders.
|
|
@@ -1845,8 +1903,9 @@ const storeImpl = {
|
|
|
1845
1903
|
},
|
|
1846
1904
|
};
|
|
1847
1905
|
|
|
1906
|
+
// A Bytes id's lowercase hex orders as its bytes do.
|
|
1848
1907
|
function byId(a: { id: unknown }, b: { id: unknown }): number {
|
|
1849
|
-
return codePointOrder(
|
|
1908
|
+
return codePointOrder(storedIdToGraphId(a.id), storedIdToGraphId(b.id));
|
|
1850
1909
|
}
|
|
1851
1910
|
|
|
1852
1911
|
function byNumericId(a: { id: unknown }, b: { id: unknown }): number {
|
package/src/subgraph/runtime.ts
CHANGED
|
@@ -1437,7 +1437,6 @@ export async function registerSubgraph(config: SubgraphConfig, logger: unknown):
|
|
|
1437
1437
|
|
|
1438
1438
|
const schema: SubgraphSchema = {
|
|
1439
1439
|
timestampFields: config.timestampFields ?? {},
|
|
1440
|
-
bytesIdEntities: config.bytesIdEntities ?? [],
|
|
1441
1440
|
entityListFields: config.entityListFields ?? {},
|
|
1442
1441
|
entityFields: config.entityFields ?? {},
|
|
1443
1442
|
entityRefFields: config.entityRefFields ?? {},
|
package/src/subgraph/scope.ts
CHANGED
|
@@ -6,7 +6,6 @@ export type Mode = "handler" | "register";
|
|
|
6
6
|
|
|
7
7
|
export type SubgraphSchema = {
|
|
8
8
|
timestampFields: Record<string, string[]>;
|
|
9
|
-
bytesIdEntities: string[];
|
|
10
9
|
entityListFields: Record<string, string[]>;
|
|
11
10
|
entityFields: Record<string, string[]>;
|
|
12
11
|
entityRefFields: Record<string, string[]>;
|
package/svm.schema.json
CHANGED
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
"minimum": 0
|
|
221
221
|
},
|
|
222
222
|
"block_throttle": {
|
|
223
|
-
"description": "
|
|
223
|
+
"description": "Once caught up, wait for this many new slots before fetching them. Delays new instructions by up to as many slots.",
|
|
224
224
|
"type": [
|
|
225
225
|
"integer",
|
|
226
226
|
"null"
|
|
@@ -303,7 +303,7 @@
|
|
|
303
303
|
"type": "object",
|
|
304
304
|
"properties": {
|
|
305
305
|
"name": {
|
|
306
|
-
"description": "A unique project-wide name for this program (used in generated
|
|
306
|
+
"description": "A unique project-wide name for this program (used in the generated types).",
|
|
307
307
|
"type": "string"
|
|
308
308
|
},
|
|
309
309
|
"program_id": {
|
|
@@ -357,7 +357,7 @@
|
|
|
357
357
|
"type": "object",
|
|
358
358
|
"properties": {
|
|
359
359
|
"name": {
|
|
360
|
-
"description": "Name of the instruction in the
|
|
360
|
+
"description": "Name of the instruction in the generated types. Should be unique per program.",
|
|
361
361
|
"type": "string"
|
|
362
362
|
},
|
|
363
363
|
"discriminator": {
|
package/src/PgWriting.res
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
let columns = (fields: array<Table.field>, ~kinds: array<Staging.kind>): array<Staging.column> =>
|
|
2
|
-
fields->Array.mapWithIndex((field, index) => {
|
|
3
|
-
Staging.name: field->Table.getPgDbFieldName,
|
|
4
|
-
kind: kinds->Array.getUnsafe(index),
|
|
5
|
-
isNullable: field.isNullable,
|
|
6
|
-
})
|
|
7
|
-
|
|
8
|
-
// Lays a batch into the arena, column by column. The values are the ones the
|
|
9
|
-
// table's own schema produced — a bigint as its digits, a date as its text, a
|
|
10
|
-
// boolean as the number the statement's cast expects — so nothing here has to
|
|
11
|
-
// know what a column means, only where its values go.
|
|
12
|
-
//
|
|
13
|
-
// The rows of a column are written in order because a variable-width slot's row
|
|
14
|
-
// starts where the row before it ended.
|
|
15
|
-
let stage = (
|
|
16
|
-
arena,
|
|
17
|
-
~table,
|
|
18
|
-
~columns: array<Staging.column>,
|
|
19
|
-
~values: array<array<unknown>>,
|
|
20
|
-
~rows,
|
|
21
|
-
) => {
|
|
22
|
-
let stage = arena->Staging.begin(~table, ~rows, ~columns)
|
|
23
|
-
try {
|
|
24
|
-
for column in 0 to columns->Array.length - 1 {
|
|
25
|
-
let values = values->Array.getUnsafe(column)
|
|
26
|
-
for row in 0 to rows - 1 {
|
|
27
|
-
stage->Staging.writeValue(~column, ~row, values->Array.getUnsafe(row))
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
stage->Staging.commit
|
|
31
|
-
} catch {
|
|
32
|
-
| exn =>
|
|
33
|
-
stage->Staging.abort
|
|
34
|
-
throw(exn)
|
|
35
|
-
}
|
|
36
|
-
}
|
package/src/PgWriting.res.mjs
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
import * as Table from "./db/Table.res.mjs";
|
|
4
|
-
import * as Staging from "./Staging.res.mjs";
|
|
5
|
-
|
|
6
|
-
function columns(fields, kinds) {
|
|
7
|
-
return fields.map((field, index) => ({
|
|
8
|
-
name: Table.getPgDbFieldName(field),
|
|
9
|
-
kind: kinds[index],
|
|
10
|
-
isNullable: field.isNullable
|
|
11
|
-
}));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function stage(arena, table, columns, values, rows) {
|
|
15
|
-
let stage$1 = Staging.begin(arena, table, rows, columns);
|
|
16
|
-
try {
|
|
17
|
-
for (let column = 0, column_finish = columns.length; column < column_finish; ++column) {
|
|
18
|
-
let values$1 = values[column];
|
|
19
|
-
for (let row = 0; row < rows; ++row) {
|
|
20
|
-
Staging.writeValue(stage$1, column, row, values$1[row]);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return Staging.commit(stage$1);
|
|
24
|
-
} catch (exn) {
|
|
25
|
-
Staging.abort(stage$1);
|
|
26
|
-
throw exn;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export {
|
|
31
|
-
columns,
|
|
32
|
-
stage,
|
|
33
|
-
}
|
|
34
|
-
/* Table Not a pure module */
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// What the indexer wants an index to be: a table, its ordered key columns with
|
|
2
|
-
// their directions, and an access method. The addon names it, matches it
|
|
3
|
-
// against what PostgreSQL holds and builds it.
|
|
4
|
-
|
|
5
|
-
type column = {
|
|
6
|
-
name: string,
|
|
7
|
-
direction: Table.indexFieldDirection,
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type t = {
|
|
11
|
-
tableName: string,
|
|
12
|
-
columns: array<column>,
|
|
13
|
-
method: string,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let make = (~tableName, ~columns, ~method="btree") => {tableName, columns, method}
|
|
17
|
-
|
|
18
|
-
let single = (~tableName, ~column) =>
|
|
19
|
-
make(~tableName, ~columns=[{name: column, direction: Table.Asc}])
|
|
20
|
-
|
|
21
|
-
let fromIndexFields = (~tableName, ~indexFields: array<Table.compositeIndexField>) =>
|
|
22
|
-
make(
|
|
23
|
-
~tableName,
|
|
24
|
-
~columns=indexFields->Array.map(({fieldName, direction}) => {name: fieldName, direction}),
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
let toInput = ({tableName, columns, method}: t): Core.pgIndexInput => {
|
|
28
|
-
tableName,
|
|
29
|
-
columns: columns->Array.map(({name, direction}): Core.pgIndexColumnInput => {
|
|
30
|
-
name,
|
|
31
|
-
direction: switch direction {
|
|
32
|
-
| Table.Asc => "Asc"
|
|
33
|
-
| Desc => "Desc"
|
|
34
|
-
},
|
|
35
|
-
}),
|
|
36
|
-
method,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let describe = (definition: t) =>
|
|
40
|
-
`${definition.tableName}(${definition.columns
|
|
41
|
-
->Array.map(({name, direction}) =>
|
|
42
|
-
switch direction {
|
|
43
|
-
| Asc => name
|
|
44
|
-
| Desc => `${name} DESC`
|
|
45
|
-
}
|
|
46
|
-
)
|
|
47
|
-
->Array.joinUnsafe(", ")}) using ${definition.method}`
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function make(tableName, columns, methodOpt) {
|
|
5
|
-
let method = methodOpt !== undefined ? methodOpt : "btree";
|
|
6
|
-
return {
|
|
7
|
-
tableName: tableName,
|
|
8
|
-
columns: columns,
|
|
9
|
-
method: method
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function single(tableName, column) {
|
|
14
|
-
return make(tableName, [{
|
|
15
|
-
name: column,
|
|
16
|
-
direction: "Asc"
|
|
17
|
-
}], undefined);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function fromIndexFields(tableName, indexFields) {
|
|
21
|
-
return make(tableName, indexFields.map(param => ({
|
|
22
|
-
name: param.fieldName,
|
|
23
|
-
direction: param.direction
|
|
24
|
-
})), undefined);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function toInput(param) {
|
|
28
|
-
return {
|
|
29
|
-
tableName: param.tableName,
|
|
30
|
-
columns: param.columns.map(param => {
|
|
31
|
-
let tmp;
|
|
32
|
-
tmp = param.direction === "Asc" ? "Asc" : "Desc";
|
|
33
|
-
return {
|
|
34
|
-
name: param.name,
|
|
35
|
-
direction: tmp
|
|
36
|
-
};
|
|
37
|
-
}),
|
|
38
|
-
method: param.method
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function describe(definition) {
|
|
43
|
-
return definition.tableName + `(` + definition.columns.map(param => {
|
|
44
|
-
let name = param.name;
|
|
45
|
-
if (param.direction === "Asc") {
|
|
46
|
-
return name;
|
|
47
|
-
} else {
|
|
48
|
-
return name + ` DESC`;
|
|
49
|
-
}
|
|
50
|
-
}).join(", ") + `) using ` + definition.method;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
make,
|
|
55
|
-
single,
|
|
56
|
-
fromIndexFields,
|
|
57
|
-
toInput,
|
|
58
|
-
describe,
|
|
59
|
-
}
|
|
60
|
-
/* No side effect */
|