@vuu-ui/vuu-data-test 5.0.0-alpha.3 → 5.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "5.0.0-alpha.3",
2
+ "version": "5.0.0-alpha.5",
3
3
  "main": "./src/index.js",
4
4
  "type": "module",
5
5
  "author": "heswell",
@@ -9,16 +9,16 @@
9
9
  "type-defs": "node ../../scripts/build-type-defs.mjs"
10
10
  },
11
11
  "dependencies": {
12
- "@vuu-ui/vuu-data-local": "5.0.0-alpha.3",
13
- "@vuu-ui/vuu-utils": "5.0.0-alpha.3",
12
+ "@vuu-ui/vuu-data-local": "5.0.0-alpha.5",
13
+ "@vuu-ui/vuu-utils": "5.0.0-alpha.5",
14
14
  "@heswell/module-admin": "1.1.0",
15
15
  "@heswell/user-admin": "1.0.1",
16
- "@vuu-ui/vuu-data-editing": "5.0.0-alpha.3"
16
+ "@vuu-ui/vuu-data-editing": "5.0.0-alpha.5"
17
17
  },
18
18
  "devDependencies": {
19
- "@vuu-ui/vuu-protocol-types": "5.0.0-alpha.3",
20
- "@vuu-ui/vuu-data-types": "5.0.0-alpha.3",
21
- "@vuu-ui/vuu-table-types": "5.0.0-alpha.3"
19
+ "@vuu-ui/vuu-protocol-types": "5.0.0-alpha.5",
20
+ "@vuu-ui/vuu-data-types": "5.0.0-alpha.5",
21
+ "@vuu-ui/vuu-table-types": "5.0.0-alpha.5"
22
22
  },
23
23
  "sideEffects": false,
