@noy-db/in-tanstack-table 0.1.0-pre.3
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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.cjs +79 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +52 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 vLannaAi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @noy-db/in-tanstack-table
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@noy-db/in-tanstack-table)
|
|
4
|
+
|
|
5
|
+
> TanStack Table bridge for noy-db
|
|
6
|
+
|
|
7
|
+
Part of [**`@noy-db/hub`**](https://www.npmjs.com/package/@noy-db/hub) — the zero-knowledge, offline-first, encrypted document store.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pnpm add @noy-db/hub @noy-db/in-tanstack-table
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What it is
|
|
16
|
+
|
|
17
|
+
TanStack Table bridge for noy-db — map Collection query state (sort, filter, pagination) into Table state and back, so a useSmartTable pattern drives the DB's query DSL without glue code.
|
|
18
|
+
|
|
19
|
+
## Status
|
|
20
|
+
|
|
21
|
+
**Pre-release** (`0.1.0-pre.1`). API may change before `1.0`.
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
See the [main repository](https://github.com/vLannaAi/noy-db#readme) for setup, examples, and the full subsystem catalog.
|
|
26
|
+
|
|
27
|
+
- Source — [`packages/in-tanstack-table`](https://github.com/vLannaAi/noy-db/tree/main/packages/in-tanstack-table)
|
|
28
|
+
- Issues — [github.com/vLannaAi/noy-db/issues](https://github.com/vLannaAi/noy-db/issues)
|
|
29
|
+
- Spec — [`SPEC.md`](https://github.com/vLannaAi/noy-db/blob/main/SPEC.md)
|
|
30
|
+
|
|
31
|
+
## License
|
|
32
|
+
|
|
33
|
+
[MIT](./LICENSE) © vLannaAi
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
buildQueryFromTableState: () => buildQueryFromTableState,
|
|
24
|
+
resetTableState: () => resetTableState,
|
|
25
|
+
tableStateFromQuery: () => tableStateFromQuery
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
function buildQueryFromTableState(query, state) {
|
|
29
|
+
let chain = query;
|
|
30
|
+
for (const filter of state.columnFilters ?? []) {
|
|
31
|
+
if (filter.value === void 0 || filter.value === null || filter.value === "") continue;
|
|
32
|
+
if (Array.isArray(filter.value)) {
|
|
33
|
+
chain = chain.where(filter.id, "in", filter.value);
|
|
34
|
+
} else {
|
|
35
|
+
chain = chain.where(filter.id, "==", filter.value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const sort of state.sorting ?? []) {
|
|
39
|
+
chain = chain.orderBy(sort.id, sort.desc ? "desc" : "asc");
|
|
40
|
+
}
|
|
41
|
+
const pag = state.pagination;
|
|
42
|
+
if (pag) {
|
|
43
|
+
const offset = pag.pageIndex * pag.pageSize;
|
|
44
|
+
if (offset > 0) chain = chain.offset(offset);
|
|
45
|
+
if (pag.pageSize > 0) chain = chain.limit(pag.pageSize);
|
|
46
|
+
}
|
|
47
|
+
return chain;
|
|
48
|
+
}
|
|
49
|
+
function tableStateFromQuery(query) {
|
|
50
|
+
const q = query;
|
|
51
|
+
const columnFilters = q.__clauses?.filter((c) => c.op === "==" || c.op === "in").map((c) => ({ id: c.field, value: c.value }));
|
|
52
|
+
const sorting = q.__sorts?.map((s) => ({
|
|
53
|
+
id: s.field,
|
|
54
|
+
desc: s.direction === "desc"
|
|
55
|
+
}));
|
|
56
|
+
const pagination = q.__limit !== void 0 ? {
|
|
57
|
+
pageSize: q.__limit,
|
|
58
|
+
pageIndex: q.__offset && q.__limit ? Math.floor(q.__offset / q.__limit) : 0
|
|
59
|
+
} : void 0;
|
|
60
|
+
const state = {};
|
|
61
|
+
if (columnFilters && columnFilters.length > 0) state.columnFilters = columnFilters;
|
|
62
|
+
if (sorting && sorting.length > 0) state.sorting = sorting;
|
|
63
|
+
if (pagination) state.pagination = pagination;
|
|
64
|
+
return state;
|
|
65
|
+
}
|
|
66
|
+
function resetTableState(pageSize = 25) {
|
|
67
|
+
return {
|
|
68
|
+
sorting: [],
|
|
69
|
+
columnFilters: [],
|
|
70
|
+
pagination: { pageIndex: 0, pageSize }
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
74
|
+
0 && (module.exports = {
|
|
75
|
+
buildQueryFromTableState,
|
|
76
|
+
resetTableState,
|
|
77
|
+
tableStateFromQuery
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/in-tanstack-table** — TanStack Table bridge for noy-db.\n *\n * Two-way binding between TanStack Table's state (sorting, filtering,\n * pagination) and noy-db's query DSL:\n *\n * - {@link buildQueryFromTableState} applies Table state to a\n * noy-db `Query<T>` chain — the returned chain is ready for a\n * terminal `.toArray()` / `.count()` / `.aggregate()`.\n *\n * - {@link tableStateFromQuery} pulls the Table-shaped state\n * back out of a query chain, for consumers that want\n * round-tripping (URL state, localStorage, etc.).\n *\n * This is a pure adapter — no React / Vue / Solid coupling. Pair with\n * the framework binding of your choice (`@tanstack/react-table`,\n * `@tanstack/vue-table`, …) to wire it up in a component.\n *\n * @packageDocumentation\n */\n\nimport type { Query } from '@noy-db/hub'\n\nexport interface TableSortDescriptor {\n readonly id: string\n readonly desc: boolean\n}\n\nexport interface TableFilterDescriptor {\n readonly id: string\n readonly value: unknown\n}\n\nexport interface TablePaginationState {\n readonly pageIndex: number\n readonly pageSize: number\n}\n\nexport interface TableState {\n readonly sorting?: readonly TableSortDescriptor[]\n readonly columnFilters?: readonly TableFilterDescriptor[]\n readonly pagination?: TablePaginationState\n}\n\n/**\n * Apply TanStack Table state to a noy-db `Query<T>` chain. Filters\n * are applied as `.where(id, '==', value)`; sorts as repeated\n * `.orderBy(id, 'desc' | 'asc')`; pagination as `.offset().limit()`.\n *\n * Consumers that need richer operators (`in`, `>=`, range) should\n * extend this with a custom `filterMapper` argument — this adapter\n * covers the 80% case cleanly.\n */\nexport function buildQueryFromTableState<T>(\n query: Query<T>,\n state: TableState,\n): Query<T> {\n let chain = query\n for (const filter of state.columnFilters ?? []) {\n if (filter.value === undefined || filter.value === null || filter.value === '') continue\n // Treat arrays as `in`, everything else as `==`.\n if (Array.isArray(filter.value)) {\n chain = chain.where(filter.id as keyof T & string, 'in', filter.value as unknown[])\n } else {\n chain = chain.where(filter.id as keyof T & string, '==', filter.value)\n }\n }\n for (const sort of state.sorting ?? []) {\n chain = chain.orderBy(sort.id as keyof T & string, sort.desc ? 'desc' : 'asc')\n }\n const pag = state.pagination\n if (pag) {\n const offset = pag.pageIndex * pag.pageSize\n if (offset > 0) chain = chain.offset(offset)\n if (pag.pageSize > 0) chain = chain.limit(pag.pageSize)\n }\n return chain\n}\n\n/**\n * Extract TanStack-Table-shaped state from a query chain for\n * serialization (URL, localStorage). Returns only what the query has\n * explicitly set — undefined fields stay undefined.\n */\nexport function tableStateFromQuery<T>(query: Query<T>): TableState {\n const q = query as unknown as {\n __clauses?: Array<{ field: string; op: string; value: unknown }>\n __sorts?: Array<{ field: string; direction: 'asc' | 'desc' }>\n __limit?: number\n __offset?: number\n }\n\n const columnFilters: TableFilterDescriptor[] | undefined = q.__clauses\n ?.filter(c => c.op === '==' || c.op === 'in')\n .map(c => ({ id: c.field, value: c.value }))\n const sorting: TableSortDescriptor[] | undefined = q.__sorts?.map(s => ({\n id: s.field,\n desc: s.direction === 'desc',\n }))\n const pagination: TablePaginationState | undefined =\n q.__limit !== undefined\n ? {\n pageSize: q.__limit,\n pageIndex: q.__offset && q.__limit ? Math.floor(q.__offset / q.__limit) : 0,\n }\n : undefined\n\n const state: TableState = {}\n if (columnFilters && columnFilters.length > 0) (state as { columnFilters?: readonly TableFilterDescriptor[] }).columnFilters = columnFilters\n if (sorting && sorting.length > 0) (state as { sorting?: readonly TableSortDescriptor[] }).sorting = sorting\n if (pagination) (state as { pagination?: TablePaginationState }).pagination = pagination\n return state\n}\n\n/**\n * Produce a `TableState` that represents \"no filter / no sort /\n * first-page pagination\". Useful as a reset function for user-facing\n * clear-all buttons.\n */\nexport function resetTableState(pageSize = 25): TableState {\n return {\n sorting: [],\n columnFilters: [],\n pagination: { pageIndex: 0, pageSize },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqDO,SAAS,yBACd,OACA,OACU;AACV,MAAI,QAAQ;AACZ,aAAW,UAAU,MAAM,iBAAiB,CAAC,GAAG;AAC9C,QAAI,OAAO,UAAU,UAAa,OAAO,UAAU,QAAQ,OAAO,UAAU,GAAI;AAEhF,QAAI,MAAM,QAAQ,OAAO,KAAK,GAAG;AAC/B,cAAQ,MAAM,MAAM,OAAO,IAAwB,MAAM,OAAO,KAAkB;AAAA,IACpF,OAAO;AACL,cAAQ,MAAM,MAAM,OAAO,IAAwB,MAAM,OAAO,KAAK;AAAA,IACvE;AAAA,EACF;AACA,aAAW,QAAQ,MAAM,WAAW,CAAC,GAAG;AACtC,YAAQ,MAAM,QAAQ,KAAK,IAAwB,KAAK,OAAO,SAAS,KAAK;AAAA,EAC/E;AACA,QAAM,MAAM,MAAM;AAClB,MAAI,KAAK;AACP,UAAM,SAAS,IAAI,YAAY,IAAI;AACnC,QAAI,SAAS,EAAG,SAAQ,MAAM,OAAO,MAAM;AAC3C,QAAI,IAAI,WAAW,EAAG,SAAQ,MAAM,MAAM,IAAI,QAAQ;AAAA,EACxD;AACA,SAAO;AACT;AAOO,SAAS,oBAAuB,OAA6B;AAClE,QAAM,IAAI;AAOV,QAAM,gBAAqD,EAAE,WACzD,OAAO,OAAK,EAAE,OAAO,QAAQ,EAAE,OAAO,IAAI,EAC3C,IAAI,QAAM,EAAE,IAAI,EAAE,OAAO,OAAO,EAAE,MAAM,EAAE;AAC7C,QAAM,UAA6C,EAAE,SAAS,IAAI,QAAM;AAAA,IACtE,IAAI,EAAE;AAAA,IACN,MAAM,EAAE,cAAc;AAAA,EACxB,EAAE;AACF,QAAM,aACJ,EAAE,YAAY,SACV;AAAA,IACE,UAAU,EAAE;AAAA,IACZ,WAAW,EAAE,YAAY,EAAE,UAAU,KAAK,MAAM,EAAE,WAAW,EAAE,OAAO,IAAI;AAAA,EAC5E,IACA;AAEN,QAAM,QAAoB,CAAC;AAC3B,MAAI,iBAAiB,cAAc,SAAS,EAAG,CAAC,MAA+D,gBAAgB;AAC/H,MAAI,WAAW,QAAQ,SAAS,EAAG,CAAC,MAAuD,UAAU;AACrG,MAAI,WAAY,CAAC,MAAgD,aAAa;AAC9E,SAAO;AACT;AAOO,SAAS,gBAAgB,WAAW,IAAgB;AACzD,SAAO;AAAA,IACL,SAAS,CAAC;AAAA,IACV,eAAe,CAAC;AAAA,IAChB,YAAY,EAAE,WAAW,GAAG,SAAS;AAAA,EACvC;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Query } from '@noy-db/hub';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **@noy-db/in-tanstack-table** — TanStack Table bridge for noy-db.
|
|
5
|
+
*
|
|
6
|
+
* Two-way binding between TanStack Table's state (sorting, filtering,
|
|
7
|
+
* pagination) and noy-db's query DSL:
|
|
8
|
+
*
|
|
9
|
+
* - {@link buildQueryFromTableState} applies Table state to a
|
|
10
|
+
* noy-db `Query<T>` chain — the returned chain is ready for a
|
|
11
|
+
* terminal `.toArray()` / `.count()` / `.aggregate()`.
|
|
12
|
+
*
|
|
13
|
+
* - {@link tableStateFromQuery} pulls the Table-shaped state
|
|
14
|
+
* back out of a query chain, for consumers that want
|
|
15
|
+
* round-tripping (URL state, localStorage, etc.).
|
|
16
|
+
*
|
|
17
|
+
* This is a pure adapter — no React / Vue / Solid coupling. Pair with
|
|
18
|
+
* the framework binding of your choice (`@tanstack/react-table`,
|
|
19
|
+
* `@tanstack/vue-table`, …) to wire it up in a component.
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
interface TableSortDescriptor {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly desc: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface TableFilterDescriptor {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly value: unknown;
|
|
31
|
+
}
|
|
32
|
+
interface TablePaginationState {
|
|
33
|
+
readonly pageIndex: number;
|
|
34
|
+
readonly pageSize: number;
|
|
35
|
+
}
|
|
36
|
+
interface TableState {
|
|
37
|
+
readonly sorting?: readonly TableSortDescriptor[];
|
|
38
|
+
readonly columnFilters?: readonly TableFilterDescriptor[];
|
|
39
|
+
readonly pagination?: TablePaginationState;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Apply TanStack Table state to a noy-db `Query<T>` chain. Filters
|
|
43
|
+
* are applied as `.where(id, '==', value)`; sorts as repeated
|
|
44
|
+
* `.orderBy(id, 'desc' | 'asc')`; pagination as `.offset().limit()`.
|
|
45
|
+
*
|
|
46
|
+
* Consumers that need richer operators (`in`, `>=`, range) should
|
|
47
|
+
* extend this with a custom `filterMapper` argument — this adapter
|
|
48
|
+
* covers the 80% case cleanly.
|
|
49
|
+
*/
|
|
50
|
+
declare function buildQueryFromTableState<T>(query: Query<T>, state: TableState): Query<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Extract TanStack-Table-shaped state from a query chain for
|
|
53
|
+
* serialization (URL, localStorage). Returns only what the query has
|
|
54
|
+
* explicitly set — undefined fields stay undefined.
|
|
55
|
+
*/
|
|
56
|
+
declare function tableStateFromQuery<T>(query: Query<T>): TableState;
|
|
57
|
+
/**
|
|
58
|
+
* Produce a `TableState` that represents "no filter / no sort /
|
|
59
|
+
* first-page pagination". Useful as a reset function for user-facing
|
|
60
|
+
* clear-all buttons.
|
|
61
|
+
*/
|
|
62
|
+
declare function resetTableState(pageSize?: number): TableState;
|
|
63
|
+
|
|
64
|
+
export { type TableFilterDescriptor, type TablePaginationState, type TableSortDescriptor, type TableState, buildQueryFromTableState, resetTableState, tableStateFromQuery };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Query } from '@noy-db/hub';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **@noy-db/in-tanstack-table** — TanStack Table bridge for noy-db.
|
|
5
|
+
*
|
|
6
|
+
* Two-way binding between TanStack Table's state (sorting, filtering,
|
|
7
|
+
* pagination) and noy-db's query DSL:
|
|
8
|
+
*
|
|
9
|
+
* - {@link buildQueryFromTableState} applies Table state to a
|
|
10
|
+
* noy-db `Query<T>` chain — the returned chain is ready for a
|
|
11
|
+
* terminal `.toArray()` / `.count()` / `.aggregate()`.
|
|
12
|
+
*
|
|
13
|
+
* - {@link tableStateFromQuery} pulls the Table-shaped state
|
|
14
|
+
* back out of a query chain, for consumers that want
|
|
15
|
+
* round-tripping (URL state, localStorage, etc.).
|
|
16
|
+
*
|
|
17
|
+
* This is a pure adapter — no React / Vue / Solid coupling. Pair with
|
|
18
|
+
* the framework binding of your choice (`@tanstack/react-table`,
|
|
19
|
+
* `@tanstack/vue-table`, …) to wire it up in a component.
|
|
20
|
+
*
|
|
21
|
+
* @packageDocumentation
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
interface TableSortDescriptor {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly desc: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface TableFilterDescriptor {
|
|
29
|
+
readonly id: string;
|
|
30
|
+
readonly value: unknown;
|
|
31
|
+
}
|
|
32
|
+
interface TablePaginationState {
|
|
33
|
+
readonly pageIndex: number;
|
|
34
|
+
readonly pageSize: number;
|
|
35
|
+
}
|
|
36
|
+
interface TableState {
|
|
37
|
+
readonly sorting?: readonly TableSortDescriptor[];
|
|
38
|
+
readonly columnFilters?: readonly TableFilterDescriptor[];
|
|
39
|
+
readonly pagination?: TablePaginationState;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Apply TanStack Table state to a noy-db `Query<T>` chain. Filters
|
|
43
|
+
* are applied as `.where(id, '==', value)`; sorts as repeated
|
|
44
|
+
* `.orderBy(id, 'desc' | 'asc')`; pagination as `.offset().limit()`.
|
|
45
|
+
*
|
|
46
|
+
* Consumers that need richer operators (`in`, `>=`, range) should
|
|
47
|
+
* extend this with a custom `filterMapper` argument — this adapter
|
|
48
|
+
* covers the 80% case cleanly.
|
|
49
|
+
*/
|
|
50
|
+
declare function buildQueryFromTableState<T>(query: Query<T>, state: TableState): Query<T>;
|
|
51
|
+
/**
|
|
52
|
+
* Extract TanStack-Table-shaped state from a query chain for
|
|
53
|
+
* serialization (URL, localStorage). Returns only what the query has
|
|
54
|
+
* explicitly set — undefined fields stay undefined.
|
|
55
|
+
*/
|
|
56
|
+
declare function tableStateFromQuery<T>(query: Query<T>): TableState;
|
|
57
|
+
/**
|
|
58
|
+
* Produce a `TableState` that represents "no filter / no sort /
|
|
59
|
+
* first-page pagination". Useful as a reset function for user-facing
|
|
60
|
+
* clear-all buttons.
|
|
61
|
+
*/
|
|
62
|
+
declare function resetTableState(pageSize?: number): TableState;
|
|
63
|
+
|
|
64
|
+
export { type TableFilterDescriptor, type TablePaginationState, type TableSortDescriptor, type TableState, buildQueryFromTableState, resetTableState, tableStateFromQuery };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function buildQueryFromTableState(query, state) {
|
|
3
|
+
let chain = query;
|
|
4
|
+
for (const filter of state.columnFilters ?? []) {
|
|
5
|
+
if (filter.value === void 0 || filter.value === null || filter.value === "") continue;
|
|
6
|
+
if (Array.isArray(filter.value)) {
|
|
7
|
+
chain = chain.where(filter.id, "in", filter.value);
|
|
8
|
+
} else {
|
|
9
|
+
chain = chain.where(filter.id, "==", filter.value);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
for (const sort of state.sorting ?? []) {
|
|
13
|
+
chain = chain.orderBy(sort.id, sort.desc ? "desc" : "asc");
|
|
14
|
+
}
|
|
15
|
+
const pag = state.pagination;
|
|
16
|
+
if (pag) {
|
|
17
|
+
const offset = pag.pageIndex * pag.pageSize;
|
|
18
|
+
if (offset > 0) chain = chain.offset(offset);
|
|
19
|
+
if (pag.pageSize > 0) chain = chain.limit(pag.pageSize);
|
|
20
|
+
}
|
|
21
|
+
return chain;
|
|
22
|
+
}
|
|
23
|
+
function tableStateFromQuery(query) {
|
|
24
|
+
const q = query;
|
|
25
|
+
const columnFilters = q.__clauses?.filter((c) => c.op === "==" || c.op === "in").map((c) => ({ id: c.field, value: c.value }));
|
|
26
|
+
const sorting = q.__sorts?.map((s) => ({
|
|
27
|
+
id: s.field,
|
|
28
|
+
desc: s.direction === "desc"
|
|
29
|
+
}));
|
|
30
|
+
const pagination = q.__limit !== void 0 ? {
|
|
31
|
+
pageSize: q.__limit,
|
|
32
|
+
pageIndex: q.__offset && q.__limit ? Math.floor(q.__offset / q.__limit) : 0
|
|
33
|
+
} : void 0;
|
|
34
|
+
const state = {};
|
|
35
|
+
if (columnFilters && columnFilters.length > 0) state.columnFilters = columnFilters;
|
|
36
|
+
if (sorting && sorting.length > 0) state.sorting = sorting;
|
|
37
|
+
if (pagination) state.pagination = pagination;
|
|
38
|
+
return state;
|
|
39
|
+
}
|
|
40
|
+
function resetTableState(pageSize = 25) {
|
|
41
|
+
return {
|
|
42
|
+
sorting: [],
|
|
43
|
+
columnFilters: [],
|
|
44
|
+
pagination: { pageIndex: 0, pageSize }
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
buildQueryFromTableState,
|
|
49
|
+
resetTableState,
|
|
50
|
+
tableStateFromQuery
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * **@noy-db/in-tanstack-table** — TanStack Table bridge for noy-db.\n *\n * Two-way binding between TanStack Table's state (sorting, filtering,\n * pagination) and noy-db's query DSL:\n *\n * - {@link buildQueryFromTableState} applies Table state to a\n * noy-db `Query<T>` chain — the returned chain is ready for a\n * terminal `.toArray()` / `.count()` / `.aggregate()`.\n *\n * - {@link tableStateFromQuery} pulls the Table-shaped state\n * back out of a query chain, for consumers that want\n * round-tripping (URL state, localStorage, etc.).\n *\n * This is a pure adapter — no React / Vue / Solid coupling. Pair with\n * the framework binding of your choice (`@tanstack/react-table`,\n * `@tanstack/vue-table`, …) to wire it up in a component.\n *\n * @packageDocumentation\n */\n\nimport type { Query } from '@noy-db/hub'\n\nexport interface TableSortDescriptor {\n readonly id: string\n readonly desc: boolean\n}\n\nexport interface TableFilterDescriptor {\n readonly id: string\n readonly value: unknown\n}\n\nexport interface TablePaginationState {\n readonly pageIndex: number\n readonly pageSize: number\n}\n\nexport interface TableState {\n readonly sorting?: readonly TableSortDescriptor[]\n readonly columnFilters?: readonly TableFilterDescriptor[]\n readonly pagination?: TablePaginationState\n}\n\n/**\n * Apply TanStack Table state to a noy-db `Query<T>` chain. Filters\n * are applied as `.where(id, '==', value)`; sorts as repeated\n * `.orderBy(id, 'desc' | 'asc')`; pagination as `.offset().limit()`.\n *\n * Consumers that need richer operators (`in`, `>=`, range) should\n * extend this with a custom `filterMapper` argument — this adapter\n * covers the 80% case cleanly.\n */\nexport function buildQueryFromTableState<T>(\n query: Query<T>,\n state: TableState,\n): Query<T> {\n let chain = query\n for (const filter of state.columnFilters ?? []) {\n if (filter.value === undefined || filter.value === null || filter.value === '') continue\n // Treat arrays as `in`, everything else as `==`.\n if (Array.isArray(filter.value)) {\n chain = chain.where(filter.id as keyof T & string, 'in', filter.value as unknown[])\n } else {\n chain = chain.where(filter.id as keyof T & string, '==', filter.value)\n }\n }\n for (const sort of state.sorting ?? []) {\n chain = chain.orderBy(sort.id as keyof T & string, sort.desc ? 'desc' : 'asc')\n }\n const pag = state.pagination\n if (pag) {\n const offset = pag.pageIndex * pag.pageSize\n if (offset > 0) chain = chain.offset(offset)\n if (pag.pageSize > 0) chain = chain.limit(pag.pageSize)\n }\n return chain\n}\n\n/**\n * Extract TanStack-Table-shaped state from a query chain for\n * serialization (URL, localStorage). Returns only what the query has\n * explicitly set — undefined fields stay undefined.\n */\nexport function tableStateFromQuery<T>(query: Query<T>): TableState {\n const q = query as unknown as {\n __clauses?: Array<{ field: string; op: string; value: unknown }>\n __sorts?: Array<{ field: string; direction: 'asc' | 'desc' }>\n __limit?: number\n __offset?: number\n }\n\n const columnFilters: TableFilterDescriptor[] | undefined = q.__clauses\n ?.filter(c => c.op === '==' || c.op === 'in')\n .map(c => ({ id: c.field, value: c.value }))\n const sorting: TableSortDescriptor[] | undefined = q.__sorts?.map(s => ({\n id: s.field,\n desc: s.direction === 'desc',\n }))\n const pagination: TablePaginationState | undefined =\n q.__limit !== undefined\n ? {\n pageSize: q.__limit,\n pageIndex: q.__offset && q.__limit ? Math.floor(q.__offset / q.__limit) : 0,\n }\n : undefined\n\n const state: TableState = {}\n if (columnFilters && columnFilters.length > 0) (state as { columnFilters?: readonly TableFilterDescriptor[] }).columnFilters = columnFilters\n if (sorting && sorting.length > 0) (state as { sorting?: readonly TableSortDescriptor[] }).sorting = sorting\n if (pagination) (state as { pagination?: TablePaginationState }).pagination = pagination\n return state\n}\n\n/**\n * Produce a `TableState` that represents \"no filter / no sort /\n * first-page pagination\". Useful as a reset function for user-facing\n * clear-all buttons.\n */\nexport function resetTableState(pageSize = 25): TableState {\n return {\n sorting: [],\n columnFilters: [],\n pagination: { pageIndex: 0, pageSize },\n }\n}\n"],"mappings":";AAqDO,SAAS,yBACd,OACA,OACU;AACV,MAAI,QAAQ;AACZ,aAAW,UAAU,MAAM,iBAAiB,CAAC,GAAG;AAC9C,QAAI,OAAO,UAAU,UAAa,OAAO,UAAU,QAAQ,OAAO,UAAU,GAAI;AAEhF,QAAI,MAAM,QAAQ,OAAO,KAAK,GAAG;AAC/B,cAAQ,MAAM,MAAM,OAAO,IAAwB,MAAM,OAAO,KAAkB;AAAA,IACpF,OAAO;AACL,cAAQ,MAAM,MAAM,OAAO,IAAwB,MAAM,OAAO,KAAK;AAAA,IACvE;AAAA,EACF;AACA,aAAW,QAAQ,MAAM,WAAW,CAAC,GAAG;AACtC,YAAQ,MAAM,QAAQ,KAAK,IAAwB,KAAK,OAAO,SAAS,KAAK;AAAA,EAC/E;AACA,QAAM,MAAM,MAAM;AAClB,MAAI,KAAK;AACP,UAAM,SAAS,IAAI,YAAY,IAAI;AACnC,QAAI,SAAS,EAAG,SAAQ,MAAM,OAAO,MAAM;AAC3C,QAAI,IAAI,WAAW,EAAG,SAAQ,MAAM,MAAM,IAAI,QAAQ;AAAA,EACxD;AACA,SAAO;AACT;AAOO,SAAS,oBAAuB,OAA6B;AAClE,QAAM,IAAI;AAOV,QAAM,gBAAqD,EAAE,WACzD,OAAO,OAAK,EAAE,OAAO,QAAQ,EAAE,OAAO,IAAI,EAC3C,IAAI,QAAM,EAAE,IAAI,EAAE,OAAO,OAAO,EAAE,MAAM,EAAE;AAC7C,QAAM,UAA6C,EAAE,SAAS,IAAI,QAAM;AAAA,IACtE,IAAI,EAAE;AAAA,IACN,MAAM,EAAE,cAAc;AAAA,EACxB,EAAE;AACF,QAAM,aACJ,EAAE,YAAY,SACV;AAAA,IACE,UAAU,EAAE;AAAA,IACZ,WAAW,EAAE,YAAY,EAAE,UAAU,KAAK,MAAM,EAAE,WAAW,EAAE,OAAO,IAAI;AAAA,EAC5E,IACA;AAEN,QAAM,QAAoB,CAAC;AAC3B,MAAI,iBAAiB,cAAc,SAAS,EAAG,CAAC,MAA+D,gBAAgB;AAC/H,MAAI,WAAW,QAAQ,SAAS,EAAG,CAAC,MAAuD,UAAU;AACrG,MAAI,WAAY,CAAC,MAAgD,aAAa;AAC9E,SAAO;AACT;AAOO,SAAS,gBAAgB,WAAW,IAAgB;AACzD,SAAO;AAAA,IACL,SAAS,CAAC;AAAA,IACV,eAAe,CAAC;AAAA,IAChB,YAAY,EAAE,WAAW,GAAG,SAAS;AAAA,EACvC;AACF;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@noy-db/in-tanstack-table",
|
|
3
|
+
"version": "0.1.0-pre.3",
|
|
4
|
+
"description": "TanStack Table bridge for noy-db — map Collection query state (sort, filter, pagination) into Table state and back, so a useSmartTable pattern drives the DB's query DSL without glue code.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "vLannaAi <vicio@lanna.ai>",
|
|
7
|
+
"homepage": "https://github.com/vLannaAi/noy-db/tree/main/packages/in-tanstack-table#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/vLannaAi/noy-db.git",
|
|
11
|
+
"directory": "packages/in-tanstack-table"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/vLannaAi/noy-db/issues"
|
|
15
|
+
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"require": {
|
|
25
|
+
"types": "./dist/index.d.cts",
|
|
26
|
+
"default": "./dist/index.cjs"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@tanstack/table-core": "^8.0.0",
|
|
43
|
+
"@noy-db/hub": "0.1.0-pre.3"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@tanstack/table-core": "^8.20.0",
|
|
47
|
+
"@noy-db/hub": "0.1.0-pre.3"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"noy-db",
|
|
51
|
+
"in-tanstack-table",
|
|
52
|
+
"tanstack",
|
|
53
|
+
"table",
|
|
54
|
+
"smart-table"
|
|
55
|
+
],
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public",
|
|
58
|
+
"tag": "latest"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsup",
|
|
62
|
+
"test": "vitest run",
|
|
63
|
+
"lint": "eslint src/",
|
|
64
|
+
"typecheck": "tsc --noEmit"
|
|
65
|
+
}
|
|
66
|
+
}
|