@graphty/graph-format 0.0.0 → 0.2.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.
Files changed (224) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +216 -43
  3. package/dist/graph-format.d.ts +1 -0
  4. package/dist/graph-format.d.ts.map +1 -0
  5. package/dist/graph-format.js +15798 -0
  6. package/dist/graph-format.js.map +1 -0
  7. package/dist/src/builder/arena.d.ts +85 -0
  8. package/dist/src/builder/arena.d.ts.map +1 -0
  9. package/dist/src/builder/arena.js +154 -0
  10. package/dist/src/builder/arena.js.map +1 -0
  11. package/dist/src/builder/compact.d.ts +515 -0
  12. package/dist/src/builder/compact.d.ts.map +1 -0
  13. package/dist/src/builder/compact.js +1553 -0
  14. package/dist/src/builder/compact.js.map +1 -0
  15. package/dist/src/builder/counting-sort.d.ts +96 -0
  16. package/dist/src/builder/counting-sort.d.ts.map +1 -0
  17. package/dist/src/builder/counting-sort.js +430 -0
  18. package/dist/src/builder/counting-sort.js.map +1 -0
  19. package/dist/src/builder/freeze.d.ts +72 -0
  20. package/dist/src/builder/freeze.d.ts.map +1 -0
  21. package/dist/src/builder/freeze.js +548 -0
  22. package/dist/src/builder/freeze.js.map +1 -0
  23. package/dist/src/builder/graph-builder.d.ts +602 -0
  24. package/dist/src/builder/graph-builder.d.ts.map +1 -0
  25. package/dist/src/builder/graph-builder.js +1940 -0
  26. package/dist/src/builder/graph-builder.js.map +1 -0
  27. package/dist/src/builder/options.d.ts +16 -0
  28. package/dist/src/builder/options.d.ts.map +1 -0
  29. package/dist/src/builder/options.js +21 -0
  30. package/dist/src/builder/options.js.map +1 -0
  31. package/dist/src/columns/bitmap.d.ts +96 -0
  32. package/dist/src/columns/bitmap.d.ts.map +1 -0
  33. package/dist/src/columns/bitmap.js +184 -0
  34. package/dist/src/columns/bitmap.js.map +1 -0
  35. package/dist/src/columns/column.d.ts +220 -0
  36. package/dist/src/columns/column.d.ts.map +1 -0
  37. package/dist/src/columns/column.js +2109 -0
  38. package/dist/src/columns/column.js.map +1 -0
  39. package/dist/src/columns/dictionary.d.ts +60 -0
  40. package/dist/src/columns/dictionary.d.ts.map +1 -0
  41. package/dist/src/columns/dictionary.js +102 -0
  42. package/dist/src/columns/dictionary.js.map +1 -0
  43. package/dist/src/columns/growable.d.ts +198 -0
  44. package/dist/src/columns/growable.d.ts.map +1 -0
  45. package/dist/src/columns/growable.js +296 -0
  46. package/dist/src/columns/growable.js.map +1 -0
  47. package/dist/src/columns/infer.d.ts +121 -0
  48. package/dist/src/columns/infer.d.ts.map +1 -0
  49. package/dist/src/columns/infer.js +268 -0
  50. package/dist/src/columns/infer.js.map +1 -0
  51. package/dist/src/columns/remap.d.ts +143 -0
  52. package/dist/src/columns/remap.d.ts.map +1 -0
  53. package/dist/src/columns/remap.js +588 -0
  54. package/dist/src/columns/remap.js.map +1 -0
  55. package/dist/src/columns/table.d.ts +184 -0
  56. package/dist/src/columns/table.d.ts.map +1 -0
  57. package/dist/src/columns/table.js +485 -0
  58. package/dist/src/columns/table.js.map +1 -0
  59. package/dist/src/constants.d.ts +34 -0
  60. package/dist/src/constants.d.ts.map +1 -0
  61. package/dist/src/constants.js +79 -0
  62. package/dist/src/constants.js.map +1 -0
  63. package/dist/src/errors.d.ts +76 -0
  64. package/dist/src/errors.d.ts.map +1 -0
  65. package/dist/src/errors.js +32 -0
  66. package/dist/src/errors.js.map +1 -0
  67. package/dist/src/ids/edge-id-index.d.ts +77 -0
  68. package/dist/src/ids/edge-id-index.d.ts.map +1 -0
  69. package/dist/src/ids/edge-id-index.js +155 -0
  70. package/dist/src/ids/edge-id-index.js.map +1 -0
  71. package/dist/src/ids/node-id-map.d.ts +280 -0
  72. package/dist/src/ids/node-id-map.d.ts.map +1 -0
  73. package/dist/src/ids/node-id-map.js +1139 -0
  74. package/dist/src/ids/node-id-map.js.map +1 -0
  75. package/dist/src/ids/string-store.d.ts +219 -0
  76. package/dist/src/ids/string-store.d.ts.map +1 -0
  77. package/dist/src/ids/string-store.js +526 -0
  78. package/dist/src/ids/string-store.js.map +1 -0
  79. package/dist/src/index.d.ts +30 -0
  80. package/dist/src/index.d.ts.map +1 -0
  81. package/dist/src/index.js +29 -0
  82. package/dist/src/index.js.map +1 -0
  83. package/dist/src/populate/from-csr.d.ts +61 -0
  84. package/dist/src/populate/from-csr.d.ts.map +1 -0
  85. package/dist/src/populate/from-csr.js +706 -0
  86. package/dist/src/populate/from-csr.js.map +1 -0
  87. package/dist/src/populate/from-edge-arrays.d.ts +51 -0
  88. package/dist/src/populate/from-edge-arrays.d.ts.map +1 -0
  89. package/dist/src/populate/from-edge-arrays.js +217 -0
  90. package/dist/src/populate/from-edge-arrays.js.map +1 -0
  91. package/dist/src/populate/from-records.d.ts +51 -0
  92. package/dist/src/populate/from-records.d.ts.map +1 -0
  93. package/dist/src/populate/from-records.js +447 -0
  94. package/dist/src/populate/from-records.js.map +1 -0
  95. package/dist/src/snapshot/derived.d.ts +211 -0
  96. package/dist/src/snapshot/derived.d.ts.map +1 -0
  97. package/dist/src/snapshot/derived.js +1254 -0
  98. package/dist/src/snapshot/derived.js.map +1 -0
  99. package/dist/src/snapshot/graph-meta.d.ts +23 -0
  100. package/dist/src/snapshot/graph-meta.d.ts.map +1 -0
  101. package/dist/src/snapshot/graph-meta.js +159 -0
  102. package/dist/src/snapshot/graph-meta.js.map +1 -0
  103. package/dist/src/snapshot/graph-snapshot.d.ts +509 -0
  104. package/dist/src/snapshot/graph-snapshot.d.ts.map +1 -0
  105. package/dist/src/snapshot/graph-snapshot.js +1247 -0
  106. package/dist/src/snapshot/graph-snapshot.js.map +1 -0
  107. package/dist/src/snapshot/hash.d.ts +90 -0
  108. package/dist/src/snapshot/hash.d.ts.map +1 -0
  109. package/dist/src/snapshot/hash.js +228 -0
  110. package/dist/src/snapshot/hash.js.map +1 -0
  111. package/dist/src/snapshot/queries.d.ts +74 -0
  112. package/dist/src/snapshot/queries.d.ts.map +1 -0
  113. package/dist/src/snapshot/queries.js +131 -0
  114. package/dist/src/snapshot/queries.js.map +1 -0
  115. package/dist/src/snapshot/validate.d.ts +192 -0
  116. package/dist/src/snapshot/validate.d.ts.map +1 -0
  117. package/dist/src/snapshot/validate.js +990 -0
  118. package/dist/src/snapshot/validate.js.map +1 -0
  119. package/dist/src/snapshot/views.d.ts +274 -0
  120. package/dist/src/snapshot/views.d.ts.map +1 -0
  121. package/dist/src/snapshot/views.js +856 -0
  122. package/dist/src/snapshot/views.js.map +1 -0
  123. package/dist/src/types/builder.d.ts +456 -0
  124. package/dist/src/types/builder.d.ts.map +1 -0
  125. package/dist/src/types/builder.js +11 -0
  126. package/dist/src/types/builder.js.map +1 -0
  127. package/dist/src/types/columns.d.ts +615 -0
  128. package/dist/src/types/columns.d.ts.map +1 -0
  129. package/dist/src/types/columns.js +14 -0
  130. package/dist/src/types/columns.js.map +1 -0
  131. package/dist/src/types/index.d.ts +14 -0
  132. package/dist/src/types/index.d.ts.map +1 -0
  133. package/dist/src/types/index.js +11 -0
  134. package/dist/src/types/index.js.map +1 -0
  135. package/dist/src/types/internal.d.ts +172 -0
  136. package/dist/src/types/internal.d.ts.map +1 -0
  137. package/dist/src/types/internal.js +13 -0
  138. package/dist/src/types/internal.js.map +1 -0
  139. package/dist/src/types/snapshot.d.ts +801 -0
  140. package/dist/src/types/snapshot.d.ts.map +1 -0
  141. package/dist/src/types/snapshot.js +14 -0
  142. package/dist/src/types/snapshot.js.map +1 -0
  143. package/dist/src/types/wire.d.ts +196 -0
  144. package/dist/src/types/wire.d.ts.map +1 -0
  145. package/dist/src/types/wire.js +8 -0
  146. package/dist/src/types/wire.js.map +1 -0
  147. package/dist/src/util/mask.d.ts +55 -0
  148. package/dist/src/util/mask.d.ts.map +1 -0
  149. package/dist/src/util/mask.js +71 -0
  150. package/dist/src/util/mask.js.map +1 -0
  151. package/dist/src/util/options.d.ts +22 -0
  152. package/dist/src/util/options.d.ts.map +1 -0
  153. package/dist/src/util/options.js +49 -0
  154. package/dist/src/util/options.js.map +1 -0
  155. package/dist/src/util/shared-buffers.d.ts +42 -0
  156. package/dist/src/util/shared-buffers.d.ts.map +1 -0
  157. package/dist/src/util/shared-buffers.js +52 -0
  158. package/dist/src/util/shared-buffers.js.map +1 -0
  159. package/dist/src/util/typed-array.d.ts +205 -0
  160. package/dist/src/util/typed-array.d.ts.map +1 -0
  161. package/dist/src/util/typed-array.js +289 -0
  162. package/dist/src/util/typed-array.js.map +1 -0
  163. package/dist/src/wire/bytes.d.ts +69 -0
  164. package/dist/src/wire/bytes.d.ts.map +1 -0
  165. package/dist/src/wire/bytes.js +361 -0
  166. package/dist/src/wire/bytes.js.map +1 -0
  167. package/dist/src/wire/carried-views.d.ts +111 -0
  168. package/dist/src/wire/carried-views.d.ts.map +1 -0
  169. package/dist/src/wire/carried-views.js +286 -0
  170. package/dist/src/wire/carried-views.js.map +1 -0
  171. package/dist/src/wire/from-wire.d.ts +144 -0
  172. package/dist/src/wire/from-wire.d.ts.map +1 -0
  173. package/dist/src/wire/from-wire.js +1425 -0
  174. package/dist/src/wire/from-wire.js.map +1 -0
  175. package/dist/src/wire/to-wire.d.ts +171 -0
  176. package/dist/src/wire/to-wire.d.ts.map +1 -0
  177. package/dist/src/wire/to-wire.js +652 -0
  178. package/dist/src/wire/to-wire.js.map +1 -0
  179. package/dist/tsconfig.build.tsbuildinfo +1 -0
  180. package/package.json +72 -7
  181. package/src/builder/arena.ts +192 -0
  182. package/src/builder/compact.ts +1811 -0
  183. package/src/builder/counting-sort.ts +506 -0
  184. package/src/builder/freeze.ts +689 -0
  185. package/src/builder/graph-builder.ts +2264 -0
  186. package/src/builder/options.ts +29 -0
  187. package/src/columns/bitmap.ts +196 -0
  188. package/src/columns/column.ts +2574 -0
  189. package/src/columns/dictionary.ts +114 -0
  190. package/src/columns/growable.ts +350 -0
  191. package/src/columns/infer.ts +285 -0
  192. package/src/columns/remap.ts +663 -0
  193. package/src/columns/table.ts +568 -0
  194. package/src/constants.ts +89 -0
  195. package/src/errors.ts +115 -0
  196. package/src/ids/edge-id-index.ts +179 -0
  197. package/src/ids/node-id-map.ts +1340 -0
  198. package/src/ids/string-store.ts +589 -0
  199. package/src/index.ts +139 -0
  200. package/src/lib-resizable-array-buffer.d.ts +34 -0
  201. package/src/populate/from-csr.ts +802 -0
  202. package/src/populate/from-edge-arrays.ts +257 -0
  203. package/src/populate/from-records.ts +536 -0
  204. package/src/snapshot/derived.ts +1486 -0
  205. package/src/snapshot/graph-meta.ts +167 -0
  206. package/src/snapshot/graph-snapshot.ts +1503 -0
  207. package/src/snapshot/hash.ts +241 -0
  208. package/src/snapshot/queries.ts +136 -0
  209. package/src/snapshot/validate.ts +1108 -0
  210. package/src/snapshot/views.ts +943 -0
  211. package/src/types/builder.ts +480 -0
  212. package/src/types/columns.ts +727 -0
  213. package/src/types/index.ts +14 -0
  214. package/src/types/internal.ts +195 -0
  215. package/src/types/snapshot.ts +886 -0
  216. package/src/types/wire.ts +207 -0
  217. package/src/util/mask.ts +89 -0
  218. package/src/util/options.ts +57 -0
  219. package/src/util/shared-buffers.ts +56 -0
  220. package/src/util/typed-array.ts +371 -0
  221. package/src/wire/bytes.ts +440 -0
  222. package/src/wire/carried-views.ts +327 -0
  223. package/src/wire/from-wire.ts +1690 -0
  224. package/src/wire/to-wire.ts +755 -0
