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.
Files changed (114) hide show
  1. package/README.md +40 -34
  2. package/evm.schema.json +3 -3
  3. package/fuel.schema.json +2 -2
  4. package/index.d.ts +3 -3
  5. package/licenses/README.md +1 -1
  6. package/package.json +8 -8
  7. package/src/Batch.res.mjs +5 -5
  8. package/src/BatchProcessing.res +1 -0
  9. package/src/BatchProcessing.res.mjs +1 -0
  10. package/src/ChainFetching.res +1 -6
  11. package/src/ChainFetching.res.mjs +1 -1
  12. package/src/ChainState.res +48 -7
  13. package/src/ChainState.res.mjs +21 -8
  14. package/src/Clock.res +57 -0
  15. package/src/Clock.res.mjs +72 -0
  16. package/src/Config.res +16 -4
  17. package/src/Config.res.mjs +5 -3
  18. package/src/Core.res +4 -40
  19. package/src/CrossChainState.res +10 -6
  20. package/src/CrossChainState.res.mjs +1 -1
  21. package/src/EffectState.res +10 -2
  22. package/src/EffectState.res.mjs +8 -4
  23. package/src/EffectState.resi +3 -1
  24. package/src/EntityId.res +2 -7
  25. package/src/EntityId.res.mjs +1 -8
  26. package/src/EntityTables.res +4 -1
  27. package/src/EntityTables.res.mjs +1 -1
  28. package/src/Env.res +4 -0
  29. package/src/Env.res.mjs +5 -0
  30. package/src/FetchState.res +157 -69
  31. package/src/FetchState.res.mjs +112 -47
  32. package/src/FinalizeBackfill.res +2 -4
  33. package/src/FinalizeBackfill.res.mjs +3 -4
  34. package/src/InMemoryTable.res +17 -16
  35. package/src/InMemoryTable.res.mjs +14 -15
  36. package/src/IndexerState.res +28 -4
  37. package/src/IndexerState.res.mjs +19 -6
  38. package/src/IndexerState.resi +4 -0
  39. package/src/Internal.res +0 -49
  40. package/src/Internal.res.mjs +1 -80
  41. package/src/LoadLayer.res +17 -10
  42. package/src/LoadLayer.res.mjs +11 -8
  43. package/src/Main.res.mjs +1 -1
  44. package/src/Persistence.res +3 -23
  45. package/src/Persistence.res.mjs +3 -3
  46. package/src/PreloadLookahead.res +42 -24
  47. package/src/PreloadLookahead.res.mjs +51 -30
  48. package/src/Rollback.res +0 -1
  49. package/src/Rollback.res.mjs +1 -1
  50. package/src/SafeCheckpointTracking.res +4 -4
  51. package/src/SafeCheckpointTracking.res.mjs +1 -1
  52. package/src/StagedRows.res +106 -0
  53. package/src/StagedRows.res.mjs +102 -0
  54. package/src/Staging.res +32 -14
  55. package/src/Staging.res.mjs +17 -20
  56. package/src/Storage.res +278 -973
  57. package/src/Storage.res.mjs +218 -720
  58. package/src/Supervisor.res +75 -56
  59. package/src/Supervisor.res.mjs +55 -26
  60. package/src/SyncWrites.res +24 -18
  61. package/src/SyncWrites.res.mjs +11 -11
  62. package/src/TestIndexer.res +22 -27
  63. package/src/TestIndexer.res.mjs +20 -17
  64. package/src/Throttler.res +15 -8
  65. package/src/Throttler.res.mjs +9 -6
  66. package/src/Throttler.resi +1 -1
  67. package/src/UserContext.res +13 -4
  68. package/src/UserContext.res.mjs +5 -5
  69. package/src/Utils.res +0 -6
  70. package/src/Utils.res.mjs +0 -5
  71. package/src/Writing.res +0 -1
  72. package/src/Writing.res.mjs +1 -1
  73. package/src/bindings/ClickHouse.res +0 -322
  74. package/src/bindings/ClickHouse.res.mjs +0 -338
  75. package/src/bindings/StorageClient.res +107 -174
  76. package/src/bindings/StorageClient.res.mjs +19 -8
  77. package/src/bindings/Vitest.res +0 -26
  78. package/src/bindings/Vitest.res.mjs +0 -3
  79. package/src/db/Table.res +24 -150
  80. package/src/db/Table.res.mjs +38 -272
  81. package/src/sources/ChainSources.res +2 -0
  82. package/src/sources/ChainSources.res.mjs +2 -2
  83. package/src/sources/EvmChain.res +3 -0
  84. package/src/sources/EvmChain.res.mjs +4 -2
  85. package/src/sources/EvmHyperSyncSource.res +2 -2
  86. package/src/sources/EvmHyperSyncSource.res.mjs +1 -1
  87. package/src/sources/EvmRpcClient.res +13 -3
  88. package/src/sources/EvmRpcClient.res.mjs +4 -3
  89. package/src/sources/EvmRpcWs.res +4 -3
  90. package/src/sources/EvmRpcWs.res.mjs +2 -2
  91. package/src/sources/HeightFeed.res +31 -10
  92. package/src/sources/HeightFeed.res.mjs +10 -6
  93. package/src/sources/HeightStream.res +32 -17
  94. package/src/sources/HeightStream.res.mjs +10 -10
  95. package/src/sources/HyperSyncSSE.res +4 -6
  96. package/src/sources/HyperSyncSSE.res.mjs +2 -2
  97. package/src/sources/RpcSource.res +10 -1
  98. package/src/sources/RpcSource.res.mjs +4 -3
  99. package/src/sources/Source.res +3 -0
  100. package/src/sources/SourceManager.res +85 -104
  101. package/src/sources/SourceManager.res.mjs +18 -37
  102. package/src/sources/SourceManager.resi +3 -5
  103. package/src/sources/StartBlockResolver.res +1 -0
  104. package/src/sources/StartBlockResolver.res.mjs +4 -3
  105. package/src/sources/SvmHyperSyncSource.res +2 -2
  106. package/src/sources/SvmHyperSyncSource.res.mjs +1 -1
  107. package/src/subgraph/graph-ts.ts +87 -28
  108. package/src/subgraph/runtime.ts +0 -1
  109. package/src/subgraph/scope.ts +0 -1
  110. package/svm.schema.json +3 -3
  111. package/src/PgWriting.res +0 -36
  112. package/src/PgWriting.res.mjs +0 -34
  113. package/src/db/IndexDefinition.res +0 -47
  114. package/src/db/IndexDefinition.res.mjs +0 -60