24
24
  "files": [
@@ -32,6 +32,7 @@ class VuuModule {
32
32
  async beforeSessionSave(_sourceTable, _sessionTable) {}
33
33
  async afterSessionSave(_sourceTable, _sessionTable) {}
34
34
  permissionFunctions;
35
+ validateEdit(_tableName, _column, _value) {}
35
36
  getTableSchema(tableName) {
36
37
  return this.schemas[tableName] ?? this.#sessionTableMap[tableName]?.schema;
37
38
  }
@@ -337,14 +338,20 @@ class VuuModule {
337
338
  const { column, data, key } = rpcRequest.params;
338
339
  const sessionTable = this.#sessionTableMap[viewPortId];
339
340
  let targetTable = sessionTable;
341
+ let sourceTableName = this.#sessionSourceTableMap[viewPortId];
340
342
  if (!targetTable) {
341
343
  const { dataSource } = this.getSubscriptionByViewport(viewPortId);
342
- if (dataSource.table) targetTable = this.tables[dataSource.table.table];
344
+ if (dataSource.table) {
345
+ sourceTableName = dataSource.table.table;
346
+ targetTable = this.tables[sourceTableName];
347
+ }
343
348
  }
344
349
  if (targetTable) try {
345
350
  const sessionRow = sessionTable?.findByKey(key);
346
351
  if (sessionRow?.[sessionTable.map.vuuAction] === "deleteRow") throw Error("editCell: cannot edit a deleted row");
347
352
  assertUpdateIsValid(targetTable.schema, column, data);
353
+ const validationError = void 0 === sourceTableName ? void 0 : this.validateEdit(sourceTableName, column, data);
354
+ if (void 0 !== validationError) throw Error(validationError);
348
355
  targetTable.update(key, column, data);
349
356
  if (sessionTable && sessionTable.findByKey(key)?.[sessionTable.map.vuuAction] !== "addRow") sessionTable.update(key, "vuuAction", "editCell");
350
357
  return {
@@ -492,6 +499,14 @@ class VuuModule {
492
499
  errorMessage: `addRow: no active session table for viewport ${viewPortId}`
493
500
  };
494
501
  const { data, key } = rpcRequest.params;
502
+ const sourceTableName = this.#sessionSourceTableMap[sessionTableName];
503
+ if (void 0 !== sourceTableName) for (const [column, value] of Object.entries(data)){
504
+ const validationError = this.validateEdit(sourceTableName, column, value);
505
+ if (void 0 !== validationError) return {
506
+ type: "ERROR_RESULT",
507
+ errorMessage: validationError
508
+ };
509
+ }
495
510
  const keyColumn = sessionTable.schema.key;
496
511
  const rowKey = data[keyColumn] ?? key ?? uuid();
497
512
  const rowData = {
@@ -29,6 +29,10 @@ const nextClosePrice = scaledDecimalColumn(4, 4, 0, 5000);
29
29
  const nextFxRate = scaledDecimalColumn(6, 6, 0.5, 2);
30
30
  const nextWeight = scaledDecimalColumn(8, 8, 0, 0.05);
31
31
  const nextRandom = createRandom(1);
32
+ const FIRST_TRADE_ID = 4000000000000;
33
+ const nextTradeIdGap = createRandom(3);
34
+ let tradeId = FIRST_TRADE_ID;
35
+ const nextTradeId = ()=>tradeId += randomInt(nextTradeIdGap, 1, 1000);
32
36
  const ONE_DAY = 86400000;
33
37
  const today = new Date();
34
38
  today.setHours(0, 0, 0, 0);
@@ -47,6 +51,7 @@ const instrumentsExtendedData = instrumentsData.map((instrument, rowIndex)=>{
47
51
  supported: nextRandom() < 0.5,
48
52
  wishlist: nextRandom() < 0.5,
49
53
  lastUpdated: instrument[InstrumentColumnMap.vuuUpdatedTimestamp],
54
+ tradeId: nextTradeId(),
50
55
  price: Math.round(100000 * nextRandom()) / 100,
51
56
  notional: nextNotional(rowIndex),
52
57
  closePrice: nextClosePrice(rowIndex),
@@ -89,6 +89,10 @@ const schemas = {
89
89
  name: "lastUpdated",
90
90
  serverDataType: "long"
91
91
  },
92
+ {
93
+ name: "tradeId",
94
+ serverDataType: "long"
95
+ },
92
96
  {
93
97
  name: "price",
94
98
  serverDataType: "double"
@@ -13,6 +13,48 @@ const generateRows = (tableSchema, count)=>{
13
13
  const columnGenerator = RowGenerator(tableSchema.columns.map((c)=>c.name));
14
14
  return new Array(count).fill(1).map((_, i)=>columnGenerator(i));
15
15
  };
16
+ const CHART_VARIANT_MAX_SERIES = 50;
17
+ const CHART_VARIANT_PREFIXES = Array.from({
18
+ length: CHART_VARIANT_MAX_SERIES
19
+ }, (_, i)=>`series_${String(i + 1).padStart(2, "0")}`);
20
+ const CHART_VARIANT_SUFFIXES = [
21
+ "set_a",
22
+ "set_b",
23
+ "set_c"
24
+ ];
25
+ const chartVariantColumns = [
26
+ {
27
+ name: "id",
28
+ serverDataType: "string"
29
+ },
30
+ {
31
+ name: "date",
32
+ serverDataType: "string"
33
+ },
34
+ ...CHART_VARIANT_PREFIXES.flatMap((prefix)=>CHART_VARIANT_SUFFIXES.map((suffix)=>({
35
+ name: `${prefix}_${suffix}`,
36
+ serverDataType: "double"
37
+ })))
38
+ ];
39
+ const chartVariantScale = [
40
+ 1,
41
+ 0.6,
42
+ 0.3
43
+ ];
44
+ const chartVariantRows = ()=>Array.from({
45
+ length: 25
46
+ }, (_, day)=>{
47
+ const date = new Date(Date.UTC(2026, 3, 2 + day)).toISOString().slice(0, 10);
48
+ const values = CHART_VARIANT_PREFIXES.flatMap((_, p)=>{
49
+ const base = 100 + 20 * p + Math.round(15 * Math.sin((day + 3 * p) / 4));
50
+ return chartVariantScale.map((scale)=>Math.round(base * scale));
51
+ });
52
+ return [
53
+ String(day + 1).padStart(3, "0"),
54
+ date,
55
+ ...values
56
+ ];
57
+ });
16
58
  const testEditColumns = [
17
59
  {
18
60
  name: "id",
@@ -39,6 +81,17 @@ const testEditColumns = [
39
81
  serverDataType: "long"
40
82
  }
41
83
  ];
84
+ const TEST_EDIT_VALIDATION_QUANTITY_MESSAGE = "quantity must be between 1 and 1000";
85
+ const TEST_EDIT_VALIDATION_PRICE_MESSAGE = "price must be greater than zero";
86
+ const validateTestEditValidation = (column, value)=>{
87
+ if ("quantity" === column) {
88
+ const quantity = Number(value);
89
+ if (!Number.isInteger(quantity) || quantity < 1 || quantity > 1000) return TEST_EDIT_VALIDATION_QUANTITY_MESSAGE;
90
+ } else if ("price" === column) {
91
+ const price = Number(value);
92
+ if (!(price > 0)) return TEST_EDIT_VALIDATION_PRICE_MESSAGE;
93
+ }
94
+ };
42
95
  class TestModule extends VuuModule {
43
96
  #schemas = {
44
97
  TestDates: {
@@ -153,6 +206,15 @@ class TestModule extends VuuModule {
153
206
  table: "ChartTable"
154
207
  }
155
208
  },
209
+ ChartVariantTable: {
210
+ columns: chartVariantColumns,
211
+ key: "id",
212
+ rangeLimits: DEFAULT_RANGE_LIMITS,
213
+ table: {
214
+ module: "TEST",
215
+ table: "ChartVariantTable"
216
+ }
217
+ },
156
218
  MaxScrollEndTable: {
157
219
  columns: DefaultColumnGenerator(6).map((col)=>toSchemaColumn({
158
220
  ...col,
@@ -185,6 +247,15 @@ class TestModule extends VuuModule {
185
247
  module: "TEST",
186
248
  table: "TestEdit"
187
249
  }
250
+ },
251
+ TestEditValidation: {
252
+ columns: testEditColumns,
253
+ key: "id",
254
+ rangeLimits: DEFAULT_RANGE_LIMITS,
255
+ table: {
256
+ module: "TEST",
257
+ table: "TestEditValidation"
258
+ }
188
259
  }
189
260
  };
190
261
  #tables = {
@@ -509,6 +580,7 @@ class TestModule extends VuuModule {
509
580
  false
510
581
  ]
511
582
  ], buildDataColumnMap(this.#schemas, "ChartTable")),
583
+ ChartVariantTable: TableContainer.createTable(this.#schemas.ChartVariantTable, chartVariantRows(), buildDataColumnMap(this.#schemas, "ChartVariantTable")),
512
584
  MaxScrollEndTable: TableContainer.createTable(this.#schemas.MaxScrollEndTable, generateRows(this.#schemas.MaxScrollEndTable, 1000), buildDataColumnMap(this.#schemas, "MaxScrollEndTable")),
513
585
  TestEditEmpty: TableContainer.createTable(this.#schemas.TestEditEmpty, [], buildDataColumnMap(this.#schemas, "TestEditEmpty")),
514
586
  TestEdit: TableContainer.createTable(this.#schemas.TestEdit, [
@@ -562,7 +634,49 @@ class TestModule extends VuuModule {
562
634
  withNanoMs(Date.now(), 5),
563
635
  1000000000000000005n
564
636
  ]
565
- ], buildDataColumnMap(this.#schemas, "TestEdit"))
637
+ ], buildDataColumnMap(this.#schemas, "TestEdit")),
638
+ TestEditValidation: TableContainer.createTable(this.#schemas.TestEditValidation, [
639
+ [
640
+ "VAL-001",
641
+ "Alpha",
642
+ 12,
643
+ 101.25,
644
+ true,
645
+ 1001
646
+ ],
647
+ [
648
+ "VAL-002",
649
+ "Bravo",
650
+ 24,
651
+ 202.5,
652
+ false,
653
+ 1002
654
+ ],
655
+ [
656
+ "VAL-003",
657
+ "Charlie",
658
+ 36,
659
+ 303.75,
660
+ true,
661
+ 1003
662
+ ],
663
+ [
664
+ "VAL-004",
665
+ "Delta",
666
+ 48,
667
+ 405,
668
+ true,
669
+ 1004
670
+ ],
671
+ [
672
+ "VAL-005",
673
+ "Echo",
674
+ 60,
675
+ 506.25,
676
+ false,
677
+ 1005
678
+ ]
679
+ ], buildDataColumnMap(this.#schemas, "TestEditValidation"))
566
680
  };
567
681
  constructor(){
568
682
  super("TEST");
@@ -577,6 +691,9 @@ class TestModule extends VuuModule {
577
691
  return this.#tables;
578
692
  }
579
693
  get visualLinks() {}
694
+ validateEdit(tableName, column, value) {
695
+ return "TestEditValidation" === tableName ? validateTestEditValidation(column, value) : void 0;
696
+ }
580
697
  }
581
698
  const testModule = new TestModule();
582
- export { testModule };
699
+ export { CHART_VARIANT_MAX_SERIES, CHART_VARIANT_PREFIXES, CHART_VARIANT_SUFFIXES, TEST_EDIT_VALIDATION_PRICE_MESSAGE, TEST_EDIT_VALIDATION_QUANTITY_MESSAGE, testModule };
@@ -1,5 +1,5 @@
1
1
  import type { DataSourceBase, DataSourceConfig, DataSourceRowWithBigint, DataSourceSubscribedMessage, DataSourceVisualLinkCreatedMessage, EditSessionMode, CopyOption, SessionDataSourceOverrides, SessionType, TableSchema } from "@vuu-ui/vuu-data-types";
2
- import type { VuuMenu, VuuLink, LinkDescriptorWithLabel, VuuRpcMenuResponse, VuuCreateVisualLink, VuuRemoveVisualLink, VuuRpcServiceRequest, RpcResultSuccess, RpcResultError, VuuRpcMenuRequest } from "@vuu-ui/vuu-protocol-types";
2
+ import type { VuuMenu, VuuRowDataItemType, VuuLink, LinkDescriptorWithLabel, VuuRpcMenuResponse, VuuCreateVisualLink, VuuRemoveVisualLink, VuuRpcServiceRequest, RpcResultSuccess, RpcResultError, VuuRpcMenuRequest } from "@vuu-ui/vuu-protocol-types";
3
3
  import { Table } from "../../Table";
4
4
  import { TickingArrayDataSource } from "../../TickingArrayDataSource";
5
5
  import { type PermissionFunction } from "../filter/PermissionFilter";
@@ -59,6 +59,12 @@ export declare abstract class VuuModule<T extends string = string> implements IV
59
59
  * lazily start a data provider.
60
60
  */
61
61
  protected beforeCreateDataSource?(tableName: T): void;
62
+ /**
63
+ * Server-side validation applied to every value submitted by editCell and
64
+ * addRow. `tableName` is the source table, also when the edit targets a
65
+ * session table. Return a message to reject the value, undefined to accept.
66
+ */
67
+ protected validateEdit(_tableName: T, _column: string, _value: VuuRowDataItemType): string | undefined;
62
68
  getTableSchema(tableName: string): Record<T, Readonly<TableSchema>>[T];
63
69
  getTableList(): string[];
64
70
  protected handlePostSubscribeActivities: ({ clientViewportId, tableSchema, }: DataSourceSubscribedMessage) => void;
@@ -1,7 +1,13 @@
1
1
  import { type RpcMenuService, VuuModule } from "../core/module/VuuModule";
2
2
  import { type Table } from "../Table";
3
3
  import type { TableSchema } from "@vuu-ui/vuu-data-types";
4
- export type TestTableName = "TestDates" | "TwoHundredColumns" | "LinkParent" | "LinkChild" | "ChartTable" | "MaxScrollEndTable" | "TestEditEmpty" | "TestEdit";
4
+ import type { VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
5
+ export type TestTableName = "TestDates" | "TwoHundredColumns" | "LinkParent" | "LinkChild" | "ChartTable" | "ChartVariantTable" | "MaxScrollEndTable" | "TestEditEmpty" | "TestEdit" | "TestEditValidation";
6
+ export declare const CHART_VARIANT_MAX_SERIES = 50;
7
+ export declare const CHART_VARIANT_PREFIXES: string[];
8
+ export declare const CHART_VARIANT_SUFFIXES: string[];
9
+ export declare const TEST_EDIT_VALIDATION_QUANTITY_MESSAGE = "quantity must be between 1 and 1000";
10
+ export declare const TEST_EDIT_VALIDATION_PRICE_MESSAGE = "price must be greater than zero";
5
11
  declare class TestModule extends VuuModule<TestTableName> {
6
12
  #private;
7
13
  constructor();
@@ -11,6 +17,7 @@ declare class TestModule extends VuuModule<TestTableName> {
11
17
  get schemas(): Record<TestTableName, TableSchema>;
12
18
  get tables(): Record<TestTableName, Table>;
13
19
  get visualLinks(): undefined;
20
+ protected validateEdit(tableName: TestTableName, column: string, value: VuuRowDataItemType): string | undefined;
14
21
  }
15
22
  export declare const testModule: TestModule;
16
23
  export {};