@rs-x/cli 2.0.0-next.15 → 2.0.0-next.16

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.
@@ -0,0 +1,126 @@
1
+ import {
2
+ createRowData,
3
+ type RowData,
4
+ type SortDirection,
5
+ type SortKey,
6
+ } from '@/lib/row-data';
7
+
8
+ export type VirtualTablePage = {
9
+ total: number;
10
+ items: RowData[];
11
+ };
12
+
13
+ const TOTAL_ROWS = 1_000_000;
14
+ const REQUEST_DELAY_MS = 120;
15
+ const CATEGORY_COUNT = 4;
16
+ const PRICE_BUCKET_COUNT = 1_000;
17
+ const QUANTITY_BUCKET_COUNT = 100;
18
+ const MAX_CACHED_PAGES = 24;
19
+
20
+ export class VirtualTableDataService {
21
+ private readonly pageCache = new Map<string, VirtualTablePage>();
22
+
23
+ public get totalRows(): number {
24
+ return TOTAL_ROWS;
25
+ }
26
+
27
+ public async fetchPage(
28
+ pageIndex: number,
29
+ pageSize: number,
30
+ sortKey: SortKey,
31
+ sortDirection: SortDirection,
32
+ ): Promise<VirtualTablePage> {
33
+ const cacheKey = `${sortKey}:${sortDirection}:${pageIndex}:${pageSize}`;
34
+ const cached = this.pageCache.get(cacheKey);
35
+ if (cached) {
36
+ return cached;
37
+ }
38
+
39
+ await this.delay(REQUEST_DELAY_MS + (pageIndex % 5) * 35);
40
+
41
+ const startIndex = pageIndex * pageSize;
42
+ const items: RowData[] = [];
43
+ const endIndex = Math.min(startIndex + pageSize, TOTAL_ROWS);
44
+
45
+ for (let visualIndex = startIndex; visualIndex < endIndex; visualIndex += 1) {
46
+ const id = this.getIdAtVisualIndex(visualIndex, sortKey, sortDirection);
47
+ items.push(createRowData(id));
48
+ }
49
+
50
+ const page = { total: TOTAL_ROWS, items };
51
+ this.pageCache.set(cacheKey, page);
52
+ this.trimCache();
53
+ return page;
54
+ }
55
+
56
+ private getIdAtVisualIndex(
57
+ visualIndex: number,
58
+ sortKey: SortKey,
59
+ sortDirection: SortDirection,
60
+ ): number {
61
+ const normalizedIndex =
62
+ sortDirection === 'asc' ? visualIndex : TOTAL_ROWS - 1 - visualIndex;
63
+
64
+ if (sortKey === 'price') {
65
+ return this.getPriceSortedId(normalizedIndex);
66
+ }
67
+
68
+ if (sortKey === 'quantity') {
69
+ return this.getQuantitySortedId(normalizedIndex);
70
+ }
71
+
72
+ if (sortKey === 'category') {
73
+ return this.getCategorySortedId(normalizedIndex);
74
+ }
75
+
76
+ return normalizedIndex + 1;
77
+ }
78
+
79
+ private getPriceSortedId(visualIndex: number): number {
80
+ const groupSize = TOTAL_ROWS / PRICE_BUCKET_COUNT;
81
+ const priceBucket = Math.floor(visualIndex / groupSize);
82
+ const offsetInBucket = visualIndex % groupSize;
83
+
84
+ return priceBucket + offsetInBucket * PRICE_BUCKET_COUNT + 1;
85
+ }
86
+
87
+ private getQuantitySortedId(visualIndex: number): number {
88
+ const groupSize = TOTAL_ROWS / QUANTITY_BUCKET_COUNT;
89
+ const quantityBucket = Math.floor(visualIndex / groupSize);
90
+ const offsetInBucket = visualIndex % groupSize;
91
+ const quantityStride = PRICE_BUCKET_COUNT * QUANTITY_BUCKET_COUNT;
92
+ const quantityBlock = Math.floor(offsetInBucket / PRICE_BUCKET_COUNT);
93
+ const priceBucket = offsetInBucket % PRICE_BUCKET_COUNT;
94
+
95
+ return (
96
+ priceBucket +
97
+ quantityBucket * PRICE_BUCKET_COUNT +
98
+ quantityBlock * quantityStride +
99
+ 1
100
+ );
101
+ }
102
+
103
+ private getCategorySortedId(visualIndex: number): number {
104
+ const groupSize = TOTAL_ROWS / CATEGORY_COUNT;
105
+ const categoryBucket = Math.floor(visualIndex / groupSize);
106
+ const offsetInBucket = visualIndex % groupSize;
107
+
108
+ return categoryBucket + offsetInBucket * CATEGORY_COUNT + 1;
109
+ }
110
+
111
+ private delay(durationMs: number): Promise<void> {
112
+ return new Promise((resolve) => {
113
+ window.setTimeout(resolve, durationMs);
114
+ });
115
+ }
116
+
117
+ private trimCache(): void {
118
+ while (this.pageCache.size > MAX_CACHED_PAGES) {
119
+ const oldestKey = this.pageCache.keys().next().value as string | undefined;
120
+ if (!oldestKey) {
121
+ return;
122
+ }
123
+ this.pageCache.delete(oldestKey);
124
+ }
125
+ }
126
+ }