dn-react-router-toolkit 0.8.0 → 0.8.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.
Files changed (47) hide show
  1. package/dist/api/index.js +13 -4
  2. package/dist/api/index.mjs +14 -5
  3. package/dist/api/item_api_handler.d.mts +4 -2
  4. package/dist/api/item_api_handler.d.ts +4 -2
  5. package/dist/api/item_api_handler.js +13 -4
  6. package/dist/api/item_api_handler.mjs +14 -5
  7. package/dist/crud/crud_loader.js +34 -5
  8. package/dist/crud/crud_loader.mjs +36 -6
  9. package/dist/crud/crud_page.js +69 -19
  10. package/dist/crud/crud_page.mjs +69 -19
  11. package/dist/crud/index.js +109 -30
  12. package/dist/crud/index.mjs +111 -31
  13. package/dist/post/index.js +6 -6
  14. package/dist/post/index.mjs +8 -7
  15. package/dist/post/post_form_page.js +6 -6
  16. package/dist/post/post_form_page.mjs +8 -7
  17. package/dist/table/index.d.mts +1 -1
  18. package/dist/table/index.d.ts +1 -1
  19. package/dist/table/index.js +94 -20
  20. package/dist/table/index.mjs +95 -20
  21. package/dist/table/load_table.d.mts +7 -1
  22. package/dist/table/load_table.d.ts +7 -1
  23. package/dist/table/load_table.js +21 -1
  24. package/dist/table/load_table.mjs +22 -1
  25. package/dist/table/loader.d.mts +3 -0
  26. package/dist/table/loader.d.ts +3 -0
  27. package/dist/table/loader.js +21 -1
  28. package/dist/table/loader.mjs +22 -1
  29. package/dist/table/page.js +69 -19
  30. package/dist/table/page.mjs +69 -19
  31. package/dist/table/repository.d.mts +6 -4
  32. package/dist/table/repository.d.ts +6 -4
  33. package/dist/table/repository.js +4 -0
  34. package/dist/table/repository.mjs +4 -0
  35. package/dist/table/table.d.mts +4 -1
  36. package/dist/table/table.d.ts +4 -1
  37. package/dist/table/table.js +55 -6
  38. package/dist/table/table.mjs +55 -6
  39. package/dist/table/table_form.d.mts +2 -2
  40. package/dist/table/table_form.d.ts +2 -2
  41. package/dist/table/table_form.js +69 -19
  42. package/dist/table/table_form.mjs +69 -19
  43. package/dist/table/use_table.d.mts +3 -3
  44. package/dist/table/use_table.d.ts +3 -3
  45. package/dist/table/use_table.js +1 -10
  46. package/dist/table/use_table.mjs +1 -10
  47. package/package.json +2 -2
