-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbinding.d.cts
More file actions
1737 lines (1682 loc) · 65.4 KB
/
Copy pathbinding.d.cts
File metadata and controls
1737 lines (1682 loc) · 65.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* auto-generated by NAPI-RS */
/* eslint-disable */
/**
* `Temporal.PlainDate`, on a program that has it.
*
* Asked of `globalThis` rather than imported, because `Temporal`
* reached Stage 4 in March 2026 and which `lib` declares it is
* different in every version of TypeScript that has shipped since. A
* program compiling against a `lib` that has `Temporal` gets the real
* type here and is checked against it. One compiling against a `lib`
* that does not gets `unknown`, which needs a cast at the call site and
* is the truth: this client cannot promise a type the compiler has
* never heard of, and it should not fail to compile for saying so.
*/
export type ZuPlainDate = typeof globalThis extends {
Temporal: { PlainDate: new (...args: any[]) => infer Value }
}
? Value
: unknown
/** `Temporal.PlainTime`, on the terms [[ZuPlainDate]] gives. */
export type ZuPlainTime = typeof globalThis extends {
Temporal: { PlainTime: new (...args: any[]) => infer Value }
}
? Value
: unknown
/** `Temporal.PlainDateTime`, on the terms [[ZuPlainDate]] gives. */
export type ZuPlainDateTime = typeof globalThis extends {
Temporal: { PlainDateTime: new (...args: any[]) => infer Value }
}
? Value
: unknown
/** `Temporal.ZonedDateTime`, on the terms [[ZuPlainDate]] gives. */
export type ZuZonedDateTime = typeof globalThis extends {
Temporal: { ZonedDateTime: new (...args: any[]) => infer Value }
}
? Value
: unknown
/** `Temporal.Duration`, on the terms [[ZuPlainDate]] gives. Named for
* the standard's class rather than for this client's `ZuDuration`,
* which is the other one. */
export type ZuTemporalDuration = typeof globalThis extends {
Temporal: { Duration: new (...args: any[]) => infer Value }
}
? Value
: unknown
/**
* Every `Temporal` value this client understands, and nothing at all on
* a program whose `lib` has no `Temporal`.
*
* Nothing rather than `unknown` there, because this one is a member of
* a union: `unknown` in a union swallows it and would turn every row
* and every parameter into `unknown` for everybody. `never` in a union
* vanishes, so a program without `Temporal` types sees exactly what it
* saw before this existed.
*/
export type ZuTemporalValue = typeof globalThis extends {
Temporal: { Instant: new (...args: any[]) => infer Instant }
}
? Instant | ZuPlainDate | ZuPlainTime | ZuPlainDateTime | ZuZonedDateTime | ZuTemporalDuration
: never
/**
* A value a statement can hold, going out.
*
* INT64 is `bigint` and FLOAT is `number`, which is the one rule worth
* learning before anything else here: a JavaScript number stops being
* exact at 2^53 and zu's integers go to 2^63, so a count that came back
* as a number would be a count you cannot trust. `bigIntMode` changes
* that for a statement or for a connection, with the hazard it
* documents.
*
* A date, a time, a timestamp and a duration are the four classes by
* default and `Temporal` values on a connection opened with
* `{ temporal: true }`. A time with an offset is the exception in both
* directions: `Temporal` has no type for one, so it stays a `ZuTime`.
*
* BYTES is a `Uint8Array` and not a string. The bytes are octets and
* need not be text at all, so decoding them is the caller's call to
* make rather than this client's to make for them.
*
* DECIMAL is a `ZuDecimal` and not a `number`, for the reason INT64 is
* not one and a stronger one: a tenth is not a binary fraction, so a
* price that came back as a number would not be the price, and how many
* places it is known to would be gone as well.
*/
export type ZuValue =
| null
| boolean
| number
| bigint
| string
| ZuNode
| ZuRel
| ZuPath
| ZuDecimal
| ZuDate
| ZuTime
| ZuTimestamp
| ZuDuration
| ZuTemporalValue
| Uint8Array
| ZuValue[]
| { [field: string]: ZuValue }
/**
* A value a statement can be given, coming in.
*
* Wider than what comes out, because a `number` that is whole binds as
* INT64 and `undefined` binds as null, which is what makes an optional
* field of a plain object pass straight through. Negative zero is the
* exception and binds as FLOAT64: no INT64 is negative zero, so binding
* it as one throws away the sign the caller went out of their way to
* write. A `Temporal` value binds as the zu value it is on every
* connection, whether or not the connection asked for `Temporal` on the
* way out, because recognizing one costs a property read and refusing
* one would be a rule nobody could guess.
*
* A `Uint8Array` binds as BYTES, and it is the only typed array that
* binds at all: an `Int32Array` is a buffer somebody meant to load
* rather than a value a statement holds, so it is refused instead of
* being read as the empty object it has no properties to be.
*
* A `ZuDecimal` binds as DECIMAL and is the only way to send one. A
* `number` never becomes one, because a caller who wrote `0.1` gave the
* double that is not a tenth, and reading it as a decimal would put a
* number nobody wrote into the query.
*/
export type ZuParam =
| null
| undefined
| boolean
| number
| bigint
| string
| ZuDecimal
| ZuDate
| ZuTime
| ZuTimestamp
| ZuDuration
| ZuTemporalValue
| Uint8Array
| ZuParam[]
| { [field: string]: ZuParam }
/**
* A value an appender takes, which is narrower than what a statement
* takes.
*
* A column of an appender has one type, read from the table when the
* appender opened, and every value in it is that type. So there is no
* `null` here: a column that holds nulls cannot be appended to at all
* and the appender says so when it opens, and `undefined` in a row is a
* value the caller forgot rather than a null they meant. There are no
* lists and no objects either, because a property column holds a scalar.
*
* BYTES is a `Uint8Array`, which is the one type here that no statement
* parameter can be, and INT64 is a `bigint` or a whole `number` below
* 2^53. A number past that is refused rather than rounded, because past
* 2^53 a number no longer names one integer.
*/
export type ZuAppendValue =
| boolean
| number
| bigint
| string
| Uint8Array
| ZuDate
| ZuTime
| ZuTimestamp
| ZuDuration
| ZuTemporalValue
/**
* One value of a registered frame's column, when the column is written
* as a plain array.
*
* The same values an appender takes, without the bytes: a frame column
* is a run of values the engine reads where it lies, and byte strings
* are not a run of anything, so a BYTES column is refused rather than
* copied into a shape it does not have. There is no `null` either, for
* the reason there is none in a row of an appender.
*/
export type ZuFrameValue =
| boolean
| number
| bigint
| string
| ZuDate
| ZuTime
| ZuTimestamp
| ZuDuration
| ZuTemporalValue
/**
* One column of a registered frame.
*
* A typed array is the shape that costs nothing: the engine reads it
* where it lies and no byte of it is copied. A plain array is read into
* buffers of this client's own, because an array holds values of the
* runtime rather than numbers, and its first value settles what the
* column holds.
*/
export type ZuFrameColumn =
| Int8Array
| Uint8Array
| Uint8ClampedArray
| Int16Array
| Uint16Array
| Int32Array
| Uint32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array
| readonly ZuFrameValue[]
/**
* An Arrow table or record batch, described by its shape rather than by
* its class.
*
* Structural on purpose. `apache-arrow` is not a dependency of this
* client and should not have to be: recognizing a table by the two
* things every version of it has means a caller's copy of that library
* and this client's are never two copies of one package disagreeing
* about `instanceof`, and it means anything else that speaks the same
* shape works too.
*/
export interface ZuArrowTable {
readonly schema: { readonly fields: readonly { readonly name: string }[] }
getChildAt(index: number): unknown
}
/**
* Columns the caller already holds, ready to be registered under a name.
*
* An Arrow table, or an object of column name to values. Both are read
* where they lie wherever there is one run of bytes to read: the two
* cases that copy are an Arrow column that arrived in several chunks,
* which is concatenated once, and a plain JavaScript array, which was
* never a column of numbers to begin with.
*/
export type ZuFrame = ZuArrowTable | Record<string, ZuFrameColumn>
/**
* An edge list, as the pairs of row numbers it is.
*
* Rows are numbered from zero in the order their columns were written,
* because at load time a row has no other name. The flat spelling is
* there for a program that built its edges in memory and would rather
* not make a million two element arrays to hand them over: two elements
* an edge, read in one pass.
*/
export type ZuEdges = readonly (readonly [number, number])[] | Int32Array | Uint32Array
/**
* What a load writes, and how much of it.
*/
export interface ZuLoadOptions {
/** The node table, which gets a row per element of every column. */
readonly nodes: string
/** The rel table holding the edges between those rows. `rel` by default. */
readonly rels?: string
/** The node table's properties, as column name to values. */
readonly columns?: Readonly<Record<string, ZuFrameColumn>>
/** The edges, as pairs of row numbers. */
readonly edges?: ZuEdges | null
/**
* How many rows the node table has.
*
* Read off the columns when there are any, so this is for the load
* that writes a graph with no properties at all, and a check on the
* columns when both are given.
*/
readonly rows?: number
}
/**
* What went into a load.
*/
export interface ZuLoadStats {
readonly nodes: number
readonly rels: number
readonly columns: number
}
/**
* A walk through the graph: nodes and edges, alternating, a node at
* each end.
*
* The two lists are kept apart rather than interleaved, because the
* question a caller asks is almost always about one of them. A path of
* one node has no edges and is the shortest there is.
*/
export interface ZuPath {
readonly nodes: ZuNode[]
readonly rels: ZuRel[]
}
/**
* Something the engine wants to say about a statement that ran anyway.
*
* A notice is a completion condition of its own, so it carries a
* GQLSTATUS the same way a failure does. The one raised today is
* `01G11`, which says an aggregate ignored a null.
*/
export interface ZuNotice {
readonly code: string
readonly condition: string
readonly message: string
readonly docUrl: string
}
/**
* What a column of a columnar read turned out to hold.
*
* Narrower than the type the statement declared, because the question
* here is which buffer arrived: a time with an offset and a time
* without are the same 64 bit cells, and the offset rides beside as
* `zone`. `value` is the fallback for what no fixed width cell covers,
* which is nodes, rels, paths, lists and records, and `null` is a
* column that held nothing else.
*
* `bytes` arrives in the two buffers `string` arrives in and is not
* one: the bytes are octets and a reader that decoded them as text
* would be handed something it cannot decode, which is why the two
* have separate names for one layout.
*
* This is what arrived rather than what the statement declared, and the
* two differ for the temporal types today. The engine's columnar sink
* has no buffer for days, nanoseconds or months, so a date, a time or a
* duration sometimes comes over as the values themselves, and which of
* the two a statement gets is the plan's business rather than the
* caller's. Such a column is `value` with its `ZuDate` and `ZuDuration`
* objects in `items`, not `date` with an empty `values`, so that a
* switch on `type` always lands on a field that holds something.
*/
export type ZuColumnType =
| 'null'
| 'bool'
| 'int'
| 'float'
| 'string'
| 'bytes'
| 'date'
| 'time'
| 'datetime'
| 'duration'
| 'value'
/**
* One column of a result, as the buffer holding it.
*
* Every field is present on every column and holds null where it does
* not apply, so reading one is a switch on `type` rather than a series
* of tests for what is there. Which field carries the values follows
* from the type: `values` for everything of a fixed width, `data` and
* `offsets` for strings and byte strings, `items` for what no buffer
* covers, and none of them for a column of nulls.
*
* The buffers are the engine's own, handed over rather than copied, and
* they are laid out the way Arrow lays them out: values end to end, a
* boolean as one bit a row, a string column as its bytes and `length +
* 1` offsets into them, where row `i` spans `offsets[i]` to `offsets[i
* + 1]`.
*/
export interface ZuColumn {
readonly name: string
readonly type: ZuColumnType
readonly length: number
/**
* The cells, for a column of a fixed width: `BigInt64Array` for
* integers, nanoseconds and months, `Float64Array` for floats,
* `Int32Array` for days, and a `Uint8Array` of packed bits for
* booleans, least significant bit first.
*/
readonly values: BigInt64Array | Float64Array | Int32Array | Uint8Array | null
/**
* The bytes of every value end to end, for a `string` or a `bytes`
* column.
*/
readonly data: Uint8Array | null
/**
* `length + 1` offsets into `data`, for a `string` or a `bytes`
* column. Narrow until the bytes pass what a 32 bit offset
* addresses, which is the difference Arrow calls Utf8 against
* LargeUtf8.
*/
readonly offsets: Int32Array | BigInt64Array | null
/** The values themselves, for a column of type `value`. */
readonly items: ZuValue[] | null
/**
* One bit a row, least significant bit first, set meaning the row has
* a value. Null when every row has one, which is the common case and
* the one where a reader gets to skip the test.
*/
readonly validity: Uint8Array | null
/** How many rows are null, which is zero when `validity` is null. */
readonly nulls: number
/**
* What one cell counts: `days`, `nanos` or `months`. Null where there
* are no cells to count, which includes a temporal column that
* arrived as a `value` column.
*/
readonly unit: 'days' | 'nanos' | 'months' | null
/** Minutes east of UTC, for a column of zoned times or datetimes. */
readonly zone: number | null
}
/**
* A whole result read down its columns.
*
* `rows` is every column's length, and is the answer for a statement
* that projected nothing at all. `gqlstatus` and `notices` are the
* statement's, exactly as they are on the rows.
*/
export interface ZuColumnar {
readonly rows: number
readonly columns: ZuColumn[]
readonly gqlstatus: string
readonly notices: ZuNotice[]
}
/**
* A whole result as Arrow, in the bytes Arrow ships between processes.
*
* The same buffers a columnar read hands over, with the schema written
* beside them, so `tableFromIPC(read.ipc)` is the whole of the reading
* code and every Arrow implementation is a reader. A result with no rows
* is a schema and one empty batch rather than nothing at all, so the
* columns are known either way.
*/
export interface ZuArrow {
/**
* The stream, as one buffer: a schema message and then a message a
* batch. It is the addon's own allocation handed over rather than
* copied, and it detaches when posted to a worker, which is what makes
* a result cross a thread without being cloned.
*/
readonly ipc: Uint8Array
/** How many rows are in it, which the batches also add up to. */
readonly rows: number
readonly gqlstatus: string
readonly notices: ZuNotice[]
}
/**
* What a statement read as Arrow takes beside its parameters.
*/
export interface ZuArrowOptions extends ZuStatementOptions {
/**
* How many rows one record batch holds. Arrow's own 65,536 by
* default, which is what a reader expects and what keeps a batch
* inside a cache.
*
* The arrays are built whole either way and a batch is a slice of
* them, so this costs nothing to change and buys nothing to tune. It
* is worth naming when the reader on the other side has a size of its
* own, or when the batches are going somewhere one at a time.
*/
readonly batchRows?: number
}
/**
* The rows a statement gave back.
*
* An array, so iterating it is `for (const row of rows)` and nothing
* else. What a wrapper object would have carried is carried as
* properties beside the elements: `columns` for the projection in the
* order it was written, `gqlstatus` for the condition the statement
* completed with, and `notices` for what it wanted to say on the way.
*/
export interface ZuRows<Row = Record<string, ZuValue>> extends Array<Row> {
readonly columns: string[]
readonly gqlstatus: string
readonly notices: ZuNotice[]
}
/**
* One batch of a streamed result.
*
* The rows of a whole result with the same array trick and one fewer
* property: `columns` is the statement's projection and is the same on
* every batch of one stream, and what a statement completed with is not
* known until it has, so it is on the summary rather than here.
*/
export interface ZuBatch<Row = Record<string, ZuValue>> extends Array<Row> {
readonly columns: string[]
}
/**
* What a streamed statement did, known once it has ended.
*
* The rows are gone by then, which is the point of streaming, so this
* is what is worth keeping about a result nobody held: what it
* projected, how much of it was read, whether the reader stopped it
* early, and what the engine wanted to say along the way.
*/
export interface ZuSummary {
readonly columns: string[]
/** How many rows were handed over, which is fewer than the statement
* would have returned when the reader stopped early. */
readonly rows: number
readonly stopped: boolean
/**
* Whether the rows arrived as they were made, rather than the
* statement running whole and being handed over in batches
* afterwards. A statement that has to see every row before it can
* give one, which is `ORDER BY`, `DISTINCT`, the aggregates and
* anything that writes, is the second kind, and so is a plan the
* pipeline executor does not take. The loop over it reads the same
* either way, so this is here for a caller measuring where the time
* went rather than for one deciding what to do next.
*/
readonly streamed: boolean
readonly notices: ZuNotice[]
}
/**
* One operator of a plan, and everything under it.
*
* The tree runs the way the rows do: a parent pulls from its children,
* so the leaves are the scans and the root is whatever the statement
* ends with.
*/
export interface ZuPlanNode {
/** The operator: `Scan`, `Expand`, `Filter`, `Project` and the rest. */
readonly op: string
/**
* What the listing calls it, which is `op` with the bracket in front
* of it where there is one, so an OPTIONAL MATCH expand is an
* `Expand` named `OptionalExpand`.
*/
readonly name: string
/** The bracket this operator is inside, and null for a plain match. */
readonly bracket: 'Optional' | 'Semi' | 'Anti' | 'Mark' | null
/**
* What it is working on, written the way the statement wrote it: the
* tables a scan reads, the pattern an expand walks, the predicate a
* filter asks. Empty where the operator has nothing to name.
*/
readonly detail: string
/** The variables it introduces, in the order it binds them. */
readonly binds: string[]
/**
* The tables it touches: node tables for a scan, rel tables for an
* expand, both for an insert, and none anywhere else.
*/
readonly tables: string[]
readonly children: ZuPlanNode[]
}
/**
* A query written where a value belongs, planned on its own.
*
* `reads` is what it reads from the query around it, and empty is the
* whole test for whether it runs once: a subquery that reads nothing
* answers the same value for every row, and one that reads a name runs
* per row. `exists` is true where what was written around it asks only
* whether it answered a row.
*/
export interface ZuScalarPlan {
readonly reads: string[]
readonly exists: boolean
readonly plan: ZuPlan
}
/**
* What a statement would do, without doing it.
*
* A tree and a rendering of it. `text` is what the engine prints, so a
* listing logged from Node is the listing the shell shows, and the tree
* is for the questions a program asks: which tables were touched, how
* deep the expands go, whether the scan reached an index.
*/
export interface ZuPlan {
/**
* The top operator, and null for the plan with no operators at all,
* which is the one row a statement with no clauses runs over.
*/
readonly root: ZuPlanNode | null
/** The columns the statement answers with, in the order it wrote them. */
readonly columns: string[]
/** The parameters it wants, without the `$` they are written with. */
readonly params: string[]
/** What compiling it raised, which is empty for most statements. */
readonly notes: string[]
readonly scalars: ZuScalarPlan[]
/** The listing, indented, as `EXPLAIN` prints it. */
readonly text: string
}
/**
* One operator of a profiled run, and what the counters saw of it.
*/
export interface ZuOp {
readonly op: string
readonly detail: string
/** How many chunks it produced. */
readonly pulls: number
/** Values produced across every pull. Over `pulls` that is the
* average vector length, which is the factorization statistic. */
readonly rows: number
/**
* The rows those values stand for with the factorization multiplied
* out. On a chain it is `rows`, and on a star it is the product over
* every vector still unflat beside this one, which is the count the
* optimizer was estimating.
*/
readonly flat: number
/**
* What the optimizer expected, and null for the operators that pass
* their input through rather than producing rows of their own.
*/
readonly estimate: number | null
/** The most rows the optimizer's ceiling allowed, where the
* statistics were there to set one. */
readonly bound: number | null
/** Self time in nanoseconds, with the children's excluded. */
readonly nanos: number
/**
* How wrong the estimate was: `max(estimate/rows, rows/estimate)`,
* both floored at one row. An operator the optimizer got right is 1,
* and null wherever `estimate` is.
*/
readonly qerror: number | null
}
/**
* One stage of a profiled run: the operators bottom-up and the sink
* that took their rows.
*/
export interface ZuStage {
readonly sink: string
/** How many rows the sink was handed. */
readonly rows: number
/** Wall time of the whole stage in nanoseconds, sink included. */
readonly nanos: number
readonly ops: ZuOp[]
}
/**
* What a statement did, with the counters on.
*
* The rows are not here: a profile is about the run rather than the
* answer, and keeping both would make the measurement pay for the thing
* it is measuring. `text` is the listing `EXPLAIN ANALYZE` prints.
*/
export interface ZuProfile {
readonly stages: ZuStage[]
/** Every stage end to end, in nanoseconds. */
readonly nanos: number
readonly text: string
}
/**
* What a watch on a running statement takes.
*/
export interface ZuProgressOptions {
/**
* How long to wait between looks, in milliseconds. A tenth of a
* second by default, which is about where a person stops reading a
* number and starts seeing it move.
*
* What one look costs is an atomic read, so this is a question about
* how often the callback should run rather than about how much the
* watch costs the statement.
*/
readonly everyMs?: number
}
/**
* A watch on a running statement, which is stopped by `stop()` or by
* leaving the scope of a `using`.
*
* Stopping twice does nothing, and so does stopping one that has
* already been left behind.
*/
export interface ZuProgress extends Disposable {
/** Stops the watch. The callback is not called again. */
stop(): void
}
/**
* What a streamed statement takes beside its parameters.
*/
export interface ZuStreamOptions extends ZuStatementOptions {
/**
* How many rows a batch may hold. The engine's own vector by
* default, which is the unit it already works in and the one that
* costs nothing to hand over. Name a size when the rows are going
* somewhere with a size of its own, an Arrow record batch or an
* HTTP chunk.
*
* A ceiling and not a promise: batches are cut out of rows that have
* already been made, so the last piece of a run of them is whatever
* was left, and a size above the engine's vector gets the vector. It
* is what bounds how much a reader holds at once, which is the
* question a caller is asking when they name one.
*/
readonly batchRows?: number
}
/**
* How INT64 is spelled on the way out.
*
* `bigint` is the default and is the only one of the two that is always
* right, because zu's integers go to 2^63 and a JavaScript number stops
* telling one integer from the next at 2^53.
*
* `number` is for the program that has already decided its integers are
* small: ids that count in millions, a `count(*)` over a table that
* will never be one, a row about to be handed to `JSON.stringify`,
* which cannot serialize a `bigint` at all. It is worth knowing exactly
* what is being traded for that. Which integers a database holds is a
* property of the data and not of the program, so a query that returned
* numbers for every row of a test database is a query that can meet a
* larger one in production. This client refuses that row rather than
* rounding it, with a `ZuUsageError` naming the column and the value,
* so the failure is loud and local rather than an answer that is quietly
* off by one. It is still a failure that arrives at read time, on a
* machine that is not yours, which is why the default is the other one.
*
* The mode reaches the INT64 columns of a result and nothing else. A
* node's `offset`, an edge's `src`, `dst` and `ord`, and the nanosecond
* counts of the temporal classes stay `bigint` in both modes, because
* they are properties of classes the addon registers once and not
* values a statement can respell.
*/
export type ZuBigIntMode = 'bigint' | 'number'
/**
* What a statement takes beside its parameters.
*
* An object rather than a bare signal, because the options that follow
* it belong in the same place and a third argument that changes meaning
* is one nobody can read at a call site.
*/
export interface ZuStatementOptions {
/**
* How INT64 comes back from this statement. `bigint` unless the
* connection was opened with the other mode, and either way a
* statement may name the one it wants.
*/
readonly bigIntMode?: ZuBigIntMode
/**
* Stops the statement when it fires, through the same interrupt a
* shell answers `Ctrl-C` with: the executor notices at the boundary it
* was already stopping at, the statement ends, and the connection is
* exactly as it was. The promise rejects with whatever the signal
* gives as its reason, which is what `fetch` does, so
* `AbortSignal.timeout(50)` rejects with a `TimeoutError` and
* `controller.abort(new MyError())` rejects with `MyError`.
*
* A signal that has already fired stops the statement before the
* engine sees it at all.
*/
readonly signal?: AbortSignal
}
/**
* What a transaction takes when it starts.
*/
export interface ZuTransactionOptions {
/**
* Starts it `READ ONLY`, which the engine refuses a write inside of
* at the statement that writes rather than at this call.
*
* Worth asking for on a span that only reads, because saying so is
* how a statement that was not meant to write is stopped by the
* database rather than by review.
*/
readonly readOnly?: boolean
}
/**
* What a failed call throws.
*
* An ordinary `Error`, so every `catch`, logger and unhandled rejection
* handler already knows what to do with it. What makes it a zu error is
* the fields, and none of them has to be parsed back out of the
* message: `code` picks the branch, `line` and `column` underline the
* token, `retryable` decides whether a retry loop goes round again.
*/
export interface ZuError extends Error {
/**
* The condition's class, written out: `ZuSyntaxError`,
* `ZuDataError`, `ZuTransactionError`, `ZuConnectionError`,
* `ZuInterrupted`, `ZuUsageError`, `ZuInternalError`, or `ZuError`
* for a condition in a class none of those name.
*/
readonly name: string
/** Whether running the same statement again could succeed. */
readonly retryable: boolean
/**
* The GQLSTATUS, five characters. Absent on a mistake this client
* caught before the engine saw it, which is why a caller mapping
* codes to branches has to tell a missing one from an unknown one.
*/
readonly code?: string
/** The standard's own words for that code. */
readonly condition?: string
readonly severity?: 'success' | 'noData' | 'warning' | 'informational' | 'exception'
readonly docUrl?: string
/** Where in the statement, for a condition that happened somewhere. */
readonly line?: number
readonly column?: number
readonly offset?: number
/** The whole line `column` indexes into, for underlining it. */
readonly excerpt?: string
}
/**
* Rows on their way into a table, buffered until they are flushed.
*
* Take one with `Connection.appender`, append rows to it, and close
* it. What is buffered is columnar and typed from the table's own
* columns, read when the appender opened, so a value that does not
* belong in a column is refused by the call that appended it rather
* than at the flush that would have carried it, and the message names
* the column it did not fit.
*/
export declare class Appender {
/** The table these rows are going into. */
get table(): string
/** Rows buffered and not yet written. */
get buffered(): number
/** Rows this appender has committed, across every flush. */
get committed(): number
/** Whether this appender has been closed. */
get closed(): boolean
/**
* Appends one row, which is one value per column of the table, in
* the order the table declares them.
*
* Synchronous, and the only synchronous call in this client: the
* values go into memory and nothing else happens, so this is a
* conversion and a push per column. Being synchronous it throws
* rather than rejecting, with the same `ZuUsageError` every other
* refusal here carries.
*
* A row of the wrong width, or with a value that does not fit the
* column, is refused with nothing of it kept, so the appender is
* still usable once the caller has fixed the row.
*/
appendRow(row: readonly ZuAppendValue[]): void
/**
* Appends every row of an array of rows.
*
* The same thing in a loop, and worth a call of its own because it
* is one check and one lock for the batch rather than one per row.
* A row that is refused stops the call where it was refused and the
* rows before it stay buffered: nothing here is a transaction until
* the flush, and throwing away work the caller can keep would not
* make it one. What it answers is how many rows went in, which is
* where a caller who caught the refusal starts again.
*/
appendRows(rows: readonly (readonly ZuAppendValue[])[]): number
/**
* Writes every buffered row and makes it readable, and answers how
* many rows this appender has committed in all.
*
* One commit, whatever the buffer holds: the values are sealed into
* the file, one frame naming them is synced to the log, and the
* fold that follows puts them where every query looks. On return
* the buffer is empty and the rows are there. A flush with nothing
* buffered touches no file, so a loader can flush on a timer
* without writing empty commits.
*
* A flush that fails keeps its rows, so that what did not go in is
* still there to be looked at and tried again.
*/
flush(): Promise<number>
/**
* Flushes what is left and answers how many rows this appender
* committed in all.
*
* Closing twice is not an error and writes nothing the second
* time, because an `await using` that closed early would otherwise
* fail on the way out.
*/
close(): Promise<number>
/**
* The close `await using` calls, which is the intended way to
* scope an appender.
*
* It flushes, whether the block ended well or badly, which is the
* opposite of what the disposal of a transaction here does and is
* the same answer the Python client gives. The two differ because
* the question differs: a transaction that leaves its scope
* unfinished is a unit of work nobody completed, and a buffer that
* leaves its scope unwritten is a loader that read a million rows
* and threw them away. A caller who wants the rows gone writes
* `discard()` and gets exactly that.
*
* It is also reachable as `Symbol.asyncDispose`, which is what
* `await using` actually looks for and which [`wire_disposal`] puts
* on every appender as it is made.
*/
dispose(): Promise<number>
/**
* Throws away what is buffered and answers how many rows that was.
*
* The way out of a load that went wrong halfway. A caller who has
* noticed that the rows are wrong wants them gone, and closing
* would write them. Rows an earlier flush committed are committed,
* and this does not reach them.
*/
discard(): number
}
/**
* One connection to one database.
*
* Statements run on it in order, one at a time. It reads the database
* as of when it was opened, which is why a program that wants to see
* another writer's work takes a new connection rather than waiting on
* this one.
*/
export declare class Connection {
/** Where the database this is connected to lives. */
get path(): string
/** Whether this connection refuses every statement that writes. */
get readOnly(): boolean
/**
* Whether the database behind it is in memory rather than on
* disk, in which case nothing survives the last connection to it.
*/
get memory(): boolean
/** Whether the connection is still open. */
get open(): boolean
/**
* Whether an explicit transaction is running on this connection.
*
* True inside a `transaction()` and true after a `START
* TRANSACTION` written by hand, because it is asked of the session
* rather than counted here. A statement written on its own runs in
* a transaction of its own and this stays false for it: what it
* answers is whether a span is open, not whether anything is
* atomic.
*/
get inTransaction(): boolean
/**
* How many rows the statement running on this connection has read
* out of storage, for showing a person that something is
* happening.
*
* Rows read rather than rows answered, because the statement
* somebody is waiting on is exactly the one that reads a hundred
* million rows to answer one. It starts at zero at each statement
* and holds its last value once one ends.
*
* This is the one thing on a connection that is worth reading
* while a statement runs, and it is answered the way
* [`Connection::open`] is: an atomic beside the lock rather than a
* question through it. So the loop's thread gets its answer while
* the threadpool thread is still scanning, and `progress()` is the
* timer written around it.
*
* A number rather than a bigint, like every other count this
* client makes rather than reads out of a column: a statement that
* had read 2^53 rows would have been running for weeks.
*/
get rowsRead(): number
/**
* Starts a transaction and hands it back.
*
* It starts here rather than at the first statement inside it, so a
* transaction that cannot start says so at the line that asked. A
* connection is inside one transaction at a time and asking for a
* second while one is open is refused by the engine rather than
* nested, because a transaction inside a transaction is a promise
* this database does not make.
*
* ```js
* await using tx = await conn.transaction()
* await conn.exec('INSERT (a:account {uid: 1, balance: 100})')
* await conn.exec('INSERT (b:account {uid: 2, balance: 0})')
* await tx.commit()
* ```
*
* The `await using` is the rollback nobody remembers to write. It
* undoes the transaction unless the block committed it, which is
* the opposite of what Python's `with` block does here and is the
* only honest reading in JavaScript: a disposal is not told whether
* the scope it is leaving threw, so a disposal that committed would
* commit half of the work of a block that failed.
*/
transaction(options?: ZuTransactionOptions | null): Promise<Transaction>
/**
* Opens an appender on `table` and hands it back.
*
* The bulk-load path. A load written as statements pays a commit
* per row, and an appender pays one per flush, which is the whole
* difference between loading a million rows in an afternoon and
* loading them in a minute.