@rokkit/data 1.0.0-next.98 → 1.0.1

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/README.md CHANGED
@@ -1,50 +1,162 @@
1
1
  # @rokkit/data
2
2
 
3
- This package provides a set of tools for managing and manipulating data in user interfaces. It is framework agnostic and can be used with any ui framework.
3
+ Data manipulation utilities for the Rokkit design system — filtering, joining, schema inference, and dataset views.
4
4
 
5
- ## Features
5
+ ## Install
6
6
 
7
- - **Datasets:** Manage and manipulate datasets with ease
8
- - filtering, sorting, and aggregation.
9
- - **Joins:** Combine datasets effortlessly with support for inner, outer, left, and right joins.
10
- - **Rollup:** Summarize data across multiple dimensions, calculating aggregate statistics like sum, average, min, and max.
11
- - **Modeling:** Create and manage data models, including merging, renaming, and resolving conflicts.
12
- - **Renaming:** Simplify key renaming in JavaScript objects, with options for prefixes, suffixes, and custom separators.
13
- - **Dataviews:** Create interactive views for exploring and analyzing datasets, including sortable and filterable columns.
7
+ ```sh
8
+ npm install @rokkit/data
9
+ # or
10
+ bun add @rokkit/data
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ `@rokkit/data` provides general-purpose data utilities for working with arrays of objects. It is used internally by `@rokkit/ui` table and grid components and can also be used standalone.
16
+
17
+ - **Type inference** — detect column types from data samples
18
+ - **Filtering** — apply single or multiple filters with standard operators
19
+ - **Joins** — relational join operations across two datasets
20
+ - **Dataset / Dataview** — composable dataset abstraction with filter, sort, and pagination
21
+ - **Metadata** — derive column definitions and types from raw data
22
+ - **Renaming** — remap object keys with a rename spec
23
+
24
+ ## Usage
25
+
26
+ ### Type inference
27
+
28
+ ```js
29
+ import { typeOf } from '@rokkit/data'
30
+
31
+ typeOf('hello') // 'string'
32
+ typeOf(42) // 'number'
33
+ typeOf(new Date()) // 'date'
34
+ typeOf([1, 2]) // 'array'
35
+ typeOf({ a: 1 }) // 'object'
36
+ typeOf(true) // 'boolean'
37
+ ```
38
+
39
+ ### Filtering
14
40
 
15
- ## Dataset
41
+ ```js
42
+ import { filterObjectArray, filterData } from '@rokkit/data'
43
+
44
+ // Single filter
45
+ const adults = filterObjectArray(users, {
46
+ column: 'age',
47
+ value: 18,
48
+ operator: 'gte'
49
+ })
50
+
51
+ // Multiple filters combined
52
+ const results = filterData(users, [
53
+ { column: 'status', value: 'active', operator: 'eq' },
54
+ { column: 'age', value: 18, operator: 'gte' }
55
+ ])
56
+ ```
16
57
 
17
- - The `dataset` function initializes a dataset from an array of objects.
18
- - This dataset comprises data rows that are sortable, filterable, and groupable.
19
- - Leverage dataset for SQL-like operations such as selecting, updating, and deleting rows.
20
- - Employ aggregate functions like sum, average, and count for summarizing multiple attributes of the data.
21
- - Utilize the dataset for various data operations like joining and merging data from disparate sources.
22
- - Establish connected data views with joins to visualize data relationships, particularly for tracking parent-child connections.
58
+ Supported operators: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `contains`, `startsWith`, `endsWith`, `in`, `notIn`.
23
59
 
24
- This makes it easier to build a tweenable data structure for animations. Here is an example of how to use the `dataset` to generate a tweenable data:
60
+ ### Joins
25
61
 
26
62
  ```js