@@ -6510,10 +6510,10 @@ var require_listCacheClear = __commonJS({
6510
6510
  var require_eq = __commonJS({
6511
6511
  "node_modules/lodash/eq.js"(exports, module) {
6512
6512
  "use strict";
6513
- function eq(value, other) {
6513
+ function eq2(value, other) {
6514
6514
  return value === other || value !== value && other !== other;
6515
6515
  }
6516
- module.exports = eq;
6516
+ module.exports = eq2;
6517
6517
  }
6518
6518
  });
6519
6519
 
@@ -6521,11 +6521,11 @@ var require_eq = __commonJS({
6521
6521
  var require_assocIndexOf = __commonJS({
6522
6522
  "node_modules/lodash/_assocIndexOf.js"(exports, module) {
6523
6523
  "use strict";
6524
- var eq = require_eq();
6524
+ var eq2 = require_eq();
6525
6525
  function assocIndexOf(array, key) {
6526
6526
  var length = array.length;
6527
6527
  while (length--) {
6528
- if (eq(array[length][0], key)) {
6528
+ if (eq2(array[length][0], key)) {
6529
6529
  return length;
6530
6530
  }
6531
6531
  }
@@ -6983,12 +6983,12 @@ var require_assignValue = __commonJS({
6983
6983
  "node_modules/lodash/_assignValue.js"(exports, module) {
6984
6984
  "use strict";
6985
6985
  var baseAssignValue = require_baseAssignValue();
6986
- var eq = require_eq();
6986
+ var eq2 = require_eq();
6987
6987
  var objectProto = Object.prototype;
6988
6988
  var hasOwnProperty = objectProto.hasOwnProperty;
6989
6989
  function assignValue(object, key, value) {
6990
6990
  var objValue = object[key];
6991
- if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || value === void 0 && !(key in object)) {
6991
+ if (!(hasOwnProperty.call(object, key) && eq2(objValue, value)) || value === void 0 && !(key in object)) {
6992
6992
  baseAssignValue(object, key, value);
6993
6993
  }
6994
6994
  }
@@ -7940,6 +7940,7 @@ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-run
7940
7940
  // src/table/load_table.tsx
7941
7941
  import {
7942
7942
  and,
7943
+ eq,
7943
7944
  ilike
7944
7945
  } from "drizzle-orm";
7945
7946
 
@@ -7958,7 +7959,7 @@ import {
7958
7959
  import { v4 } from "uuid";
7959
7960
 
7960
7961
  // src/api/item_api_handler.ts
7961
- import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
7962
+ import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
7962
7963
 
7963
7964
  // src/crud/crud_page.tsx
7964
7965
  import { useLoaderData as useLoaderData2, useLocation as useLocation4 } from "react-router";
@@ -6,7 +6,7 @@ export { createTablePage } from './page.mjs';
6
6
  export { OrderedTableProps, Table, TableColumnOptions, TableColumnProps } from './table.mjs';
7
7
  export { TableLoaderOptions, loadTable } from './load_table.mjs';
8
8
  export { LoadedModel, TableForm, TablePageOptions } from './table_form.mjs';
9
- export { LoadedTable, useTable } from './use_table.mjs';
9
+ export { TableLoaderData, useTable } from './use_table.mjs';
10
10
  import 'drizzle-orm';
11
11
  import 'drizzle-orm/node-postgres';
12
12
  import 'drizzle-orm/pg-core';
@@ -6,7 +6,7 @@ export { createTablePage } from './page.js';
6
6
  export { OrderedTableProps, Table, TableColumnOptions, TableColumnProps } from './table.js';
7
7
  export { TableLoaderOptions, loadTable } from './load_table.js';
8
8
  export { LoadedModel, TableForm, TablePageOptions } from './table_form.js';
9
- export { LoadedTable, useTable } from './use_table.js';
9
+ export { TableLoaderData, useTable } from './use_table.js';
10
10
  import 'drizzle-orm';
11
11
  import 'drizzle-orm/node-postgres';
12
12
  import 'drizzle-orm/pg-core';
@@ -79,6 +79,10 @@ var BaseTableRepository = class {
79
79
  async delete(pk) {
80
80
  await this.db.delete(this.schema).where((0, import_drizzle_orm.eq)(this.schema[this.pk], pk));
81
81
  }
82
+ async select(key) {
83
+ const rows = await this.db.select({ value: this.schema[key] }).from(this.schema).groupBy(this.schema[key]);
84
+ return rows.map((row) => row.value);
85
+ }
82
86
  };
83
87
 
84
88
  // src/table/buttons.tsx
@@ -184,11 +188,22 @@ async function loadTable({
184
188
  const offset = Number(searchParams.get("offset") ?? "0");
185
189
  const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
186
190
  const direction = searchParams.get("direction") ?? defaultDirection;
191
+ const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
192
+ const param = searchParams.get(key);
193
+ if (param) {
194
+ return (0, import_drizzle_orm2.eq)(
195
+ repository.schema[key],
196
+ decodeURIComponent(param)
197
+ );
198
+ }
199
+ return void 0;
200
+ }).filter(Boolean);
187
201
  const whereClauses = (0, import_drizzle_orm2.and)(
188
202
  searchKey && query ? (0, import_drizzle_orm2.ilike)(
189
203
  repository.schema[searchKey],
190
204
  `%${query}%`
191
205
  ) : void 0,
206
+ ...filterWhere,
192
207
  ...where ?? []
193
208
  );
194
209
  const total = await repository.countTotal({ where: whereClauses });
@@ -199,6 +214,14 @@ async function loadTable({
199
214
  offset,
200
215
  where: whereClauses
201
216
  });
217
+ const filters = Object.fromEntries(
218
+ await Promise.all(
219
+ Object.keys(options.filters ?? {}).map(async (key) => {
220
+ const values = await repository.select(key);
221
+ return [key, values.filter(Boolean)];
222
+ })
223
+ )
224
+ );
202
225
  return {
203
226
  items,
204
227
  total,
@@ -206,7 +229,8 @@ async function loadTable({
206
229
  offset,
207
230
  orderBy,
208
231
  direction,
209
- searchKey
232
+ searchKey,
233
+ filters
210
234
  };
211
235
  }
212
236
 
@@ -248,7 +272,8 @@ function Table({
248
272
  limit,
249
273
  offset,
250
274
  orderBy,
251
- direction
275
+ direction,
276
+ filters
252
277
  }) {
253
278
  const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
254
279
  const sortedArray = [...data];
@@ -256,7 +281,10 @@ function Table({
256
281
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
257
282
  "table",
258
283
  {
259
- className: (0, import_utils2.cn)(className, "text-[15px] border-separate border-spacing-0"),
284
+ className: (0, import_utils2.cn)(
285
+ className,
286
+ "text-[15px] border-separate border-spacing-0"
287
+ ),
260
288
  children: [
261
289
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: keys.map((key) => {
262
290
  const value = columns[key];
@@ -273,8 +301,8 @@ function Table({
273
301
  "button",
274
302
  {
275
303
  className: (0, import_utils2.cn)(
276
- orderBy === key ? "text-neutral-900 font-medium" : "text-neutral-500",
277
- "px-4 h-14 flex items-center w-full"
304
+ orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
305
+ "px-4 flex items-center w-full"
278
306
  ),
279
307
  onClick: () => {
280
308
  let newDirection = "asc";
@@ -295,14 +323,59 @@ function Table({
295
323
  }
296
324
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: reactNode });
297
325
  }
298
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { className: (0, import_utils2.cn)("border-y font-normal"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Head, {}) }, key);
326
+ const filter = filters[key];
327
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
328
+ "th",
329
+ {
330
+ className: (0, import_utils2.cn)(
331
+ "py-4 border-y font-normal align-top"
332
+ ),
333
+ children: [
334
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Head, {}),
335
+ filter && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "px-3 mt-4", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
336
+ "select",
337
+ {
338
+ className: "w-full h-10 px-1.5 border rounded-full outline-none",
339
+ onChange: (e) => {
340
+ const value2 = e.target.value;
341
+ setSearchParams((prev) => {
342
+ if (value2) {
343
+ prev.set(
344
+ key,
345
+ encodeURIComponent(
346
+ value2
347
+ )
348
+ );
349
+ } else {
350
+ prev.delete(key);
351
+ }
352
+ return prev;
353
+ });
354
+ },
355
+ children: [
356
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: "\uC804\uCCB4" }),
357
+ filter.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
358
+ "option",
359
+ {
360
+ value: option,
361
+ children: option
362
+ },
363
+ option
364
+ ))
365
+ ]
366
+ }
367
+ ) })
368
+ ]
369
+ },
370
+ key
371
+ );
299
372
  }) }) }),
300
373
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tbody", { children: [
301
374
  sortedArray.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
302
375
  "td",
303
376
  {
304
377
  colSpan: keys.length,
305
- className: "px-4 h-14 text-neutral-400 text-center",
378
+ className: "px-4 h-20 text-gray-400 text-center",
306
379
  children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
307
380
  }
308
381
  ) }),
@@ -341,16 +414,7 @@ function Table({
341
414
  var import_react_router3 = require("react-router");
342
415
  function useTable() {
343
416
  const { table } = (0, import_react_router3.useLoaderData)();
344
- const { items, total, limit, offset, orderBy, direction, searchKey } = table;
345
- return {
346
- items,
347
- total,
348
- limit,
349
- offset,
350
- orderBy,
351
- direction,
352
- searchKey
353
- };
417
+ return table;
354
418
  }
355
419
 
356
420
  // src/table/table_form.tsx
@@ -360,7 +424,16 @@ function TableForm({
360
424
  primaryKey = "id"
361
425
  }) {
362
426
  const { pathname } = (0, import_react_router4.useLocation)();
363
- const { items, total, limit, offset, orderBy, direction, searchKey } = useTable();
427
+ const {
428
+ items,
429
+ total,
430
+ limit,
431
+ offset,
432
+ orderBy,
433
+ direction,
434
+ searchKey,
435
+ filters
436
+ } = useTable();
364
437
  const navigate = (0, import_react_router4.useNavigate)();
365
438
  const search = (query) => {
366
439
  const searchParams2 = new URLSearchParams(window.location.search);
@@ -373,7 +446,7 @@ function TableForm({
373
446
  searchKey && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
374
447
  "form",
375
448
  {
376
- className: "h-18 px-4 flex items-center border-t",
449
+ className: "h-20 px-4 flex items-center border-t",
377
450
  onSubmit: (e) => {
378
451
  e.preventDefault();
379
452
  const formData = new FormData(e.currentTarget);
@@ -410,7 +483,8 @@ function TableForm({
410
483
  limit,
411
484
  offset,
412
485
  orderBy,
413
- direction
486
+ direction,
487
+ filters
414
488
  }
415
489
  ),
416
490
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
@@ -50,6 +50,10 @@ var BaseTableRepository = class {
50
50
  async delete(pk) {
51
51
  await this.db.delete(this.schema).where(eq(this.schema[this.pk], pk));
52
52
  }
53
+ async select(key) {
54
+ const rows = await this.db.select({ value: this.schema[key] }).from(this.schema).groupBy(this.schema[key]);
55
+ return rows.map((row) => row.value);
56
+ }
53
57
  };
54
58
 
55
59
  // src/table/buttons.tsx
@@ -144,6 +148,7 @@ var tableItemloader = ({
144
148
  // src/table/load_table.tsx
145
149
  import {
146
150
  and,
151
+ eq as eq2,
147
152
  ilike
148
153
  } from "drizzle-orm";
149
154
  async function loadTable({
@@ -158,11 +163,22 @@ async function loadTable({
158
163
  const offset = Number(searchParams.get("offset") ?? "0");
159
164
  const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
160
165
  const direction = searchParams.get("direction") ?? defaultDirection;
166
+ const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
167
+ const param = searchParams.get(key);
168
+ if (param) {
169
+ return eq2(
170
+ repository.schema[key],
171
+ decodeURIComponent(param)
172
+ );
173
+ }
174
+ return void 0;
175
+ }).filter(Boolean);
161
176
  const whereClauses = and(
162
177
  searchKey && query ? ilike(
163
178
  repository.schema[searchKey],
164
179
  `%${query}%`
165
180
  ) : void 0,
181
+ ...filterWhere,
166
182
  ...where ?? []
167
183
  );
168
184
  const total = await repository.countTotal({ where: whereClauses });
@@ -173,6 +189,14 @@ async function loadTable({
173
189
  offset,
174
190
  where: whereClauses
175
191
  });
192
+ const filters = Object.fromEntries(
193
+ await Promise.all(
194
+ Object.keys(options.filters ?? {}).map(async (key) => {
195
+ const values = await repository.select(key);
196
+ return [key, values.filter(Boolean)];
197
+ })
198
+ )
199
+ );
176
200
  return {
177
201
  items,
178
202
  total,
@@ -180,7 +204,8 @@ async function loadTable({
180
204
  offset,
181
205
  orderBy,
182
206
  direction,
183
- searchKey
207
+ searchKey,
208
+ filters
184
209
  };
185
210
  }
186
211
 
@@ -222,7 +247,8 @@ function Table({
222
247
  limit,
223
248
  offset,
224
249
  orderBy,
225
- direction
250
+ direction,
251
+ filters
226
252
  }) {
227
253
  const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
228
254
  const sortedArray = [...data];
@@ -230,7 +256,10 @@ function Table({
230
256
  return /* @__PURE__ */ jsxs2(
231
257
  "table",
232
258
  {
233
- className: cn2(className, "text-[15px] border-separate border-spacing-0"),
259
+ className: cn2(
260
+ className,
261
+ "text-[15px] border-separate border-spacing-0"
262
+ ),
234
263
  children: [
235
264
  /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsx2("tr", { children: keys.map((key) => {
236
265
  const value = columns[key];
@@ -247,8 +276,8 @@ function Table({
247
276
  "button",
248
277
  {
249
278
  className: cn2(
250
- orderBy === key ? "text-neutral-900 font-medium" : "text-neutral-500",
251
- "px-4 h-14 flex items-center w-full"
279
+ orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
280
+ "px-4 flex items-center w-full"
252
281
  ),
253
282
  onClick: () => {
254
283
  let newDirection = "asc";
@@ -269,14 +298,59 @@ function Table({
269
298
  }
270
299
  return /* @__PURE__ */ jsx2(Fragment2, { children: reactNode });
271
300
  }
272
- return /* @__PURE__ */ jsx2("th", { className: cn2("border-y font-normal"), children: /* @__PURE__ */ jsx2(Head, {}) }, key);
301
+ const filter = filters[key];
302
+ return /* @__PURE__ */ jsxs2(
303
+ "th",
304
+ {
305
+ className: cn2(
306
+ "py-4 border-y font-normal align-top"
307
+ ),
308
+ children: [
309
+ /* @__PURE__ */ jsx2(Head, {}),
310
+ filter && /* @__PURE__ */ jsx2("div", { className: "px-3 mt-4", children: /* @__PURE__ */ jsxs2(
311
+ "select",
312
+ {
313
+ className: "w-full h-10 px-1.5 border rounded-full outline-none",
314
+ onChange: (e) => {
315
+ const value2 = e.target.value;
316
+ setSearchParams((prev) => {
317
+ if (value2) {
318
+ prev.set(
319
+ key,
320
+ encodeURIComponent(
321
+ value2
322
+ )
323
+ );
324
+ } else {
325
+ prev.delete(key);
326
+ }
327
+ return prev;
328
+ });
329
+ },
330
+ children: [
331
+ /* @__PURE__ */ jsx2("option", { value: "", children: "\uC804\uCCB4" }),
332
+ filter.map((option) => /* @__PURE__ */ jsx2(
333
+ "option",
334
+ {
335
+ value: option,
336
+ children: option
337
+ },
338
+ option
339
+ ))
340
+ ]
341
+ }
342
+ ) })
343
+ ]
344
+ },
345
+ key
346
+ );
273
347
  }) }) }),
274
348
  /* @__PURE__ */ jsxs2("tbody", { children: [
275
349
  sortedArray.length === 0 && /* @__PURE__ */ jsx2("tr", { children: /* @__PURE__ */ jsx2(
276
350
  "td",
277
351
  {
278
352
  colSpan: keys.length,
279
- className: "px-4 h-14 text-neutral-400 text-center",
353
+ className: "px-4 h-20 text-gray-400 text-center",
280
354
  children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
281
355
  }
282
356
  ) }),
@@ -315,16 +389,7 @@ function Table({
315
389
  import { useLoaderData } from "react-router";
316
390
  function useTable() {
317
391
  const { table } = useLoaderData();
318
- const { items, total, limit, offset, orderBy, direction, searchKey } = table;
319
- return {
320
- items,
321
- total,
322
- limit,
323
- offset,
324
- orderBy,
325
- direction,
326
- searchKey
327
- };
392
+ return table;
328
393
  }
329
394
 
330
395
  // src/table/table_form.tsx
@@ -334,7 +399,16 @@ function TableForm({
334
399
  primaryKey = "id"
335
400
  }) {
336
401
  const { pathname } = useLocation2();
337
- const { items, total, limit, offset, orderBy, direction, searchKey } = useTable();
402
+ const {
403
+ items,
404
+ total,
405
+ limit,
406
+ offset,
407
+ orderBy,
408
+ direction,
409
+ searchKey,
410
+ filters
411
+ } = useTable();
338
412
  const navigate = useNavigate();
339
413
  const search = (query) => {
340
414
  const searchParams2 = new URLSearchParams(window.location.search);
@@ -347,7 +421,7 @@ function TableForm({
347
421
  searchKey && /* @__PURE__ */ jsxs3(
348
422
  "form",
349
423
  {
350
- className: "h-18 px-4 flex items-center border-t",
424
+ className: "h-20 px-4 flex items-center border-t",
351
425
  onSubmit: (e) => {
352
426
  e.preventDefault();
353
427
  const formData = new FormData(e.currentTarget);
@@ -384,7 +458,8 @@ function TableForm({
384
458
  limit,
385
459
  offset,
386
460
  orderBy,
387
- direction
461
+ direction,
462
+ filters
388
463
  }
389
464
  ),
390
465
  /* @__PURE__ */ jsx3(
@@ -1,6 +1,6 @@
1
1
  import { SQLWrapper, InferSelectModel } from 'drizzle-orm';
2
- import { TableRepository, ColumnOf } from './repository.mjs';
3
2
  import { PgTableWithColumns } from 'drizzle-orm/pg-core';
3
+ import { TableRepository, ColumnOf } from './repository.mjs';
4
4
  import 'drizzle-orm/node-postgres';
5
5
 
6
6
  type TableOptions<T extends PgTableWithColumns<any>> = {
@@ -8,6 +8,9 @@ type TableOptions<T extends PgTableWithColumns<any>> = {
8
8
  searchKey?: ColumnOf<T>;
9
9
  defaultOrderBy: keyof InferSelectModel<T>;
10
10
  defaultDirection: "asc" | "desc";
11
+ filters?: {
12
+ [key in keyof InferSelectModel<T>]?: "auto";
13
+ };
11
14
  };
12
15
  type TableLoaderOptions<T extends PgTableWithColumns<any>, TSelect> = {
13
16
  repository: TableRepository<T, TSelect>;
@@ -25,6 +28,9 @@ declare function loadTable<T extends PgTableWithColumns<any>, TSelect>({ request
25
28
  orderBy: keyof T["_"]["columns"] & string;
26
29
  direction: "asc" | "desc";
27
30
  searchKey: ColumnOf<T> | undefined;
31
+ filters: {
32
+ [k: string]: unknown[];
33
+ };
28
34
  }>;
29
35
 
30
36
  export { type TableLoaderOptions, loadTable };
@@ -1,6 +1,6 @@
1
1
  import { SQLWrapper, InferSelectModel } from 'drizzle-orm';
2
- import { TableRepository, ColumnOf } from './repository.js';
3
2
  import { PgTableWithColumns } from 'drizzle-orm/pg-core';
3
+ import { TableRepository, ColumnOf } from './repository.js';
4
4
  import 'drizzle-orm/node-postgres';
5
5
 
6
6
  type TableOptions<T extends PgTableWithColumns<any>> = {
@@ -8,6 +8,9 @@ type TableOptions<T extends PgTableWithColumns<any>> = {
8
8
  searchKey?: ColumnOf<T>;
9
9
  defaultOrderBy: keyof InferSelectModel<T>;
10
10
  defaultDirection: "asc" | "desc";
11
+ filters?: {
12
+ [key in keyof InferSelectModel<T>]?: "auto";
13
+ };
11
14
  };
12
15
  type TableLoaderOptions<T extends PgTableWithColumns<any>, TSelect> = {
13
16
  repository: TableRepository<T, TSelect>;
@@ -25,6 +28,9 @@ declare function loadTable<T extends PgTableWithColumns<any>, TSelect>({ request
25
28
  orderBy: keyof T["_"]["columns"] & string;
26
29
  direction: "asc" | "desc";
27
30
  searchKey: ColumnOf<T> | undefined;
31
+ filters: {
32
+ [k: string]: unknown[];
33
+ };
28
34
  }>;
29
35
 
30
36
  export { type TableLoaderOptions, loadTable };
@@ -36,11 +36,22 @@ async function loadTable({
36
36
  const offset = Number(searchParams.get("offset") ?? "0");
37
37
  const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
38
38
  const direction = searchParams.get("direction") ?? defaultDirection;
39
+ const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
40
+ const param = searchParams.get(key);
41
+ if (param) {
42
+ return (0, import_drizzle_orm.eq)(
43
+ repository.schema[key],
44
+ decodeURIComponent(param)
45
+ );
46
+ }
47
+ return void 0;
48
+ }).filter(Boolean);
39
49
  const whereClauses = (0, import_drizzle_orm.and)(
40
50
  searchKey && query ? (0, import_drizzle_orm.ilike)(
41
51
  repository.schema[searchKey],
42
52
  `%${query}%`
43
53
  ) : void 0,
54
+ ...filterWhere,
44
55
  ...where ?? []
45
56
  );
46
57
  const total = await repository.countTotal({ where: whereClauses });
@@ -51,6 +62,14 @@ async function loadTable({
51
62
  offset,
52
63
  where: whereClauses
53
64
  });
65
+ const filters = Object.fromEntries(
66
+ await Promise.all(
67
+ Object.keys(options.filters ?? {}).map(async (key) => {
68
+ const values = await repository.select(key);
69
+ return [key, values.filter(Boolean)];
70
+ })
71
+ )
72
+ );
54
73
  return {
55
74
  items,
56
75
  total,
@@ -58,7 +77,8 @@ async function loadTable({
58
77
  offset,
59
78
  orderBy,
60
79
  direction,
61
- searchKey
80
+ searchKey,
81
+ filters
62
82
  };
63
83
  }
64
84
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,6 +1,7 @@
1
1
  // src/table/load_table.tsx
2
2
  import {
3
3
  and,
4
+ eq,
4
5
  ilike
5
6
  } from "drizzle-orm";
6
7
  async function loadTable({
@@ -15,11 +16,22 @@ async function loadTable({
15
16
  const offset = Number(searchParams.get("offset") ?? "0");
16
17
  const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
17
18
  const direction = searchParams.get("direction") ?? defaultDirection;
19
+ const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
20
+ const param = searchParams.get(key);
21
+ if (param) {
22
+ return eq(
23
+ repository.schema[key],
24
+ decodeURIComponent(param)
25
+ );
26
+ }
27
+ return void 0;
28
+ }).filter(Boolean);
18
29
  const whereClauses = and(
19
30
  searchKey && query ? ilike(
20
31
  repository.schema[searchKey],
21
32
  `%${query}%`
22
33
  ) : void 0,
34
+ ...filterWhere,
23
35
  ...where ?? []
24
36
  );
25
37
  const total = await repository.countTotal({ where: whereClauses });
@@ -30,6 +42,14 @@ async function loadTable({
30
42
  offset,
31
43
  where: whereClauses
32
44
  });
45
+ const filters = Object.fromEntries(
46
+ await Promise.all(
47
+ Object.keys(options.filters ?? {}).map(async (key) => {
48
+ const values = await repository.select(key);
49
+ return [key, values.filter(Boolean)];
50
+ })
51
+ )
52
+ );
33
53
  return {
34
54
  items,
35
55
  total,
@@ -37,7 +57,8 @@ async function loadTable({
37
57
  offset,
38
58
  orderBy,
39
59
  direction,
40
- searchKey
60
+ searchKey,
61
+ filters
41
62
  };
42
63
  }
43
64
  export {
@@ -14,6 +14,9 @@ declare function tableLoader<T extends PgTableWithColumns<any>, TSelect>({ repos
14
14
  orderBy: keyof T["_"]["columns"] & string;
15
15
  direction: "asc" | "desc";
16
16
  searchKey: ColumnOf<T> | undefined;
17
+ filters: {
18
+ [k: string]: unknown[];
19
+ };
17
20
  };
18
21
  }>;
19
22
 
@@ -14,6 +14,9 @@ declare function tableLoader<T extends PgTableWithColumns<any>, TSelect>({ repos
14
14
  orderBy: keyof T["_"]["columns"] & string;
15
15
  direction: "asc" | "desc";
16
16
  searchKey: ColumnOf<T> | undefined;
17
+ filters: {
18
+ [k: string]: unknown[];
19
+ };
17
20
  };
18
21
  }>;
19
22