@@ -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, isId);
1434
+ : fromValue(entry.value, idColumn);
1430
1435
  }
1431
1436
  return row;
1432
1437
  }
1433
1438
 
1434
- function fromValue(value: Value, isId = false): unknown {
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 isId ? value.toBytes().toHexString() : Uint8Array.from(value.toBytes());
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, isId));
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; an id column
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 refFields = new Set(scope.schema.entityRefFields[entityType] ?? []);
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(id));
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(id));
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 = 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
- const stored = own === false ? undefined : table.getSync(id);
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(id)) return;
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(id);
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 rows = entityContext(target).getWhereSync({ [back]: { _eq: id } });
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((row: any) => file.entities.has(target) && file.written.has(`${target}\u0000${row.id}`))
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(String(a.id), String(b.id));
1908
+ return codePointOrder(storedIdToGraphId(a.id), storedIdToGraphId(b.id));
1850
1909
  }
1851
1910
 
1852
1911
  function byNumericId(a: { id: unknown }, b: { id: unknown }): number {
@@ -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 ?? {},
@@ -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": "The minimum number of new blocks the chain head must advance by before the indexer fetches again once it has caught up. Useful on chains with very fast blocks, where fetching every block is wasteful. Unset, 0 and 1 all fetch on every new block.",
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 code).",
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 HyperIndex generated code. Should be unique per program.",
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
- }
@@ -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 */