next-data-kit 0.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/LICENSE +21 -0
- package/README.md +478 -0
- package/dist/client/components/data-kit-table.d.ts +29 -0
- package/dist/client/components/data-kit.d.ts +19 -0
- package/dist/client/components/index.d.ts +3 -0
- package/dist/client/components/ui/button.d.ts +14 -0
- package/dist/client/components/ui/checkbox.d.ts +5 -0
- package/dist/client/components/ui/dropdown-menu.d.ts +28 -0
- package/dist/client/components/ui/index.d.ts +9 -0
- package/dist/client/components/ui/pagination.d.ts +14 -0
- package/dist/client/components/ui/popover.d.ts +10 -0
- package/dist/client/components/ui/select.d.ts +18 -0
- package/dist/client/components/ui/switch.d.ts +5 -0
- package/dist/client/components/ui/table.d.ts +11 -0
- package/dist/client/context/index.d.ts +22 -0
- package/dist/client/hooks/index.d.ts +7 -0
- package/dist/client/hooks/useDataKit.d.ts +9 -0
- package/dist/client/hooks/usePagination.d.ts +18 -0
- package/dist/client/hooks/useSelection.d.ts +13 -0
- package/dist/client/index.d.ts +11 -0
- package/dist/client/utils/cn.d.ts +10 -0
- package/dist/client/utils/index.d.ts +60 -0
- package/dist/client.d.ts +7 -0
- package/dist/index.d.cts +652 -0
- package/dist/index.d.ts +652 -0
- package/dist/react-data-kit-DmTzxNTc.d.cts +225 -0
- package/dist/react-data-kit-DmTzxNTc.d.ts +225 -0
- package/dist/server.cjs +222 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +68 -0
- package/dist/server.d.ts +68 -0
- package/dist/server.js +216 -0
- package/dist/server.js.map +1 -0
- package/dist/types/component.d.ts +106 -0
- package/dist/types/database/mongo.d.ts +129 -0
- package/dist/types/hook.d.ts +100 -0
- package/dist/types/index.cjs +15 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +252 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.js +13 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/react-data-kit.d.ts +95 -0
- package/dist/types/selectable.d.ts +43 -0
- package/package.json +127 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-data-kit - Database Types (Mongo)
|
|
3
|
+
*
|
|
4
|
+
* MongoDB-specific types.
|
|
5
|
+
* Consolidated into a single file for simplicity.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Sort order for database queries
|
|
9
|
+
*/
|
|
10
|
+
type TSortOrder = 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending';
|
|
11
|
+
/**
|
|
12
|
+
* ObjectId placeholder type - compatible with MongoDB ObjectId.
|
|
13
|
+
*/
|
|
14
|
+
type TObjectId = {
|
|
15
|
+
toString(): string;
|
|
16
|
+
toHexString(): string;
|
|
17
|
+
equals(otherId: TObjectId | string): boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Generic document type that represents a database document with an ID.
|
|
21
|
+
*/
|
|
22
|
+
type TDocument<TId = unknown> = {
|
|
23
|
+
_id: TId;
|
|
24
|
+
createdAt?: Date;
|
|
25
|
+
updatedAt?: Date;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Mongo document base (includes common Mongo-only fields).
|
|
29
|
+
*/
|
|
30
|
+
type TMongoDocument = TDocument<string | TObjectId> & {
|
|
31
|
+
__v?: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Hydrated document type - represents a document with methods.
|
|
35
|
+
*/
|
|
36
|
+
type THydratedDocument<T, TId = unknown> = T & TDocument<TId>;
|
|
37
|
+
/**
|
|
38
|
+
* Hydrated Mongo document.
|
|
39
|
+
*/
|
|
40
|
+
type TMongoHydratedDocument<T> = T & TMongoDocument & {
|
|
41
|
+
toObject(): T;
|
|
42
|
+
toJSON(): T;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Filter operators for individual fields (Mongo subset)
|
|
46
|
+
*/
|
|
47
|
+
type TMongoFilterOperators<T> = {
|
|
48
|
+
$eq?: T;
|
|
49
|
+
$ne?: T;
|
|
50
|
+
$gt?: T;
|
|
51
|
+
$gte?: T;
|
|
52
|
+
$lt?: T;
|
|
53
|
+
$lte?: T;
|
|
54
|
+
$in?: T[];
|
|
55
|
+
$nin?: T[];
|
|
56
|
+
$exists?: boolean;
|
|
57
|
+
$all?: T extends Array<infer U> ? U[] : never;
|
|
58
|
+
$elemMatch?: T extends Array<infer U> ? TMongoFilterQuery<U> : never;
|
|
59
|
+
$size?: number;
|
|
60
|
+
$regex?: string | RegExp;
|
|
61
|
+
$options?: string;
|
|
62
|
+
$type?: string | number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Mongo root operators.
|
|
66
|
+
*/
|
|
67
|
+
type TMongoRootFilterOperators<T> = {
|
|
68
|
+
$and?: TMongoFilterQuery<T>[];
|
|
69
|
+
$or?: TMongoFilterQuery<T>[];
|
|
70
|
+
$nor?: TMongoFilterQuery<T>[];
|
|
71
|
+
$not?: TMongoFilterQuery<T>;
|
|
72
|
+
$text?: {
|
|
73
|
+
$search: string;
|
|
74
|
+
$language?: string;
|
|
75
|
+
$caseSensitive?: boolean;
|
|
76
|
+
$diacriticSensitive?: boolean;
|
|
77
|
+
};
|
|
78
|
+
$where?: string | ((this: T) => boolean);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Mongo filter query type.
|
|
82
|
+
*/
|
|
83
|
+
type TMongoFilterQuery<T> = {
|
|
84
|
+
[P in keyof T]?: T[P] | TMongoFilterOperators<T[P]>;
|
|
85
|
+
} & TMongoRootFilterOperators<T>;
|
|
86
|
+
/**
|
|
87
|
+
* Populate options for query builder.
|
|
88
|
+
*/
|
|
89
|
+
type TPopulateOptions = {
|
|
90
|
+
path: string;
|
|
91
|
+
select?: string | Record<string, 0 | 1>;
|
|
92
|
+
model?: string;
|
|
93
|
+
match?: Record<string, unknown>;
|
|
94
|
+
populate?: TPopulateOptions | TPopulateOptions[];
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Query builder for chaining query operations.
|
|
98
|
+
*/
|
|
99
|
+
type TQueryBuilder<TResult, TQueryHelpers = object> = Promise<TResult> & {
|
|
100
|
+
sort(options: Record<string, TSortOrder>): TQueryBuilder<TResult, TQueryHelpers>;
|
|
101
|
+
limit(count: number): TQueryBuilder<TResult, TQueryHelpers>;
|
|
102
|
+
skip(count: number): TQueryBuilder<TResult, TQueryHelpers>;
|
|
103
|
+
select(fields: string | Record<string, 0 | 1>): TQueryBuilder<TResult, TQueryHelpers>;
|
|
104
|
+
populate(path: string | TPopulateOptions): TQueryBuilder<TResult, TQueryHelpers>;
|
|
105
|
+
lean(): TQueryBuilder<TResult, TQueryHelpers>;
|
|
106
|
+
exec(): Promise<TResult>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Generic Model type.
|
|
110
|
+
*/
|
|
111
|
+
type TModel<TRawDocType = unknown, TQueryHelpers = object, TId = unknown, TFilter = unknown> = {
|
|
112
|
+
countDocuments(filter?: TFilter): Promise<number>;
|
|
113
|
+
find(filter?: TFilter): TQueryBuilder<TRawDocType[], TQueryHelpers>;
|
|
114
|
+
findOne(filter?: TFilter): TQueryBuilder<TRawDocType | null, TQueryHelpers>;
|
|
115
|
+
findById(id: TId): TQueryBuilder<TRawDocType | null, TQueryHelpers>;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Convenience alias for a Mongo-backed model.
|
|
119
|
+
*/
|
|
120
|
+
type TMongoModel<TRawDocType = unknown, TQueryHelpers = object> = TModel<TRawDocType, TQueryHelpers, string | TObjectId, TMongoFilterQuery<TRawDocType>>;
|
|
121
|
+
/**
|
|
122
|
+
* Extract raw document type from a Model
|
|
123
|
+
*/
|
|
124
|
+
type TExtractDocType<M> = M extends TModel<infer TRawDocType, unknown, unknown, unknown> ? TRawDocType : never;
|
|
125
|
+
/**
|
|
126
|
+
* Extract hydrated document type from a Model
|
|
127
|
+
*/
|
|
128
|
+
type TExtractHydratedDoc<M> = M extends TModel<infer TRawDocType, unknown, infer TId, unknown> ? THydratedDocument<TRawDocType, TId> : never;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* react-data-kit - React Data Kit Types
|
|
132
|
+
*
|
|
133
|
+
* Core types for the react-data-kit server action and components.
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Sort options type that references keys from the item type
|
|
138
|
+
*/
|
|
139
|
+
type TSortOptions<T> = {
|
|
140
|
+
[K in keyof T]?: TSortOrder;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Sort entry for array-based sorting
|
|
144
|
+
*/
|
|
145
|
+
type TSortEntry = {
|
|
146
|
+
path: string;
|
|
147
|
+
value: 1 | -1;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Filter configuration for automatic filtering
|
|
151
|
+
*/
|
|
152
|
+
type TFilterConfig = {
|
|
153
|
+
[key: string]: {
|
|
154
|
+
type: 'regex' | 'exact';
|
|
155
|
+
field?: string;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Custom filter configuration
|
|
160
|
+
* Allows defining custom filter functions for specific filter keys
|
|
161
|
+
*/
|
|
162
|
+
type TFilterCustomConfig<T = unknown> = {
|
|
163
|
+
[id: string]: (data: unknown) => TMongoFilterQuery<T>;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Variant of TFilterCustomConfig that allows customizing the returned filter shape.
|
|
167
|
+
* Useful for Mongo (operator-based) vs. other ORMs (where clauses) in the future.
|
|
168
|
+
*/
|
|
169
|
+
type TFilterCustomConfigWithFilter<TDoc = unknown, TFilter = TMongoFilterQuery<TDoc>> = {
|
|
170
|
+
[id: string]: (data: unknown) => TFilter;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* React Data Kit server action input
|
|
174
|
+
*/
|
|
175
|
+
type TDataKitInput<T = unknown> = {
|
|
176
|
+
action?: 'FETCH';
|
|
177
|
+
page?: number;
|
|
178
|
+
limit?: number;
|
|
179
|
+
sort?: TSortOptions<T>;
|
|
180
|
+
sorts?: TSortEntry[];
|
|
181
|
+
query?: Record<string, unknown>;
|
|
182
|
+
filter?: Record<string, unknown>;
|
|
183
|
+
filterConfig?: TFilterConfig;
|
|
184
|
+
filterCustom?: TFilterCustomConfig<T>;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* React Data Kit server action result
|
|
188
|
+
*/
|
|
189
|
+
type TDataKitResult<R> = {
|
|
190
|
+
type: 'ITEMS';
|
|
191
|
+
items: R[];
|
|
192
|
+
documentTotal: number;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Pagination info for client-side use
|
|
196
|
+
*/
|
|
197
|
+
type TPaginationInfo = {
|
|
198
|
+
currentPage: number;
|
|
199
|
+
totalPages: number;
|
|
200
|
+
totalItems: number;
|
|
201
|
+
itemsPerPage: number;
|
|
202
|
+
hasNextPage: boolean;
|
|
203
|
+
hasPrevPage: boolean;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Calculate pagination info from react-data-kit result
|
|
207
|
+
*/
|
|
208
|
+
declare const calculatePagination: (page: number, limit: number, total: number) => TPaginationInfo;
|
|
209
|
+
/**
|
|
210
|
+
* React Data Kit Adapter Interface
|
|
211
|
+
* Defines the contract for a database adapter.
|
|
212
|
+
*/
|
|
213
|
+
type TDataKitAdapter<T> = (params: Readonly<{
|
|
214
|
+
filter: Record<string, unknown>;
|
|
215
|
+
sorts: TSortEntry[];
|
|
216
|
+
limit: number;
|
|
217
|
+
page: number;
|
|
218
|
+
skip: number;
|
|
219
|
+
input: TDataKitInput<T>;
|
|
220
|
+
}>) => Promise<{
|
|
221
|
+
items: T[];
|
|
222
|
+
total: number;
|
|
223
|
+
}>;
|
|
224
|
+
|
|
225
|
+
export { type TDataKitInput as T, type TDataKitAdapter as a, type TMongoModel as b, type TMongoFilterQuery as c, type TFilterCustomConfigWithFilter as d, type TSortOptions as e, type TDataKitResult as f, type TExtractDocType as g, type TModel as h, type THydratedDocument as i, type TSortOrder as j, type TFilterCustomConfig as k, type TFilterConfig as l, type TMongoFilterOperators as m, type TMongoRootFilterOperators as n, type TObjectId as o, type TMongoDocument as p, type TMongoHydratedDocument as q, type TSortEntry as r, type TDocument as s, type TQueryBuilder as t, type TPopulateOptions as u, type TExtractHydratedDoc as v, type TPaginationInfo as w, calculatePagination as x };
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* react-data-kit - Database Types (Mongo)
|
|
3
|
+
*
|
|
4
|
+
* MongoDB-specific types.
|
|
5
|
+
* Consolidated into a single file for simplicity.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Sort order for database queries
|
|
9
|
+
*/
|
|
10
|
+
type TSortOrder = 1 | -1 | 'asc' | 'desc' | 'ascending' | 'descending';
|
|
11
|
+
/**
|
|
12
|
+
* ObjectId placeholder type - compatible with MongoDB ObjectId.
|
|
13
|
+
*/
|
|
14
|
+
type TObjectId = {
|
|
15
|
+
toString(): string;
|
|
16
|
+
toHexString(): string;
|
|
17
|
+
equals(otherId: TObjectId | string): boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Generic document type that represents a database document with an ID.
|
|
21
|
+
*/
|
|
22
|
+
type TDocument<TId = unknown> = {
|
|
23
|
+
_id: TId;
|
|
24
|
+
createdAt?: Date;
|
|
25
|
+
updatedAt?: Date;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Mongo document base (includes common Mongo-only fields).
|
|
29
|
+
*/
|
|
30
|
+
type TMongoDocument = TDocument<string | TObjectId> & {
|
|
31
|
+
__v?: number;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Hydrated document type - represents a document with methods.
|
|
35
|
+
*/
|
|
36
|
+
type THydratedDocument<T, TId = unknown> = T & TDocument<TId>;
|
|
37
|
+
/**
|
|
38
|
+
* Hydrated Mongo document.
|
|
39
|
+
*/
|
|
40
|
+
type TMongoHydratedDocument<T> = T & TMongoDocument & {
|
|
41
|
+
toObject(): T;
|
|
42
|
+
toJSON(): T;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Filter operators for individual fields (Mongo subset)
|
|
46
|
+
*/
|
|
47
|
+
type TMongoFilterOperators<T> = {
|
|
48
|
+
$eq?: T;
|
|
49
|
+
$ne?: T;
|
|
50
|
+
$gt?: T;
|
|
51
|
+
$gte?: T;
|
|
52
|
+
$lt?: T;
|
|
53
|
+
$lte?: T;
|
|
54
|
+
$in?: T[];
|
|
55
|
+
$nin?: T[];
|
|
56
|
+
$exists?: boolean;
|
|
57
|
+
$all?: T extends Array<infer U> ? U[] : never;
|
|
58
|
+
$elemMatch?: T extends Array<infer U> ? TMongoFilterQuery<U> : never;
|
|
59
|
+
$size?: number;
|
|
60
|
+
$regex?: string | RegExp;
|
|
61
|
+
$options?: string;
|
|
62
|
+
$type?: string | number;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Mongo root operators.
|
|
66
|
+
*/
|
|
67
|
+
type TMongoRootFilterOperators<T> = {
|
|
68
|
+
$and?: TMongoFilterQuery<T>[];
|
|
69
|
+
$or?: TMongoFilterQuery<T>[];
|
|
70
|
+
$nor?: TMongoFilterQuery<T>[];
|
|
71
|
+
$not?: TMongoFilterQuery<T>;
|
|
72
|
+
$text?: {
|
|
73
|
+
$search: string;
|
|
74
|
+
$language?: string;
|
|
75
|
+
$caseSensitive?: boolean;
|
|
76
|
+
$diacriticSensitive?: boolean;
|
|
77
|
+
};
|
|
78
|
+
$where?: string | ((this: T) => boolean);
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Mongo filter query type.
|
|
82
|
+
*/
|
|
83
|
+
type TMongoFilterQuery<T> = {
|
|
84
|
+
[P in keyof T]?: T[P] | TMongoFilterOperators<T[P]>;
|
|
85
|
+
} & TMongoRootFilterOperators<T>;
|
|
86
|
+
/**
|
|
87
|
+
* Populate options for query builder.
|
|
88
|
+
*/
|
|
89
|
+
type TPopulateOptions = {
|
|
90
|
+
path: string;
|
|
91
|
+
select?: string | Record<string, 0 | 1>;
|
|
92
|
+
model?: string;
|
|
93
|
+
match?: Record<string, unknown>;
|
|
94
|
+
populate?: TPopulateOptions | TPopulateOptions[];
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Query builder for chaining query operations.
|
|
98
|
+
*/
|
|
99
|
+
type TQueryBuilder<TResult, TQueryHelpers = object> = Promise<TResult> & {
|
|
100
|
+
sort(options: Record<string, TSortOrder>): TQueryBuilder<TResult, TQueryHelpers>;
|
|
101
|
+
limit(count: number): TQueryBuilder<TResult, TQueryHelpers>;
|
|
102
|
+
skip(count: number): TQueryBuilder<TResult, TQueryHelpers>;
|
|
103
|
+
select(fields: string | Record<string, 0 | 1>): TQueryBuilder<TResult, TQueryHelpers>;
|
|
104
|
+
populate(path: string | TPopulateOptions): TQueryBuilder<TResult, TQueryHelpers>;
|
|
105
|
+
lean(): TQueryBuilder<TResult, TQueryHelpers>;
|
|
106
|
+
exec(): Promise<TResult>;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Generic Model type.
|
|
110
|
+
*/
|
|
111
|
+
type TModel<TRawDocType = unknown, TQueryHelpers = object, TId = unknown, TFilter = unknown> = {
|
|
112
|
+
countDocuments(filter?: TFilter): Promise<number>;
|
|
113
|
+
find(filter?: TFilter): TQueryBuilder<TRawDocType[], TQueryHelpers>;
|
|
114
|
+
findOne(filter?: TFilter): TQueryBuilder<TRawDocType | null, TQueryHelpers>;
|
|
115
|
+
findById(id: TId): TQueryBuilder<TRawDocType | null, TQueryHelpers>;
|
|
116
|
+
};
|
|
117
|
+
/**
|
|
118
|
+
* Convenience alias for a Mongo-backed model.
|
|
119
|
+
*/
|
|
120
|
+
type TMongoModel<TRawDocType = unknown, TQueryHelpers = object> = TModel<TRawDocType, TQueryHelpers, string | TObjectId, TMongoFilterQuery<TRawDocType>>;
|
|
121
|
+
/**
|
|
122
|
+
* Extract raw document type from a Model
|
|
123
|
+
*/
|
|
124
|
+
type TExtractDocType<M> = M extends TModel<infer TRawDocType, unknown, unknown, unknown> ? TRawDocType : never;
|
|
125
|
+
/**
|
|
126
|
+
* Extract hydrated document type from a Model
|
|
127
|
+
*/
|
|
128
|
+
type TExtractHydratedDoc<M> = M extends TModel<infer TRawDocType, unknown, infer TId, unknown> ? THydratedDocument<TRawDocType, TId> : never;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* react-data-kit - React Data Kit Types
|
|
132
|
+
*
|
|
133
|
+
* Core types for the react-data-kit server action and components.
|
|
134
|
+
*/
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Sort options type that references keys from the item type
|
|
138
|
+
*/
|
|
139
|
+
type TSortOptions<T> = {
|
|
140
|
+
[K in keyof T]?: TSortOrder;
|
|
141
|
+
};
|
|
142
|
+
/**
|
|
143
|
+
* Sort entry for array-based sorting
|
|
144
|
+
*/
|
|
145
|
+
type TSortEntry = {
|
|
146
|
+
path: string;
|
|
147
|
+
value: 1 | -1;
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Filter configuration for automatic filtering
|
|
151
|
+
*/
|
|
152
|
+
type TFilterConfig = {
|
|
153
|
+
[key: string]: {
|
|
154
|
+
type: 'regex' | 'exact';
|
|
155
|
+
field?: string;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Custom filter configuration
|
|
160
|
+
* Allows defining custom filter functions for specific filter keys
|
|
161
|
+
*/
|
|
162
|
+
type TFilterCustomConfig<T = unknown> = {
|
|
163
|
+
[id: string]: (data: unknown) => TMongoFilterQuery<T>;
|
|
164
|
+
};
|
|
165
|
+
/**
|
|
166
|
+
* Variant of TFilterCustomConfig that allows customizing the returned filter shape.
|
|
167
|
+
* Useful for Mongo (operator-based) vs. other ORMs (where clauses) in the future.
|
|
168
|
+
*/
|
|
169
|
+
type TFilterCustomConfigWithFilter<TDoc = unknown, TFilter = TMongoFilterQuery<TDoc>> = {
|
|
170
|
+
[id: string]: (data: unknown) => TFilter;
|
|
171
|
+
};
|
|
172
|
+
/**
|
|
173
|
+
* React Data Kit server action input
|
|
174
|
+
*/
|
|
175
|
+
type TDataKitInput<T = unknown> = {
|
|
176
|
+
action?: 'FETCH';
|
|
177
|
+
page?: number;
|
|
178
|
+
limit?: number;
|
|
179
|
+
sort?: TSortOptions<T>;
|
|
180
|
+
sorts?: TSortEntry[];
|
|
181
|
+
query?: Record<string, unknown>;
|
|
182
|
+
filter?: Record<string, unknown>;
|
|
183
|
+
filterConfig?: TFilterConfig;
|
|
184
|
+
filterCustom?: TFilterCustomConfig<T>;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* React Data Kit server action result
|
|
188
|
+
*/
|
|
189
|
+
type TDataKitResult<R> = {
|
|
190
|
+
type: 'ITEMS';
|
|
191
|
+
items: R[];
|
|
192
|
+
documentTotal: number;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Pagination info for client-side use
|
|
196
|
+
*/
|
|
197
|
+
type TPaginationInfo = {
|
|
198
|
+
currentPage: number;
|
|
199
|
+
totalPages: number;
|
|
200
|
+
totalItems: number;
|
|
201
|
+
itemsPerPage: number;
|
|
202
|
+
hasNextPage: boolean;
|
|
203
|
+
hasPrevPage: boolean;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Calculate pagination info from react-data-kit result
|
|
207
|
+
*/
|
|
208
|
+
declare const calculatePagination: (page: number, limit: number, total: number) => TPaginationInfo;
|
|
209
|
+
/**
|
|
210
|
+
* React Data Kit Adapter Interface
|
|
211
|
+
* Defines the contract for a database adapter.
|
|
212
|
+
*/
|
|
213
|
+
type TDataKitAdapter<T> = (params: Readonly<{
|
|
214
|
+
filter: Record<string, unknown>;
|
|
215
|
+
sorts: TSortEntry[];
|
|
216
|
+
limit: number;
|
|
217
|
+
page: number;
|
|
218
|
+
skip: number;
|
|
219
|
+
input: TDataKitInput<T>;
|
|
220
|
+
}>) => Promise<{
|
|
221
|
+
items: T[];
|
|
222
|
+
total: number;
|
|
223
|
+
}>;
|
|
224
|
+
|
|
225
|
+
export { type TDataKitInput as T, type TDataKitAdapter as a, type TMongoModel as b, type TMongoFilterQuery as c, type TFilterCustomConfigWithFilter as d, type TSortOptions as e, type TDataKitResult as f, type TExtractDocType as g, type TModel as h, type THydratedDocument as i, type TSortOrder as j, type TFilterCustomConfig as k, type TFilterConfig as l, type TMongoFilterOperators as m, type TMongoRootFilterOperators as n, type TObjectId as o, type TMongoDocument as p, type TMongoHydratedDocument as q, type TSortEntry as r, type TDocument as s, type TQueryBuilder as t, type TPopulateOptions as u, type TExtractHydratedDoc as v, type TPaginationInfo as w, calculatePagination as x };
|
package/dist/server.cjs
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/server/adapters/mongoose.ts
|
|
4
|
+
var isProvided = (value) => value !== void 0 && value !== null && value !== "";
|
|
5
|
+
var mongooseAdapter = (model, options = {}) => {
|
|
6
|
+
const { filter: customFilterFn, filterCustom, defaultSort = { _id: -1 } } = options;
|
|
7
|
+
return async ({ filter, sorts, limit, skip, input }) => {
|
|
8
|
+
let sortOption;
|
|
9
|
+
if (input.sort && Object.keys(input.sort).length > 0) {
|
|
10
|
+
sortOption = input.sort;
|
|
11
|
+
} else if (sorts && sorts.length > 0) {
|
|
12
|
+
sortOption = sorts.reduce((acc, s) => {
|
|
13
|
+
if (s?.path && (s.value === 1 || s.value === -1)) {
|
|
14
|
+
acc[s.path] = s.value;
|
|
15
|
+
}
|
|
16
|
+
return acc;
|
|
17
|
+
}, {});
|
|
18
|
+
} else {
|
|
19
|
+
sortOption = defaultSort;
|
|
20
|
+
}
|
|
21
|
+
let filterQuery = {};
|
|
22
|
+
if (input.query) {
|
|
23
|
+
Object.entries(input.query).forEach(([key, value]) => {
|
|
24
|
+
if (isProvided(value)) {
|
|
25
|
+
filterQuery[key] = value;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (customFilterFn) {
|
|
30
|
+
const customQuery = customFilterFn(filter);
|
|
31
|
+
filterQuery = { ...filterQuery, ...customQuery };
|
|
32
|
+
}
|
|
33
|
+
if (filter && !customFilterFn) {
|
|
34
|
+
if (input.filterConfig) {
|
|
35
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
36
|
+
if (isProvided(value) && input.filterConfig?.[key]) {
|
|
37
|
+
const config = input.filterConfig[key];
|
|
38
|
+
const fieldName = config?.field ?? key;
|
|
39
|
+
if (config?.type === "regex") {
|
|
40
|
+
filterQuery[fieldName] = {
|
|
41
|
+
$regex: value,
|
|
42
|
+
$options: "i"
|
|
43
|
+
};
|
|
44
|
+
} else if (config?.type === "exact") {
|
|
45
|
+
filterQuery[fieldName] = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
} else {
|
|
50
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
51
|
+
if (isProvided(value)) {
|
|
52
|
+
if (typeof value === "string") {
|
|
53
|
+
filterQuery[key] = {
|
|
54
|
+
$regex: value,
|
|
55
|
+
$options: "i"
|
|
56
|
+
};
|
|
57
|
+
} else {
|
|
58
|
+
filterQuery[key] = value;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (filterCustom && filter) {
|
|
65
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
66
|
+
if (isProvided(value) && filterCustom[key]) {
|
|
67
|
+
const customFilter = filterCustom[key](value);
|
|
68
|
+
filterQuery = { ...filterQuery, ...customFilter };
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const total = await model.countDocuments(filterQuery);
|
|
73
|
+
const items = await model.find(filterQuery).sort(sortOption).limit(limit).skip(skip);
|
|
74
|
+
return { items, total };
|
|
75
|
+
};
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/server/action.ts
|
|
79
|
+
var dataKitServerAction = async (props) => {
|
|
80
|
+
const { input, adapter, item, filter, filterCustom, defaultSort } = props;
|
|
81
|
+
const finalAdapter = typeof adapter === "function" ? adapter : mongooseAdapter(adapter, {
|
|
82
|
+
filter,
|
|
83
|
+
filterCustom,
|
|
84
|
+
defaultSort
|
|
85
|
+
});
|
|
86
|
+
switch (input.action ?? "FETCH") {
|
|
87
|
+
case "FETCH": {
|
|
88
|
+
if (!input.limit || !input.page) {
|
|
89
|
+
throw new Error("Invalid input: missing limit or page");
|
|
90
|
+
}
|
|
91
|
+
const limit = input.limit;
|
|
92
|
+
const skip = limit * (input.page - 1);
|
|
93
|
+
const { items, total } = await finalAdapter({
|
|
94
|
+
filter: input.filter ?? {},
|
|
95
|
+
sorts: input.sorts ?? [],
|
|
96
|
+
limit,
|
|
97
|
+
page: input.page,
|
|
98
|
+
skip,
|
|
99
|
+
input
|
|
100
|
+
});
|
|
101
|
+
const processedItems = await Promise.all(items.map((dataItem) => item(dataItem)));
|
|
102
|
+
return {
|
|
103
|
+
type: "ITEMS",
|
|
104
|
+
items: processedItems,
|
|
105
|
+
documentTotal: total
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
default:
|
|
109
|
+
throw new Error(`Unsupported action: ${input.action}`);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// src/server/adapters/memory.ts
|
|
114
|
+
var isProvided2 = (value) => value !== void 0 && value !== null && value !== "";
|
|
115
|
+
var getValueByPath = (obj, path) => {
|
|
116
|
+
if (!path) return void 0;
|
|
117
|
+
const parts = path.split(".");
|
|
118
|
+
let current = obj;
|
|
119
|
+
for (const part of parts) {
|
|
120
|
+
if (current && typeof current === "object" && part in current) {
|
|
121
|
+
current = current[part];
|
|
122
|
+
} else {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return current;
|
|
127
|
+
};
|
|
128
|
+
var matchesExact = (rowValue, needle) => {
|
|
129
|
+
if (Array.isArray(needle)) return needle.includes(rowValue);
|
|
130
|
+
return rowValue === needle;
|
|
131
|
+
};
|
|
132
|
+
var matchesRegexLike = (rowValue, needle) => {
|
|
133
|
+
if (!isProvided2(needle)) return true;
|
|
134
|
+
if (rowValue === void 0 || rowValue === null) return false;
|
|
135
|
+
const hay = String(rowValue);
|
|
136
|
+
if (needle instanceof RegExp) return needle.test(hay);
|
|
137
|
+
const n = String(needle);
|
|
138
|
+
return hay.toLowerCase().includes(n.toLowerCase());
|
|
139
|
+
};
|
|
140
|
+
var compareValues = (a, b) => {
|
|
141
|
+
if (a === b) return 0;
|
|
142
|
+
if (a === void 0 || a === null) return -1;
|
|
143
|
+
if (b === void 0 || b === null) return 1;
|
|
144
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
145
|
+
if (typeof a === "bigint" && typeof b === "bigint") return a < b ? -1 : 1;
|
|
146
|
+
const as = String(a);
|
|
147
|
+
const bs = String(b);
|
|
148
|
+
return as.localeCompare(bs);
|
|
149
|
+
};
|
|
150
|
+
var normalizeSorts = (sorts) => Array.isArray(sorts) ? sorts.filter((s) => !!s?.path && (s.value === 1 || s.value === -1)) : [];
|
|
151
|
+
var adapterMemory = (dataset, options = {}) => {
|
|
152
|
+
const { defaultFilterType = "exact" } = options;
|
|
153
|
+
return async ({ filter, sorts, limit, skip, input }) => {
|
|
154
|
+
const filterConfig = input.filterConfig;
|
|
155
|
+
const query = input.query ?? {};
|
|
156
|
+
let rows = dataset.filter((row) => {
|
|
157
|
+
for (const [key, value] of Object.entries(query)) {
|
|
158
|
+
if (!isProvided2(value)) continue;
|
|
159
|
+
const rowValue = getValueByPath(row, key);
|
|
160
|
+
if (!matchesExact(rowValue, value)) return false;
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
});
|
|
164
|
+
const effectiveFilter = filter ?? {};
|
|
165
|
+
rows = rows.filter((row) => {
|
|
166
|
+
for (const [key, value] of Object.entries(effectiveFilter)) {
|
|
167
|
+
if (!isProvided2(value)) continue;
|
|
168
|
+
const config = filterConfig?.[key];
|
|
169
|
+
const field = config?.field ?? key;
|
|
170
|
+
const rowValue = getValueByPath(row, field);
|
|
171
|
+
const type = config?.type ?? defaultFilterType;
|
|
172
|
+
if (type === "regex") {
|
|
173
|
+
if (!matchesRegexLike(rowValue, value)) return false;
|
|
174
|
+
} else {
|
|
175
|
+
if (!matchesExact(rowValue, value)) return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
});
|
|
180
|
+
const normalizedSorts = normalizeSorts(sorts);
|
|
181
|
+
if (normalizedSorts.length > 0) {
|
|
182
|
+
rows = [...rows].sort((ra, rb) => {
|
|
183
|
+
for (const s of normalizedSorts) {
|
|
184
|
+
const av = getValueByPath(ra, s.path);
|
|
185
|
+
const bv = getValueByPath(rb, s.path);
|
|
186
|
+
const cmp = compareValues(av, bv);
|
|
187
|
+
if (cmp !== 0) return s.value === 1 ? cmp : -cmp;
|
|
188
|
+
}
|
|
189
|
+
return 0;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const total = rows.length;
|
|
193
|
+
const items = rows.slice(skip, skip + limit);
|
|
194
|
+
return { items, total };
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/server/utils.ts
|
|
199
|
+
var escapeRegex = (str) => {
|
|
200
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
201
|
+
};
|
|
202
|
+
var createSearchFilter = (fields) => {
|
|
203
|
+
return (value) => {
|
|
204
|
+
if (!value || typeof value !== "string") {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
const escapedValue = escapeRegex(value);
|
|
208
|
+
return {
|
|
209
|
+
$or: fields.map((field) => ({
|
|
210
|
+
[field]: { $regex: escapedValue, $options: "i" }
|
|
211
|
+
}))
|
|
212
|
+
};
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
exports.adapterMemory = adapterMemory;
|
|
217
|
+
exports.createSearchFilter = createSearchFilter;
|
|
218
|
+
exports.dataKitServerAction = dataKitServerAction;
|
|
219
|
+
exports.escapeRegex = escapeRegex;
|
|
220
|
+
exports.mongooseAdapter = mongooseAdapter;
|
|
221
|
+
//# sourceMappingURL=server.cjs.map
|
|
222
|
+
//# sourceMappingURL=server.cjs.map
|