@@ -0,0 +1,184 @@
1
+ /**
2
+ * AttributeTable: a set of index-aligned columns with a fixed row count (design section 5.7). The
3
+ * column SET is a mutable side table of the snapshot (set / remove / rename at any time, by the
4
+ * snapshot owner); the row count is fixed for the life of the table (invariant I17) and column
5
+ * contents are frozen unless the column was declared mutable (design section 5.8). "Absent" is
6
+ * always null on this surface; undefined only ever means "unset row" from value(). Iteration yields
7
+ * columns in declaration order. At most one column per role (E_DUPLICATE_ROLE).
8
+ *
9
+ * The exported helper functions (tableWithColumns, verifyUniqueColumns, declareColumn) are for the
10
+ * snapshot, builder and freeze modules; they are not part of the public surface.
11
+ */
12
+ import { type AttributeTableContract, type Column, type ColumnDeclPatch, type ColumnDomain, type ColumnInput, type ColumnOf, type ColumnRole, type Dtype, type F32, type I32, type SetOptions, type TypedArrayData, type U32 } from "../types/index.js";
13
+ /**
14
+ * The number of column-set changes a table has seen (set / remove / rename), so a cached role or name
15
+ * lookup can be reused while the set is unchanged.
16
+ * @param table - the table
17
+ * @returns the change count
18
+ */
19
+ export declare function columnSetVersion(table: AttributeTable): number;
20
+ /**
21
+ * A set of columns with a fixed row count (design sections 5.7 and 12.2): `nodes` (nodeCount rows),
22
+ * `edges` (edgeCount rows), `graph` (1 row) and extension tables. The column set is a mutable side
23
+ * table; the row count is fixed; iteration is in declaration order.
24
+ */
25
+ export declare class AttributeTable implements AttributeTableContract {
26
+ /** The table the columns belong to. */
27
+ readonly domain: ColumnDomain;
28
+ /** Number of rows of every column; fixed for the life of the table. */
29
+ readonly rowCount: number;
30
+ private readonly columns;
31
+ /** Bumped on every change of the column set (set / remove / rename), for callers that cache a lookup. */
32
+ private mutations;
33
+ /**
34
+ * Column names in declaration order.
35
+ * @returns a fresh array of the names
36
+ */
37
+ names(): readonly string[];
38
+ /**
39
+ * Whether a column exists.
40
+ * @param name - the column name
41
+ * @returns true when present
42
+ */
43
+ has(name: string): boolean;
44
+ /**
45
+ * Total lookup by name.
46
+ * @param name - the column name
47
+ * @returns the column, or null when absent
48
+ */
49
+ get(name: string): Column | null;
50
+ /**
51
+ * Checked lookup by name.
52
+ * @param name - the column name
53
+ * @returns the column; E_UNKNOWN_COLUMN when absent
54
+ */
55
+ require(name: string): Column;
56
+ /**
57
+ * Total lookup by name and dtype.
58
+ * @param name - the column name
59
+ * @param dtype - the expected dtype
60
+ * @returns the column, or null when absent or of another dtype
61
+ */
62
+ typed<D extends Dtype>(name: string, dtype: D): ColumnOf<D> | null;
63
+ /**
64
+ * Checked lookup by name and dtype.
65
+ * @param name - the column name
66
+ * @param dtype - the expected dtype
67
+ * @returns the column; E_UNKNOWN_COLUMN when absent, E_COLUMN_TYPE when of another dtype
68
+ */
69
+ requireTyped<D extends Dtype>(name: string, dtype: D): ColumnOf<D>;
70
+ /**
71
+ * The column holding a role (at most one per table).
72
+ * @param role - the role
73
+ * @returns the column, or null when no column has the role
74
+ */
75
+ byRole(role: ColumnRole): Column | null;
76
+ /**
77
+ * Typed read of one cell honouring the column's declared default.
78
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
79
+ * @param row - the row index; E_INDEX_RANGE when out of range
80
+ * @returns the value, the default for an unset row, or undefined for an unset row without a default
81
+ */
82
+ value(name: string, row: number): unknown;
83
+ /**
84
+ * Whether one cell holds a value.
85
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
86
+ * @param row - the row index (false when out of range)
87
+ * @returns true when set
88
+ */
89
+ isSet(name: string, row: number): boolean;
90
+ /**
91
+ * Attach a column (design section 5.7). A typed array is adopted by reference after its length is
92
+ * checked (E_COLUMN_LENGTH); a u8 array from which no padded u32 view is constructible is copied
93
+ * unless opts.adopt is "strict" (E_COLUMN_ALIGNMENT); a view over a SharedArrayBuffer or a
94
+ * resizable buffer is E_UNSUPPORTED (decision D-SAB, invariant I10); a JS array builds a column of
95
+ * the declared dtype, or of the dtype inferred from the values (design section 5.1) when the
96
+ * patch names none; a Column object is moved in when its row count matches. Replaces a column of
97
+ * the same name. E_DUPLICATE_ROLE when the declared role is held by another column and
98
+ * opts.replaceRole is not set; with replaceRole the previous holder is removed.
99
+ * @param name - the column name
100
+ * @param data - a Column, a typed array, or a JS array of values
101
+ * @param decl - declaration fields to apply (dtype is inferred from a typed array when omitted)
102
+ * @param opts - role replacement and u8 adoption options
103
+ * @returns the attached column (`column.data !== data` only when a u8 array was copied)
104
+ */
105
+ set(name: string, data: Column | TypedArrayData | readonly unknown[], decl?: ColumnDeclPatch, opts?: SetOptions): Column;
106
+ /**
107
+ * Remove a column.
108
+ * @param name - the column name
109
+ * @returns true when a column was removed
110
+ */
111
+ remove(name: string): boolean;
112
+ /**
113
+ * Rename a column in place (declaration order kept). The Column object is re-wrapped under the new
114
+ * name; its storage is shared with the previous object.
115
+ * @param from - the current name; E_UNKNOWN_COLUMN when absent
116
+ * @param to - the new name; E_COLUMN_EXISTS when another column has it
117
+ */
118
+ rename(from: string, to: string): void;
119
+ /**
120
+ * The array a GPU binds for a column (design section 10.4): its own data for the direct dtypes,
121
+ * the padded u32 view for u8, the packed words for bool, the codes for dict, and a cached f32 copy
122
+ * for f64.
123
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
124
+ * @returns the bindable array; E_GPU_INELIGIBLE for string / list / json
125
+ */
126
+ gpuView(name: string): U32 | I32 | F32;
127
+ /**
128
+ * A new table with the same columns: the Column objects are shared, the set is independent.
129
+ * @returns the cloned table
130
+ */
131
+ clone(): AttributeTable;
132
+ /**
133
+ * Iterate the columns in declaration order.
134
+ * @returns an iterator over the columns
135
+ */
136
+ [Symbol.iterator](): IterableIterator<Column>;
137
+ /**
138
+ * Move a Column object in: checked for row count and re-wrapped when its name, domain or
139
+ * declaration differ from the target slot.
140
+ * @param name - the target name
141
+ * @param column - the column
142
+ * @param decl - an optional declaration patch
143
+ * @returns the column to store (the same object when nothing changes)
144
+ */
145
+ private adoptColumn;
146
+ private checkColumn;
147
+ /**
148
+ * Enforce "at most one column per role": E_DUPLICATE_ROLE when another column holds the role,
149
+ * unless replaceRole, in which case that column is removed.
150
+ * @param name - the column being attached (a column may keep its own role)
151
+ * @param role - the role being attached, or null
152
+ * @param replaceRole - whether to evict the previous holder
153
+ */
154
+ private checkRole;
155
+ }
156
+ /**
157
+ * Create an empty table.
158
+ * @param domain - the table's domain
159
+ * @param rowCount - the fixed row count
160
+ * @returns a table with no columns
161
+ */
162
+ export declare function createTable(domain: ColumnDomain, rowCount: number): AttributeTable;
163
+ /**
164
+ * A cloned table plus the given columns (the column half of snapshot.withColumns(), design section
165
+ * 7.3): the Column objects of the source are shared, the set is new, and each entry of `columns` is
166
+ * attached through set() (a typed array, or a ColumnInput carrying data and a declaration patch).
167
+ * @param table - the source table
168
+ * @param columns - the columns to add or replace, keyed by name
169
+ * @returns the new table
170
+ */
171
+ export declare function tableWithColumns(table: AttributeTable, columns: Readonly<Record<string, TypedArrayData | ColumnInput>>): AttributeTable;
172
+ /**
173
+ * Enforce a unique column over its set rows (design section 5.5; the freeze step 10 hook):
174
+ * E_DUPLICATE_EDGE_ID for an edge column and E_DUPLICATE_ID for every other domain, with the
175
+ * duplicated value and both rows in details.
176
+ * @param column - a column declared unique
177
+ */
178
+ export declare function verifyUniqueColumn(column: Column): void;
179
+ /**
180
+ * Enforce every unique column of a table (freeze step 10).
181
+ * @param table - the table to check
182
+ */
183
+ export declare function verifyUniqueColumns(table: AttributeTable): void;
184
+ //# sourceMappingURL=table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/columns/table.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,MAAM,EACX,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,UAAU,EACf,KAAK,KAAK,EACV,KAAK,GAAG,EACR,KAAK,GAAG,EACR,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,GAAG,EACX,MAAM,mBAAmB,CAAC;AAgD3B;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAE9D;AAaD;;;;GAIG;AACH,qBAAa,cAAe,YAAW,sBAAsB;IACzD,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAE9B,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAE9C,yGAAyG;IACzG,OAAO,CAAC,SAAS,CAAK;IAgCtB;;;OAGG;IACH,KAAK,IAAI,SAAS,MAAM,EAAE;IAI1B;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIhC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAW7B;;;;;OAKG;IACH,KAAK,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAQlE;;;;;OAKG;IACH,YAAY,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IAYlE;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IASvC;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzC;;;;;;;;;;;;;;OAcG;IACH,GAAG,CACC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,OAAO,EAAE,EAClD,IAAI,CAAC,EAAE,eAAe,EACtB,IAAI,CAAC,EAAE,UAAU,GAClB,MAAM;IA6CT;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQ7B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IA4BtC;;;;;;OAMG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG;IAItC;;;OAGG;IACH,KAAK,IAAI,cAAc;IAQvB;;;OAGG;IACH,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAI7C;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,WAAW;IAUnB;;;;;;OAMG;IACH,OAAO,CAAC,SAAS;CAkBpB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAElF;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,cAAc,EACrB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CAAC,CAAC,GAChE,cAAc,CAWhB;AAwCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA0BvD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAI/D"}
@@ -0,0 +1,485 @@
1
+ /**
2
+ * AttributeTable: a set of index-aligned columns with a fixed row count (design section 5.7). The
3
+ * column SET is a mutable side table of the snapshot (set / remove / rename at any time, by the
4
+ * snapshot owner); the row count is fixed for the life of the table (invariant I17) and column
5
+ * contents are frozen unless the column was declared mutable (design section 5.8). "Absent" is
6
+ * always null on this surface; undefined only ever means "unset row" from value(). Iteration yields
7
+ * columns in declaration order. At most one column per role (E_DUPLICATE_ROLE).
8
+ *
9
+ * The exported helper functions (tableWithColumns, verifyUniqueColumns, declareColumn) are for the
10
+ * snapshot, builder and freeze modules; they are not part of the public surface.
11
+ */
12
+ import { GraphFormatError } from "../errors.js";
13
+ import { assertOneOf } from "../util/options.js";
14
+ import { claimHolder, holderCount, isShared, noteShared } from "../util/shared-buffers.js";
15
+ import { bitmapGet } from "./bitmap.js";
16
+ import { columnBuffers, columnFromTypedArray, columnFromValues, gpuViewOf, isPackageColumn, metaToDecl, resolveColumnMeta, rewrapColumn, } from "./column.js";
17
+ /**
18
+ * Whether a set() payload is a typed array (as opposed to a Column object or a JS array).
19
+ * @param data - the payload
20
+ * @returns true for one of the five typed-array classes
21
+ */
22
+ function isTypedArrayData(data) {
23
+ return (data instanceof Uint32Array ||
24
+ data instanceof Int32Array ||
25
+ data instanceof Float32Array ||
26
+ data instanceof Float64Array ||
27
+ data instanceof Uint8Array);
28
+ }
29
+ /**
30
+ * Whether a set() payload is a Column object (duck-typed on the members every column has).
31
+ * @param data - the payload
32
+ * @returns true for a Column
33
+ */
34
+ function isColumn(data) {
35
+ if (typeof data !== "object" || data === null || Array.isArray(data) || isTypedArrayData(data)) {
36
+ return false;
37
+ }
38
+ const candidate = data;
39
+ return (typeof candidate.dtype === "string" &&
40
+ typeof candidate.meta === "object" &&
41
+ typeof candidate.length === "number");
42
+ }
43
+ /**
44
+ * The number of column-set changes a table has seen (set / remove / rename), so a cached role or name
45
+ * lookup can be reused while the set is unchanged.
46
+ * @param table - the table
47
+ * @returns the change count
48
+ */
49
+ export function columnSetVersion(table) {
50
+ return table.mutations;
51
+ }
52
+ /**
53
+ * Record a table as a holder of a column and of every buffer the column views (design section 9.1).
54
+ * @param column - the column being attached
55
+ */
56
+ function claimColumn(column) {
57
+ claimHolder(column);
58
+ for (const buffer of columnBuffers(column)) {
59
+ claimHolder(buffer);
60
+ }
61
+ }
62
+ /**
63
+ * A set of columns with a fixed row count (design sections 5.7 and 12.2): `nodes` (nodeCount rows),
64
+ * `edges` (edgeCount rows), `graph` (1 row) and extension tables. The column set is a mutable side
65
+ * table; the row count is fixed; iteration is in declaration order.
66
+ */
67
+ export class AttributeTable {
68
+ /**
69
+ * Create a table from wrapped columns (the constructor the freeze pipeline, fromCsr and the wire
70
+ * reader use). Every column must have the table's row count and domain, names must be unique and
71
+ * at most one column may hold each role.
72
+ * @param parts - the domain, the row count and the columns in declaration order
73
+ * @internal
74
+ */
75
+ constructor(parts) {
76
+ /** Bumped on every change of the column set (set / remove / rename), for callers that cache a lookup. */
77
+ this.mutations = 0;
78
+ const { domain, rowCount } = parts;
79
+ if (!(Number.isInteger(rowCount) && rowCount >= 0)) {
80
+ throw new GraphFormatError("E_COLUMN_LENGTH", `invalid row count ${rowCount} for a ${domain} table`, {
81
+ domain,
82
+ found: rowCount,
83
+ });
84
+ }
85
+ this.domain = domain;
86
+ this.rowCount = rowCount;
87
+ this.columns = new Map();
88
+ for (const column of parts.columns) {
89
+ const { name } = column.meta;
90
+ if (this.columns.has(name)) {
91
+ throw new GraphFormatError("E_COLUMN_EXISTS", `column "${name}" is declared twice`, { column: name });
92
+ }
93
+ this.checkColumn(name, column);
94
+ this.checkRole(name, column.meta.role, false);
95
+ this.columns.set(name, column);
96
+ claimColumn(column);
97
+ }
98
+ }
99
+ /**
100
+ * Column names in declaration order.
101
+ * @returns a fresh array of the names
102
+ */
103
+ names() {
104
+ return [...this.columns.keys()];
105
+ }
106
+ /**
107
+ * Whether a column exists.
108
+ * @param name - the column name
109
+ * @returns true when present
110
+ */
111
+ has(name) {
112
+ return this.columns.has(name);
113
+ }
114
+ /**
115
+ * Total lookup by name.
116
+ * @param name - the column name
117
+ * @returns the column, or null when absent
118
+ */
119
+ get(name) {
120
+ return this.columns.get(name) ?? null;
121
+ }
122
+ /**
123
+ * Checked lookup by name.
124
+ * @param name - the column name
125
+ * @returns the column; E_UNKNOWN_COLUMN when absent
126
+ */
127
+ require(name) {
128
+ const column = this.columns.get(name);
129
+ if (column === undefined) {
130
+ throw new GraphFormatError("E_UNKNOWN_COLUMN", `no ${this.domain} column named "${name}"`, {
131
+ column: name,
132
+ domain: this.domain,
133
+ });
134
+ }
135
+ return column;
136
+ }
137
+ /**
138
+ * Total lookup by name and dtype.
139
+ * @param name - the column name
140
+ * @param dtype - the expected dtype
141
+ * @returns the column, or null when absent or of another dtype
142
+ */
143
+ typed(name, dtype) {
144
+ const column = this.columns.get(name);
145
+ if (column === undefined || column.dtype !== dtype) {
146
+ return null;
147
+ }
148
+ return column;
149
+ }
150
+ /**
151
+ * Checked lookup by name and dtype.
152
+ * @param name - the column name
153
+ * @param dtype - the expected dtype
154
+ * @returns the column; E_UNKNOWN_COLUMN when absent, E_COLUMN_TYPE when of another dtype
155
+ */
156
+ requireTyped(name, dtype) {
157
+ const column = this.require(name);
158
+ if (column.dtype !== dtype) {
159
+ throw new GraphFormatError("E_COLUMN_TYPE", `column "${name}" is ${column.dtype}, expected ${dtype}`, {
160
+ column: name,
161
+ expected: dtype,
162
+ found: column.dtype,
163
+ });
164
+ }
165
+ return column;
166
+ }
167
+ /**
168
+ * The column holding a role (at most one per table).
169
+ * @param role - the role
170
+ * @returns the column, or null when no column has the role
171
+ */
172
+ byRole(role) {
173
+ for (const column of this.columns.values()) {
174
+ if (column.meta.role === role) {
175
+ return column;
176
+ }
177
+ }
178
+ return null;
179
+ }
180
+ /**
181
+ * Typed read of one cell honouring the column's declared default.
182
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
183
+ * @param row - the row index; E_INDEX_RANGE when out of range
184
+ * @returns the value, the default for an unset row, or undefined for an unset row without a default
185
+ */
186
+ value(name, row) {
187
+ return this.require(name).value(row);
188
+ }
189
+ /**
190
+ * Whether one cell holds a value.
191
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
192
+ * @param row - the row index (false when out of range)
193
+ * @returns true when set
194
+ */
195
+ isSet(name, row) {
196
+ return this.require(name).isSet(row);
197
+ }
198
+ /**
199
+ * Attach a column (design section 5.7). A typed array is adopted by reference after its length is
200
+ * checked (E_COLUMN_LENGTH); a u8 array from which no padded u32 view is constructible is copied
201
+ * unless opts.adopt is "strict" (E_COLUMN_ALIGNMENT); a view over a SharedArrayBuffer or a
202
+ * resizable buffer is E_UNSUPPORTED (decision D-SAB, invariant I10); a JS array builds a column of
203
+ * the declared dtype, or of the dtype inferred from the values (design section 5.1) when the
204
+ * patch names none; a Column object is moved in when its row count matches. Replaces a column of
205
+ * the same name. E_DUPLICATE_ROLE when the declared role is held by another column and
206
+ * opts.replaceRole is not set; with replaceRole the previous holder is removed.
207
+ * @param name - the column name
208
+ * @param data - a Column, a typed array, or a JS array of values
209
+ * @param decl - declaration fields to apply (dtype is inferred from a typed array when omitted)
210
+ * @param opts - role replacement and u8 adoption options
211
+ * @returns the attached column (`column.data !== data` only when a u8 array was copied)
212
+ */
213
+ set(name, data, decl, opts) {
214
+ const patch = decl ?? {};
215
+ let column;
216
+ if (isTypedArrayData(data)) {
217
+ const adopt = assertOneOf("adopt", opts?.adopt, ["copy", "strict"]) ?? "copy";
218
+ column = columnFromTypedArray(this.domain, this.rowCount, name, data, patch, adopt);
219
+ }
220
+ else if (Array.isArray(data)) {
221
+ column = columnFromValues(this.domain, this.rowCount, name, data, patch);
222
+ }
223
+ else if (isColumn(data)) {
224
+ if (!isPackageColumn(data)) {
225
+ throw new GraphFormatError("E_COLUMN_TYPE", `column "${name}": not a Column of this package`, {
226
+ column: name,
227
+ reason: "foreign column",
228
+ });
229
+ }
230
+ column = this.adoptColumn(name, data, decl);
231
+ if (column !== data && holderCount(data) > 0) {
232
+ // a re-wrapped column shares every buffer with `data`, which another table still holds
233
+ noteShared(column);
234
+ }
235
+ }
236
+ else {
237
+ throw new GraphFormatError("E_COLUMN_TYPE", `column "${name}": unsupported data (${typeof data})`, {
238
+ column: name,
239
+ found: typeof data,
240
+ });
241
+ }
242
+ this.checkRole(name, column.meta.role, opts?.replaceRole ?? false);
243
+ const previous = this.columns.get(name);
244
+ if (previous !== column) {
245
+ // a Column object moved in from another table gains a second holder, and so does every
246
+ // buffer it views (a zero-copy slice of another table's column, design section 9.1);
247
+ // re-wrapping this table's own column under a patch adds no holder of its buffers
248
+ claimHolder(column);
249
+ if (previous !== data) {
250
+ for (const buffer of columnBuffers(column)) {
251
+ claimHolder(buffer);
252
+ }
253
+ }
254
+ }
255
+ // Map.set on an existing key keeps its position, so a replacement keeps the declaration order
256
+ this.columns.set(name, column);
257
+ this.mutations++;
258
+ return column;
259
+ }
260
+ /**
261
+ * Remove a column.
262
+ * @param name - the column name
263
+ * @returns true when a column was removed
264
+ */
265
+ remove(name) {
266
+ const removed = this.columns.delete(name);
267
+ if (removed) {
268
+ this.mutations++;
269
+ }
270
+ return removed;
271
+ }
272
+ /**
273
+ * Rename a column in place (declaration order kept). The Column object is re-wrapped under the new
274
+ * name; its storage is shared with the previous object.
275
+ * @param from - the current name; E_UNKNOWN_COLUMN when absent
276
+ * @param to - the new name; E_COLUMN_EXISTS when another column has it
277
+ */
278
+ rename(from, to) {
279
+ const column = this.require(from);
280
+ if (from === to) {
281
+ return;
282
+ }
283
+ if (this.columns.has(to)) {
284
+ throw new GraphFormatError("E_COLUMN_EXISTS", `cannot rename "${from}": a column named "${to}" exists`, {
285
+ column: to,
286
+ });
287
+ }
288
+ const renamed = rewrapColumn(column, resolveColumnMeta(to, this.domain, metaToDecl(column.meta)));
289
+ // the same table keeps holding the same buffers: only the new Column object is claimed
290
+ claimHolder(renamed);
291
+ if (isShared(column)) {
292
+ noteShared(renamed);
293
+ }
294
+ const entries = [...this.columns.entries()];
295
+ this.columns.clear();
296
+ for (const [name, existing] of entries) {
297
+ if (name === from) {
298
+ this.columns.set(to, renamed);
299
+ }
300
+ else {
301
+ this.columns.set(name, existing);
302
+ }
303
+ }
304
+ this.mutations++;
305
+ }
306
+ /**
307
+ * The array a GPU binds for a column (design section 10.4): its own data for the direct dtypes,
308
+ * the padded u32 view for u8, the packed words for bool, the codes for dict, and a cached f32 copy
309
+ * for f64.
310
+ * @param name - the column name; E_UNKNOWN_COLUMN when absent
311
+ * @returns the bindable array; E_GPU_INELIGIBLE for string / list / json
312
+ */
313
+ gpuView(name) {
314
+ return gpuViewOf(this.require(name));
315
+ }
316
+ /**
317
+ * A new table with the same columns: the Column objects are shared, the set is independent.
318
+ * @returns the cloned table
319
+ */
320
+ clone() {
321
+ return new AttributeTable({
322
+ domain: this.domain,
323
+ rowCount: this.rowCount,
324
+ columns: [...this.columns.values()],
325
+ });
326
+ }
327
+ /**
328
+ * Iterate the columns in declaration order.
329
+ * @returns an iterator over the columns
330
+ */
331
+ [Symbol.iterator]() {
332
+ return this.columns.values();
333
+ }
334
+ /**
335
+ * Move a Column object in: checked for row count and re-wrapped when its name, domain or
336
+ * declaration differ from the target slot.
337
+ * @param name - the target name
338
+ * @param column - the column
339
+ * @param decl - an optional declaration patch
340
+ * @returns the column to store (the same object when nothing changes)
341
+ */
342
+ adoptColumn(name, column, decl) {
343
+ this.checkColumn(name, column);
344
+ const { meta } = column;
345
+ const unchanged = decl === undefined && meta.name === name && meta.domain === this.domain;
346
+ if (unchanged) {
347
+ return column;
348
+ }
349
+ const merged = { ...metaToDecl(meta), ...decl };
350
+ if (decl?.fill === undefined) {
351
+ merged.fill = meta.fill;
352
+ }
353
+ return rewrapColumn(column, resolveColumnMeta(name, this.domain, merged));
354
+ }
355
+ checkColumn(name, column) {
356
+ if (column.length !== this.rowCount) {
357
+ throw new GraphFormatError("E_COLUMN_LENGTH", `column "${name}" has ${column.length} rows; the ${this.domain} table has ${this.rowCount}`, { column: name, expected: this.rowCount, found: column.length });
358
+ }
359
+ }
360
+ /**
361
+ * Enforce "at most one column per role": E_DUPLICATE_ROLE when another column holds the role,
362
+ * unless replaceRole, in which case that column is removed.
363
+ * @param name - the column being attached (a column may keep its own role)
364
+ * @param role - the role being attached, or null
365
+ * @param replaceRole - whether to evict the previous holder
366
+ */
367
+ checkRole(name, role, replaceRole) {
368
+ if (role === null) {
369
+ return;
370
+ }
371
+ for (const [otherName, other] of this.columns) {
372
+ if (otherName !== name && other.meta.role === role) {
373
+ if (!replaceRole) {
374
+ throw new GraphFormatError("E_DUPLICATE_ROLE", `role "${role}" is already held by column "${otherName}" in the ${this.domain} table`, { role, column: name, holder: otherName });
375
+ }
376
+ this.columns.delete(otherName);
377
+ return;
378
+ }
379
+ }
380
+ }
381
+ }
382
+ /**
383
+ * Create an empty table.
384
+ * @param domain - the table's domain
385
+ * @param rowCount - the fixed row count
386
+ * @returns a table with no columns
387
+ */
388
+ export function createTable(domain, rowCount) {
389
+ return new AttributeTable({ domain, rowCount, columns: [] });
390
+ }
391
+ /**
392
+ * A cloned table plus the given columns (the column half of snapshot.withColumns(), design section
393
+ * 7.3): the Column objects of the source are shared, the set is new, and each entry of `columns` is
394
+ * attached through set() (a typed array, or a ColumnInput carrying data and a declaration patch).
395
+ * @param table - the source table
396
+ * @param columns - the columns to add or replace, keyed by name
397
+ * @returns the new table
398
+ */
399
+ export function tableWithColumns(table, columns) {
400
+ const out = table.clone();
401
+ for (const name of Object.keys(columns)) {
402
+ const input = columns[name];
403
+ if (isTypedArrayData(input)) {
404
+ out.set(name, input);
405
+ }
406
+ else {
407
+ out.set(name, input.data, input.decl);
408
+ }
409
+ }
410
+ return out;
411
+ }
412
+ /**
413
+ * The comparable key of one set cell for uniqueness checks: the number, string, boolean or
414
+ * dictionary value; json values are compared by their JSON text.
415
+ * @param column - the column
416
+ * @param row - a set row
417
+ * @returns the key
418
+ */
419
+ function uniqueKey(column, row) {
420
+ const { dtype } = column;
421
+ switch (dtype) {
422
+ case "f32":
423
+ case "f64":
424
+ case "i32":
425
+ case "u32":
426
+ case "u8":
427
+ if (column.meta.components === 1) {
428
+ return column.data[row];
429
+ }
430
+ return Array.from(column.data.subarray(row * column.meta.components, (row + 1) * column.meta.components)).join(",");
431
+ case "bool":
432
+ return bitmapGet(column.data, row);
433
+ case "dict":
434
+ return column.codes[row];
435
+ case "string":
436
+ return column.valueAt(row);
437
+ case "list":
438
+ return JSON.stringify(column.sliceOf(row));
439
+ case "json":
440
+ return JSON.stringify(column.values[row]);
441
+ default: {
442
+ const name = dtype;
443
+ throw new GraphFormatError("E_COLUMN_TYPE", `unknown dtype ${name}`, { dtype: name });
444
+ }
445
+ }
446
+ }
447
+ /**
448
+ * Enforce a unique column over its set rows (design section 5.5; the freeze step 10 hook):
449
+ * E_DUPLICATE_EDGE_ID for an edge column and E_DUPLICATE_ID for every other domain, with the
450
+ * duplicated value and both rows in details.
451
+ * @param column - a column declared unique
452
+ */
453
+ export function verifyUniqueColumn(column) {
454
+ if (!column.meta.unique) {
455
+ return;
456
+ }
457
+ const seen = new Map();
458
+ for (let row = 0; row < column.length; row++) {
459
+ if (!column.isSet(row)) {
460
+ continue;
461
+ }
462
+ const key = uniqueKey(column, row);
463
+ const first = seen.get(key);
464
+ if (first !== undefined) {
465
+ const code = column.meta.domain === "edge" ? "E_DUPLICATE_EDGE_ID" : "E_DUPLICATE_ID";
466
+ throw new GraphFormatError(code, `column "${column.meta.name}" is unique but rows ${first} and ${row} hold the same value`, {
467
+ column: column.meta.name,
468
+ domain: column.meta.domain,
469
+ rows: [first, row],
470
+ value: column.value(row),
471
+ });
472
+ }
473
+ seen.set(key, row);
474
+ }
475
+ }
476
+ /**
477
+ * Enforce every unique column of a table (freeze step 10).
478
+ * @param table - the table to check
479
+ */
480
+ export function verifyUniqueColumns(table) {
481
+ for (const column of table) {
482
+ verifyUniqueColumn(column);
483
+ }
484
+ }
485
+ //# sourceMappingURL=table.js.map