|
2 | 2 | import { SenderOptions } from "../options";
|
3 | 3 | import { SenderBuffer } from "./index";
|
4 | 4 | import { SenderBufferBase } from "./base";
|
| 5 | +import { ArrayPrimitive, getDimensions, validateArray } from "../utils"; |
5 | 6 |
|
| 7 | +const COLUMN_TYPE_DOUBLE: number = 10; |
| 8 | +const COLUMN_TYPE_NULL: number = 33; |
| 9 | + |
| 10 | +const ENTITY_TYPE_ARRAY: number = 14; |
6 | 11 | const ENTITY_TYPE_DOUBLE: number = 16;
|
| 12 | + |
7 | 13 | const EQUALS_SIGN: number = "=".charCodeAt(0);
|
8 | 14 |
|
9 | 15 | /**
|
@@ -37,6 +43,91 @@ class SenderBufferV2 extends SenderBufferBase {
|
37 | 43 | );
|
38 | 44 | return this;
|
39 | 45 | }
|
| 46 | + |
| 47 | + arrayColumn(name: string, value: unknown[]): SenderBuffer { |
| 48 | + const dimensions = getDimensions(value); |
| 49 | + const type = validateArray(value, dimensions); |
| 50 | + // only number arrays and NULL supported for now |
| 51 | + if (type !== "number" && type !== null) { |
| 52 | + throw new Error(`Unsupported array type [type=${type}]`); |
| 53 | + } |
| 54 | + |
| 55 | + this.writeColumn(name, value, () => { |
| 56 | + this.checkCapacity([], 3); |
| 57 | + this.writeByte(EQUALS_SIGN); |
| 58 | + this.writeByte(ENTITY_TYPE_ARRAY); |
| 59 | + |
| 60 | + if (!value) { |
| 61 | + this.writeByte(COLUMN_TYPE_NULL); |
| 62 | + } else { |
| 63 | + this.writeByte(COLUMN_TYPE_DOUBLE); |
| 64 | + this.writeArray(value, dimensions, type); |
| 65 | + } |
| 66 | + }); |
| 67 | + return this; |
| 68 | + } |
| 69 | + |
| 70 | + private writeArray( |
| 71 | + arr: unknown[], |
| 72 | + dimensions: number[], |
| 73 | + type: ArrayPrimitive, |
| 74 | + ) { |
| 75 | + this.checkCapacity([], 1 + dimensions.length * 4); |
| 76 | + this.writeByte(dimensions.length); |
| 77 | + for (let i = 0; i < dimensions.length; i++) { |
| 78 | + this.writeInt(dimensions[i]); |
| 79 | + } |
| 80 | + |
| 81 | + this.checkCapacity([], SenderBufferV2.arraySize(dimensions, type)); |
| 82 | + this.writeArrayValues(arr, dimensions); |
| 83 | + } |
| 84 | + |
| 85 | + private writeArrayValues(arr: unknown[], dimensions: number[]) { |
| 86 | + if (Array.isArray(arr[0])) { |
| 87 | + for (let i = 0; i < arr.length; i++) { |
| 88 | + this.writeArrayValues(arr[i] as unknown[], dimensions); |
| 89 | + } |
| 90 | + } else { |
| 91 | + const type = arr[0] !== undefined ? typeof arr[0] : null; |
| 92 | + switch (type) { |
| 93 | + case "number": |
| 94 | + for (let i = 0; i < arr.length; i++) { |
| 95 | + this.position = this.buffer.writeDoubleLE( |
| 96 | + arr[i] as number, |
| 97 | + this.position, |
| 98 | + ); |
| 99 | + } |
| 100 | + break; |
| 101 | + case null: |
| 102 | + // empty array |
| 103 | + break; |
| 104 | + default: |
| 105 | + throw new Error(`Unsupported array type [type=${type}]`); |
| 106 | + } |
| 107 | + } |
| 108 | + } |
| 109 | + |
| 110 | + private static arraySize(dimensions: number[], type: ArrayPrimitive): number { |
| 111 | + let numOfElements = 1; |
| 112 | + for (let i = 0; i < dimensions.length; i++) { |
| 113 | + numOfElements *= dimensions[i]; |
| 114 | + } |
| 115 | + |
| 116 | + switch (type) { |
| 117 | + case "number": |
| 118 | + return numOfElements * 8; |
| 119 | + case "boolean": |
| 120 | + return numOfElements; |
| 121 | + case "string": |
| 122 | + // in case of string[] capacity check is done separately for each array element |
| 123 | + return 0; |
| 124 | + case null: |
| 125 | + // empty array |
| 126 | + return 0; |
| 127 | + default: |
| 128 | + throw new Error(`Unsupported array type [type=${type}]`); |
| 129 | + } |
| 130 | + } |
40 | 131 | }
|
41 | 132 |
|
42 | 133 | export { SenderBufferV2 };
|
0 commit comments