27
- function tweenable(data, by, group, template) {
28
- return dataset(data)
29
- .groupBy(by)
30
- .using(template)
31
- .alignBy(...group)
32
- .rollup()
33
- .sortBy(by)
34
- .select()
35
- }
63
+ import { leftJoin, innerJoin } from '@rokkit/data'
64
+
65
+ const result = leftJoin(orders, customers, 'customerId', 'id')
66
+ // Each order row merged with its matching customer row (nulls if unmatched)
36
67
  ```
37
68
 
38
- Refer to [dataset](docs/dataset.md) documentation for more details.
69
+ Available joins: `innerJoin`, `leftJoin`, `rightJoin`, `fullJoin`, `crossJoin`, `antiJoin`, `semiJoin`.
70
+
71
+ ### Schema inference
72
+
73
+ ```js
74
+ import { deriveMetadata, deriveColumns } from '@rokkit/data'
75
+
76
+ const metadata = deriveMetadata(data)
77
+ // [{ column: 'name', type: 'string' }, { column: 'age', type: 'number' }, ...]
78
+
79
+ const columns = deriveColumns(data)
80
+ // Column definitions ready for use in a table component
81
+ ```
39
82
 
40
- ## DataView
83
+ ### Dataset and dataview
41
84
 
42
- - Utilize the `dataview` function to create a data view, enabling dynamic data manipulation and observation.
43
- - This view facilitates sorting, filtering, and grouping data while providing insight into selected or hidden rows.
44
- - The original dataset remains untouched while the view offers flexible data presentation options.
45
- - Associate actions such as select, edit, and delete with data rows using action columns within the view.
46
- - Manage data effectively, including parent-child links, even within a flat array structure.
85
+ ```js
86
+ import { dataset, dataview } from '@rokkit/data'
87
+
88
+ const ds = dataset(rawData)
89
+ const view = dataview(ds, {
90
+ filters: [{ column: 'active', value: true, operator: 'eq' }],
91
+ sort: [{ column: 'name', direction: 'asc' }],
92
+ page: { size: 20, index: 0 }
93
+ })
94
+ ```
95
+
96
+ ### Key renaming
97
+
98
+ ```js
99
+ import { renamer } from '@rokkit/data'
100
+
101
+ const rename = renamer({ firstName: 'first_name', lastName: 'last_name' })
102
+ const remapped = data.map(rename)
103
+ ```
104
+
105
+ ### Filter string parsing
106
+
107
+ ```js
108
+ import { parseFilters } from '@rokkit/data'
109
+
110
+ const filters = parseFilters('age >= 18 AND status = "active"')
111
+ ```
112
+
113
+ ## API
114
+
115
+ | Export | Description |
116
+ | --------------------------------- | ----------------------------------------------------- |
117
+ | `typeOf(value)` | Infer type string from a value |
118
+ | `filterObjectArray(data, filter)` | Apply a single filter object to an array |
119
+ | `filterData(data, filters)` | Apply an array of filters to a dataset |
120
+ | `parseFilters(string)` | Parse a filter expression string into filter objects |
121
+ | `innerJoin(a, b, keyA, keyB)` | Inner join two arrays on matching keys |
122
+ | `leftJoin(a, b, keyA, keyB)` | Left join — all rows from `a`, matched rows from `b` |
123
+ | `rightJoin(a, b, keyA, keyB)` | Right join — all rows from `b`, matched rows from `a` |
124
+ | `fullJoin(a, b, keyA, keyB)` | Full outer join |
125
+ | `crossJoin(a, b)` | Cartesian product of two arrays |
126
+ | `antiJoin(a, b, keyA, keyB)` | Rows in `a` with no match in `b` |
127
+ | `semiJoin(a, b, keyA, keyB)` | Rows in `a` that have a match in `b` |
128
+ | `deriveMetadata(data)` | Infer column names and types from a data sample |
129
+ | `deriveColumns(data)` | Derive column definitions from data |
130
+ | `deriveSortableColumn(col)` | Mark a column as sortable |
131
+ | `dataset(data, options?)` | Create a dataset abstraction |
132
+ | `dataview(dataset, options?)` | Create a filtered/sorted/paged view over a dataset |
133
+ | `renamer(mapping)` | Create a function that renames object keys |
134
+ | `model(data)` | Create a reactive data model |
135
+
136
+ ## Benchmarks
137
+
138
+ Results from `benchmark/results/p4-lazy-fusion.json` — Bun 1.3.11, Apple Silicon (arm64).
139
+ All times in **ms (mean)** over 10 iterations. Dataset sizes: small = 100 rows, medium = 1 000 rows, large = 10 000 rows.
140
+
141
+ | Operation | Small | Medium | Large |
142
+ | --------------------------- | ----: | -----: | -----: |
143
+ | `groupBy` + `rollup` | 0.113 | 0.236 | 1.617 |
144
+ | `groupBy` + `summarize` + `rollup` | 0.042 | 0.097 | 0.534 |
145
+ | `groupBy` + `alignBy` + `rollup` | 0.133 | 0.090 | 0.085 |
146
+ | `where` + `apply` + `sortBy`| 0.024 | 0.120 | 1.328 |
147
+ | `filterData` | 0.020 | 0.022 | 0.081 |
148
+ | `leftJoin` | 0.044 | 0.448 | 23.620 |
149
+ | `antiJoin` | 0.045 | 0.340 | 13.798 |
150
+ | `semiJoin` | 0.032 | 0.172 | 11.318 |
151
+ | `crossJoin` | 0.034 | 0.023 | — |
152
+
153
+ To run benchmarks locally:
154
+
155
+ ```sh
156
+ bun run benchmark # print results to console
157
+ bun run benchmark:save # save results to benchmark/results/baseline.json
158
+ ```
47
159
 
48
- Refer to [dataview](docs/dataview.md) documentation for more details.
160
+ ---
49
161
 
50
- The `dataview` function initializes a manageable data state with methods that allow for manipulation and observation of data changes, integrating smoothly with UI updates.
162
+ Part of [Rokkit](https://github.com/jerrythomas/rokkit) — a Svelte 5 component library and design system.
package/package.json CHANGED
@@ -1,30 +1,31 @@
1
1
  {
2
2
  "name": "@rokkit/data",
3
- "version": "1.0.0-next.98",
3
+ "version": "1.0.1",
4
4
  "description": "Contains generic data manipulation functions that can be used in various components.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/jerrythomas/rokkit.git"
8
+ },
5
9
  "author": "Jerry Thomas <me@jerrythomas.name>",
6
10
  "license": "MIT",
7
- "main": "index.js",
8
- "module": "src/index.js",
9
- "types": "dist/index.d.ts",
10
11
  "type": "module",
11
12
  "publishConfig": {
12
13
  "access": "public"
13
14
  },
14
- "devDependencies": {
15
- "@sveltejs/vite-plugin-svelte": "^3.1.2",
16
- "@testing-library/svelte": "^5.2.1",
17
- "@types/ramda": "^0.30.2",
18
- "@vitest/coverage-v8": "^1.6.0",
19
- "@vitest/ui": "~1.6.0",
20
- "typescript": "^5.6.2",
21
- "vite": "^5.4.6",
22
- "vitest": "~1.6.0",
23
- "shared-config": "1.0.0-next.98"
15
+ "scripts": {
16
+ "prepublishOnly": "cp ../../LICENSE . && tsc --project tsconfig.build.json",
17
+ "postpublish": "rm -f LICENSE",
18
+ "clean": "rm -rf dist",
19
+ "build": "bun clean && bun prepublishOnly",
20
+ "benchmark": "bun benchmark/index.js",
21
+ "benchmark:save": "bun benchmark/index.js --save"
24
22
  },
25
23
  "files": [
26
24
  "src/**/*.js",
27
- "src/**/*.svelte"
25
+ "dist/**/*.d.ts",
26
+ "README.md",
27
+ "package.json",
28
+ "LICENSE"
28
29
  ],
29
30
  "exports": {
30
31
  "./src": "./src",
@@ -37,20 +38,10 @@
37
38
  },
38
39
  "dependencies": {
39
40
  "@lukeed/uuid": "^2.0.1",
41
+ "@rokkit/core": "1.0.1",
40
42
  "d3-array": "^3.2.4",
41
43
  "d3-collection": "^1.0.7",
42
- "ramda": "^0.30.1",
43
- "svelte": "^4.2.19",
44
- "@rokkit/core": "1.0.0-next.98"
45
- },
46
- "scripts": {
47
- "format": "prettier --write .",
48
- "lint": "eslint --fix .",
49
- "test:ci": "vitest run",
50
- "test:ui": "vitest --ui",
51
- "test": "vitest",
52
- "coverage": "vitest run --coverage",
53
- "latest": "pnpm upgrade --latest && pnpm test:ci",
54
- "release": "pnpm publish --access public"
44
+ "ramda": "^0.32.0",
45
+ "svelte": "^5.53.5"
55
46
  }
56
- }
47
+ }
package/src/constants.js CHANGED
@@ -1,6 +1,11 @@
1
- import { identity, pick } from 'ramda'
2
-
3
- export const pickAllowedConfig = pick(['children', 'actual_flag'])
1
+ const ALLOWED_CONFIG_KEYS = new Set(['children', 'actual_flag'])
2
+ export const pickAllowedConfig = (obj) => {
3
+ const result = {}
4
+ for (const k of ALLOWED_CONFIG_KEYS) {
5
+ if (k in obj) result[k] = obj[k]
6
+ }
7
+ return result
8
+ }
4
9
 
5
10
  /** @type {import('./types').DataFrameConfig */
6
11
  export const defaultConfig = {
@@ -63,7 +68,7 @@ export const typeConverters = {
63
68
  number: (value) => Number(value),
64
69
  boolean: (value) => value === 'true' || value === true,
65
70
  date: (value) => new Date(value),
66
- mixed: identity
71
+ mixed: (x) => x
67
72
  }
68
73
 
69
74
  /**