@carbonorm/carbonnode 3.0.0 → 3.0.2
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/dist/api/builders/sqlBuilder.d.ts +3 -0
- package/dist/api/convertForRequestBody.d.ts +1 -1
- package/dist/api/executors/Executor.d.ts +16 -0
- package/dist/api/executors/HttpExecutor.d.ts +13 -0
- package/dist/api/executors/SqlExecutor.d.ts +19 -0
- package/dist/api/restRequest.d.ts +9 -166
- package/dist/api/types/dynamicFetching.d.ts +10 -0
- package/dist/api/types/modifyTypes.d.ts +9 -0
- package/dist/api/types/mysqlTypes.d.ts +4 -0
- package/dist/api/types/ormInterfaces.d.ts +219 -0
- package/dist/api/utils/apiHelpers.d.ts +9 -0
- package/dist/api/utils/cacheManager.d.ts +10 -0
- package/dist/api/utils/determineRuntimeJsType.d.ts +5 -0
- package/dist/api/utils/logger.d.ts +7 -0
- package/dist/api/utils/sortAndSerializeQueryObject.d.ts +1 -0
- package/dist/api/utils/testHelpers.d.ts +1 -0
- package/dist/api/utils/toastNotifier.d.ts +2 -0
- package/dist/index.cjs.js +665 -614
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.esm.js +655 -618
- package/dist/index.esm.js.map +1 -1
- package/package.json +22 -6
- package/scripts/assets/handlebars/C6.ts.handlebars +13 -5
- package/scripts/assets/handlebars/Table.ts.handlebars +44 -12
- package/scripts/generateRestBindings.cjs +1 -1
- package/scripts/generateRestBindings.ts +1 -1
- package/src/api/builders/sqlBuilder.ts +173 -0
- package/src/api/convertForRequestBody.ts +2 -3
- package/src/api/executors/Executor.ts +28 -0
- package/src/api/executors/HttpExecutor.ts +794 -0
- package/src/api/executors/SqlExecutor.ts +104 -0
- package/src/api/restRequest.ts +50 -1287
- package/src/api/types/dynamicFetching.ts +10 -0
- package/src/api/types/modifyTypes.ts +25 -0
- package/src/api/types/mysqlTypes.ts +33 -0
- package/src/api/types/ormInterfaces.ts +310 -0
- package/src/api/utils/apiHelpers.ts +82 -0
- package/src/api/utils/cacheManager.ts +67 -0
- package/src/api/utils/determineRuntimeJsType.ts +46 -0
- package/src/api/utils/logger.ts +24 -0
- package/src/api/utils/sortAndSerializeQueryObject.ts +12 -0
- package/src/api/utils/testHelpers.ts +24 -0
- package/src/api/utils/toastNotifier.ts +11 -0
- package/src/index.ts +15 -2
- package/src/api/carbonSqlExecutor.ts +0 -279
- package/src/api/interfaces/ormInterfaces.ts +0 -87
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// if you can get away with modify over modifyDeep, use modify. The editor will be happier.
|
|
2
|
+
export type Modify<T, R> = Omit<T, keyof R> & R;
|
|
3
|
+
|
|
4
|
+
// @link https://stackoverflow.com/questions/41285211/overriding-interface-property-type-defined-in-typescript-d-ts-file/55032655#55032655
|
|
5
|
+
export type ModifyDeep<A, B extends DeepPartialAny<A>> = {
|
|
6
|
+
[K in keyof A | keyof B]?: // For all keys in A and B:
|
|
7
|
+
K extends keyof A // ───┐
|
|
8
|
+
? K extends keyof B // ───┼─ key K exists in both A and B
|
|
9
|
+
? A[K] extends AnyObject // │ ┴──┐
|
|
10
|
+
? B[K] extends AnyObject // │ ───┼─ both A and B are objects
|
|
11
|
+
? ModifyDeep<A[K], B[K]> // │ │ └─── We need to go deeper (recursively)
|
|
12
|
+
: B[K] // │ ├─ B is a primitive 🠆 use B as the final type (new type)
|
|
13
|
+
: B[K] // │ └─ A is a primitive 🠆 use B as the final type (new type)
|
|
14
|
+
: A[K] // ├─ key only exists in A 🠆 use A as the final type (original type)
|
|
15
|
+
: B[K] // └─ key only exists in B 🠆 use B as the final type (new type)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type AnyObject = Record<string, any>
|
|
19
|
+
|
|
20
|
+
// This type is here only for some intellisense for the overrides object
|
|
21
|
+
type DeepPartialAny<T> = {
|
|
22
|
+
/** Makes each property optional and turns each leaf property into any, allowing for type overrides by narrowing any. */
|
|
23
|
+
[P in keyof T]?: T[P] extends AnyObject ? DeepPartialAny<T[P]> : any
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
// ========================
|
|
3
|
+
// 🔧 SQL Operator & Helpers
|
|
4
|
+
// ========================
|
|
5
|
+
|
|
6
|
+
export type SQLFunction =
|
|
7
|
+
| 'COUNT'
|
|
8
|
+
| 'GROUP_CONCAT'
|
|
9
|
+
| 'MAX'
|
|
10
|
+
| 'MIN'
|
|
11
|
+
| 'SUM'
|
|
12
|
+
| 'DISTINCT';
|
|
13
|
+
|
|
14
|
+
export type SQLComparisonOperator =
|
|
15
|
+
| '='
|
|
16
|
+
| '!='
|
|
17
|
+
| '<'
|
|
18
|
+
| '<='
|
|
19
|
+
| '>'
|
|
20
|
+
| '>='
|
|
21
|
+
| 'IN'
|
|
22
|
+
| 'NOT IN'
|
|
23
|
+
| 'LIKE'
|
|
24
|
+
| 'IS NULL'
|
|
25
|
+
| 'IS NOT NULL'
|
|
26
|
+
| 'BETWEEN'
|
|
27
|
+
| 'LESS_THAN'
|
|
28
|
+
| 'GREATER_THAN';
|
|
29
|
+
|
|
30
|
+
export type JoinType = 'INNER' | 'LEFT_OUTER' | 'RIGHT_OUTER';
|
|
31
|
+
|
|
32
|
+
export type OrderDirection = 'ASC' | 'DESC';
|
|
33
|
+
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import {AxiosInstance, AxiosPromise, AxiosResponse} from "axios";
|
|
2
|
+
import {Pool} from "mysql2/promise";
|
|
3
|
+
import {eFetchDependencies} from "./dynamicFetching";
|
|
4
|
+
import {Modify} from "./modifyTypes";
|
|
5
|
+
import {JoinType, OrderDirection, SQLComparisonOperator, SQLFunction} from "./mysqlTypes";
|
|
6
|
+
|
|
7
|
+
export interface stringMap {
|
|
8
|
+
[key: string]: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface stringNumberMap {
|
|
12
|
+
[key: string]: string | number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RegExpMap {
|
|
16
|
+
[key: string]: RegExp | RegExpMap;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface complexMap {
|
|
20
|
+
[key: string]: stringMap | stringNumberMap | stringMap[] | RegExpMap;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface iTypeValidation {
|
|
24
|
+
MYSQL_TYPE: string,
|
|
25
|
+
MAX_LENGTH: string,
|
|
26
|
+
AUTO_INCREMENT: boolean,
|
|
27
|
+
SKIP_COLUMN_IN_POST: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type iRestReactiveLifecycle<T extends RequestGetPutDeleteBody> = {
|
|
31
|
+
beforeProcessing?: (args: { request: T[]; requestMeta?: any }) => void | Promise<void>;
|
|
32
|
+
beforeExecution?: (args: { request: T[]; requestMeta?: any }) => void | Promise<void>;
|
|
33
|
+
afterExecution?: (args: { response: T[]; request: T[]; responseMeta?: any }) => void | Promise<void>;
|
|
34
|
+
afterCommit?: (args: { response: T[]; request: T[]; responseMeta?: any }) => void | Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export interface iConstraint {
|
|
38
|
+
TABLE: string,
|
|
39
|
+
COLUMN: string,
|
|
40
|
+
CONSTRAINT: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// This maps full column names to short column keys
|
|
44
|
+
export type tColumns<
|
|
45
|
+
TableName extends string,
|
|
46
|
+
T extends { [key: string]: any }
|
|
47
|
+
> = {
|
|
48
|
+
[K in keyof T & string as `${TableName}.${K}`]: K;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type tPrimaryKeys<
|
|
52
|
+
TableName extends string,
|
|
53
|
+
PK extends string
|
|
54
|
+
> = `${TableName}.${PK}`;
|
|
55
|
+
|
|
56
|
+
export interface iC6RestfulModel<
|
|
57
|
+
RestShortTableNames extends string,
|
|
58
|
+
RestTableInterfaces extends { [key: string]: any },
|
|
59
|
+
PK extends keyof RestTableInterfaces & string,
|
|
60
|
+
> {
|
|
61
|
+
TABLE_NAME: RestShortTableNames;
|
|
62
|
+
PRIMARY: tPrimaryKeys<RestShortTableNames, PK>[];
|
|
63
|
+
PRIMARY_SHORT: PK[];
|
|
64
|
+
COLUMNS: tColumns<RestShortTableNames, RestTableInterfaces>;
|
|
65
|
+
TYPE_VALIDATION: { [key: string]: iTypeValidation };
|
|
66
|
+
REGEX_VALIDATION: RegExpMap;
|
|
67
|
+
LIFECYCLE_HOOKS: iRestReactiveLifecycle<RequestGetPutDeleteBody>[];
|
|
68
|
+
TABLE_REFERENCES: { [columnName: string]: iConstraint[] };
|
|
69
|
+
TABLE_REFERENCED_BY: { [columnName: string]: iConstraint[] };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface iRestApiFunctions<RestData = any> {
|
|
73
|
+
Delete: (request?: (iAPI<any> & any)) => apiReturn<iDeleteC6RestResponse<RestData>>;
|
|
74
|
+
Post: (request?: (iAPI<any> & any)) => apiReturn<iPostC6RestResponse<RestData>>;
|
|
75
|
+
Get: (request?: (iAPI<any> & any)) => apiReturn<iGetC6RestResponse<RestData>>;
|
|
76
|
+
Put: (request?: (iAPI<any> & any)) => apiReturn<iPutC6RestResponse<RestData>>,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface iDynamicApiImport<RestData = any> {
|
|
80
|
+
default: iRestApiFunctions<RestData>
|
|
81
|
+
// the methods below are optional
|
|
82
|
+
postState?: (response: AxiosResponse<iPostC6RestResponse<RestData>>, request: iAPI<any>, id: string | number | boolean) => void,
|
|
83
|
+
deleteState?: (response: AxiosResponse<iDeleteC6RestResponse<RestData>>, request: iAPI<any>) => void,
|
|
84
|
+
putState?: (response: AxiosResponse<iPutC6RestResponse<RestData>>, request: iAPI<any>) => void
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface tC6Tables<
|
|
88
|
+
RestShortTableName extends string = any,
|
|
89
|
+
RestTableInterface extends { [key: string]: any } = any,
|
|
90
|
+
PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>
|
|
91
|
+
> {
|
|
92
|
+
[key: string]: iC6RestfulModel<RestShortTableName, RestTableInterface, PrimaryKey> & { [key: string]: any }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface tC6RestApi {
|
|
96
|
+
[key: string]: {
|
|
97
|
+
REST: iRestApiFunctions,
|
|
98
|
+
PUT: Function;
|
|
99
|
+
POST: Function;
|
|
100
|
+
DELETE: Function;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// todo - I don't like that these essentially become reserved words.
|
|
105
|
+
export type iAPI<RestTableInterfaces extends { [key: string]: any }> = RestTableInterfaces & {
|
|
106
|
+
dataInsertMultipleRows?: RestTableInterfaces[],
|
|
107
|
+
cacheResults?: boolean, // aka ignoreCache
|
|
108
|
+
// todo - this should really only be used for get requests - add this to the Get interface or throw error (im actually inclined to ts ignore the function and add to iGetC6 atm; back later)
|
|
109
|
+
fetchDependencies?: number | eFetchDependencies | Awaited<apiReturn<iGetC6RestResponse<any>>>[],
|
|
110
|
+
debug?: boolean,
|
|
111
|
+
success?: string | ((r: AxiosResponse) => (string | void)),
|
|
112
|
+
error?: string | ((r: AxiosResponse) => (string | void)),
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface iCacheAPI<ResponseDataType = any> {
|
|
116
|
+
requestArgumentsSerialized: string,
|
|
117
|
+
request: AxiosPromise<ResponseDataType>,
|
|
118
|
+
response?: AxiosResponse,
|
|
119
|
+
final?: boolean,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* the first argument ....
|
|
125
|
+
*
|
|
126
|
+
* Our api returns a zero argument function iff the method is get and the previous request reached the predefined limit.
|
|
127
|
+
* This function can be aliased as GetNextPageOfResults(). If the end is reached undefined will be returned.
|
|
128
|
+
*
|
|
129
|
+
*
|
|
130
|
+
* For POST, PUT, and DELETE requests one can expect the primary key of the new or modified index, or a boolean success
|
|
131
|
+
* indication if no primary key exists.
|
|
132
|
+
**/
|
|
133
|
+
export const POST = 'POST';
|
|
134
|
+
export const PUT = 'PUT';
|
|
135
|
+
export const GET = 'GET';
|
|
136
|
+
export const DELETE = 'DELETE';
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
export type iRestMethods = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
140
|
+
|
|
141
|
+
// ========================
|
|
142
|
+
// 📦 SELECT
|
|
143
|
+
// ========================
|
|
144
|
+
|
|
145
|
+
export type SubSelect<T = any> = {
|
|
146
|
+
subSelect: true;
|
|
147
|
+
table: string; // could be enum’d to known table names
|
|
148
|
+
args: RequestGetPutDeleteBody<T>;
|
|
149
|
+
alias: string;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export type SelectField<T = any> =
|
|
153
|
+
| keyof T
|
|
154
|
+
| [keyof T, 'AS', string]
|
|
155
|
+
| [SQLFunction, keyof T]
|
|
156
|
+
| [SQLFunction, keyof T, string] // With alias
|
|
157
|
+
| SubSelect<T>; // Fully nested sub-select
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
// ========================
|
|
161
|
+
// 🧠 WHERE (Recursive)
|
|
162
|
+
// ========================
|
|
163
|
+
|
|
164
|
+
export type WhereClause<T = any> =
|
|
165
|
+
| Partial<T>
|
|
166
|
+
| LogicalGroup<T>
|
|
167
|
+
| ComparisonClause<T>;
|
|
168
|
+
|
|
169
|
+
export type LogicalGroup<T = any> = {
|
|
170
|
+
[logicalGroup: string]: Array<WhereClause<T>>;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export type ComparisonClause<T = any> = [keyof T, SQLComparisonOperator, any];
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
// ========================
|
|
177
|
+
// 🔗 JOIN
|
|
178
|
+
// ========================
|
|
179
|
+
|
|
180
|
+
export type JoinTableCondition<T = any> =
|
|
181
|
+
| Partial<T>
|
|
182
|
+
| WhereClause<T>[]
|
|
183
|
+
| ComparisonClause<T>[];
|
|
184
|
+
|
|
185
|
+
export type JoinClause<T = any> = {
|
|
186
|
+
[table: string]: JoinTableCondition<T>;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export type Join<T = any> = {
|
|
190
|
+
[K in JoinType]?: JoinClause<T>;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
// ========================
|
|
195
|
+
// 📄 PAGINATION
|
|
196
|
+
// ========================
|
|
197
|
+
|
|
198
|
+
export type Pagination<T = any> = {
|
|
199
|
+
PAGE?: number;
|
|
200
|
+
LIMIT?: number | null;
|
|
201
|
+
ORDER?: Partial<Record<keyof T, OrderDirection>>;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
// ========================
|
|
206
|
+
// 🌐 MAIN API TYPE
|
|
207
|
+
// ========================
|
|
208
|
+
|
|
209
|
+
export type RequestGetPutDeleteBody<T = any> = {
|
|
210
|
+
SELECT?: SelectField<T>[];
|
|
211
|
+
UPDATE?: Partial<T>;
|
|
212
|
+
DELETE?: boolean;
|
|
213
|
+
WHERE?: WhereClause<T>;
|
|
214
|
+
JOIN?: Join<T>;
|
|
215
|
+
PAGINATION?: Pagination<T>;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
export type RequestQueryBody<RestTableInterfaces extends { [key: string]: any }> =
|
|
220
|
+
iAPI<RestTableInterfaces>
|
|
221
|
+
| RequestGetPutDeleteBody;
|
|
222
|
+
|
|
223
|
+
export function isPromise(x) {
|
|
224
|
+
return Object(x).constructor === Promise
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
interface iC6RestResponse<RestData> {
|
|
228
|
+
rest: RestData,
|
|
229
|
+
session?: any,
|
|
230
|
+
sql?: any
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
interface iChangeC6Data {
|
|
235
|
+
rowCount: number,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface iDeleteC6RestResponse<RestData = any, RequestData = any> extends iChangeC6Data, iC6RestResponse<RestData> {
|
|
239
|
+
deleted: boolean | number | string | RequestData,
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export interface iPostC6RestResponse<RestData = any> extends iC6RestResponse<RestData> {
|
|
243
|
+
created: boolean | number | string,
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export interface iPutC6RestResponse<RestData = any, RequestData = any> extends iChangeC6Data, iC6RestResponse<RestData> {
|
|
247
|
+
updated: boolean | number | string | RequestData,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface iC6Object<
|
|
251
|
+
RestShortTableName extends string = any,
|
|
252
|
+
RestTableInterface extends { [key: string]: any } = any,
|
|
253
|
+
PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>
|
|
254
|
+
> {
|
|
255
|
+
C6VERSION: string,
|
|
256
|
+
TABLES: {
|
|
257
|
+
[key: string]: iC6RestfulModel<RestShortTableName, RestTableInterface, PrimaryKey>
|
|
258
|
+
& {
|
|
259
|
+
[key: string]: string | number
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
PREFIX: string,
|
|
263
|
+
IMPORT: (tableName: string) => Promise<iDynamicApiImport>,
|
|
264
|
+
|
|
265
|
+
[key: string]: any
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// todo - I'm not sure that Modify<ResponseDataType, ResponseDataOverrides>[]> is needed?
|
|
269
|
+
export type iGetC6RestResponse<ResponseDataType, ResponseDataOverrides = {}> = iC6RestResponse<Modify<ResponseDataType, ResponseDataOverrides> | Modify<ResponseDataType, ResponseDataOverrides>[]>
|
|
270
|
+
|
|
271
|
+
// returning undefined means no more results are available, thus we've queried everything possible
|
|
272
|
+
// null means the request is currently being executed
|
|
273
|
+
// https://www.typescriptlang.org/docs/handbook/2/conditional-types.html
|
|
274
|
+
export type apiReturn<Response> =
|
|
275
|
+
null
|
|
276
|
+
| undefined
|
|
277
|
+
| AxiosPromise<Response>
|
|
278
|
+
| (Response extends iPutC6RestResponse | iDeleteC6RestResponse | iPostC6RestResponse ? null : (() => apiReturn<Response>))
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
export interface iRest<
|
|
282
|
+
RestShortTableName extends string = any,
|
|
283
|
+
RestTableInterface extends { [key: string]: any } = any,
|
|
284
|
+
PrimaryKey extends Extract<keyof RestTableInterface, string> = Extract<keyof RestTableInterface, string>,
|
|
285
|
+
CustomAndRequiredFields extends { [key: string]: any } = any,
|
|
286
|
+
RequestTableOverrides = { [key in keyof RestTableInterface]: any },
|
|
287
|
+
ResponseDataType = any
|
|
288
|
+
> {
|
|
289
|
+
C6: iC6Object,
|
|
290
|
+
axios?: AxiosInstance,
|
|
291
|
+
restURL?: string,
|
|
292
|
+
mysqlPool?: Pool;
|
|
293
|
+
withCredentials?: boolean,
|
|
294
|
+
restModel: iC6RestfulModel<RestShortTableName, RestTableInterface, PrimaryKey>,
|
|
295
|
+
requestMethod: iRestMethods,
|
|
296
|
+
clearCache?: () => void,
|
|
297
|
+
skipPrimaryCheck?: boolean,
|
|
298
|
+
queryCallback: RequestQueryBody<Modify<RestTableInterface, RequestTableOverrides>> | ((request: iAPI<Modify<RestTableInterface, RequestTableOverrides>> & CustomAndRequiredFields) => (null | undefined | RequestQueryBody<Modify<RestTableInterface, RequestTableOverrides>>)),
|
|
299
|
+
responseCallback?: (response: AxiosResponse<ResponseDataType>,
|
|
300
|
+
request: iAPI<Modify<RestTableInterface, RequestTableOverrides>> & CustomAndRequiredFields,
|
|
301
|
+
success: (ResponseDataType extends iPutC6RestResponse | iDeleteC6RestResponse
|
|
302
|
+
? RequestQueryBody<Modify<RestTableInterface, RequestTableOverrides>>
|
|
303
|
+
: string)
|
|
304
|
+
| RestTableInterface[PrimaryKey] // Rest PK
|
|
305
|
+
| string | number | boolean // Toast and validations
|
|
306
|
+
) => any // keep this set to any, it allows easy arrow functions and the results unused here
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// When we capture DropExceptions and display them as a custom page, this will change.
|
|
2
|
+
import {toast} from "react-toastify";
|
|
3
|
+
import isTest from "../../variables/isTest";
|
|
4
|
+
import { AxiosResponse } from "axios";
|
|
5
|
+
import {toastOptions} from "../../variables/toastOptions";
|
|
6
|
+
import {iC6RestfulModel} from "../types/ormInterfaces";
|
|
7
|
+
|
|
8
|
+
export function TestRestfulResponse(response: AxiosResponse | any, success: ((r: AxiosResponse) => (string | void)) | string | undefined, error: ((r: AxiosResponse) => (string | void)) | string | undefined): string | boolean | number {
|
|
9
|
+
|
|
10
|
+
if (undefined === response.data?.['ERROR TYPE']
|
|
11
|
+
&& (undefined !== response?.data?.rest
|
|
12
|
+
|| undefined !== response.data?.created
|
|
13
|
+
|| undefined !== response.data?.updated
|
|
14
|
+
|| undefined !== response.data?.deleted)) {
|
|
15
|
+
|
|
16
|
+
let successReturn: string | undefined | void = 'function' === typeof success ? success?.(response) : success;
|
|
17
|
+
|
|
18
|
+
if (typeof successReturn === 'string') {
|
|
19
|
+
|
|
20
|
+
toast.success(successReturn, toastOptions);
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// this could end up with bad results for deleting id's === 0
|
|
25
|
+
return response.data.created ?? response.data.updated ?? response.data.deleted ?? true;
|
|
26
|
+
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let errorReturn: string | undefined | void = 'function' === typeof error ? error?.(response) : error;
|
|
30
|
+
|
|
31
|
+
if (typeof errorReturn === 'string') {
|
|
32
|
+
|
|
33
|
+
toast.error(errorReturn, toastOptions);
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false;
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function removePrefixIfExists(tableName: string, prefix: string): string {
|
|
42
|
+
if (tableName.startsWith(prefix.toLowerCase())) {
|
|
43
|
+
return tableName.slice(prefix.length);
|
|
44
|
+
}
|
|
45
|
+
return tableName;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function removeInvalidKeys<iRestObject>(request: any, c6Tables: {
|
|
49
|
+
[key: string]: (iC6RestfulModel<any,any,any> & { [key: string]: any })
|
|
50
|
+
}): iRestObject {
|
|
51
|
+
|
|
52
|
+
let intersection: iRestObject = {} as iRestObject
|
|
53
|
+
|
|
54
|
+
let restfulObjectKeys: string[] = [];
|
|
55
|
+
|
|
56
|
+
const tableList = Object.values(c6Tables)
|
|
57
|
+
|
|
58
|
+
tableList.forEach(table => Object.values(table.COLUMNS).forEach(column => {
|
|
59
|
+
|
|
60
|
+
if (false === restfulObjectKeys.includes(column)) {
|
|
61
|
+
|
|
62
|
+
restfulObjectKeys.push(column)
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
}))
|
|
67
|
+
|
|
68
|
+
Object.keys(request).forEach(key => {
|
|
69
|
+
|
|
70
|
+
if (restfulObjectKeys.includes(key)) {
|
|
71
|
+
|
|
72
|
+
intersection[key] = request[key]
|
|
73
|
+
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
isTest || console.log('intersection', intersection)
|
|
79
|
+
|
|
80
|
+
return intersection
|
|
81
|
+
|
|
82
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {AxiosPromise} from "axios";
|
|
2
|
+
import isTest from "../../variables/isTest";
|
|
3
|
+
import isVerbose from "../../variables/isVerbose";
|
|
4
|
+
import { iCacheAPI } from "api/types/ormInterfaces";
|
|
5
|
+
|
|
6
|
+
// do not remove entries from this array. It is used to track the progress of API requests.
|
|
7
|
+
// position in array is important. Do not sort. To not add to begging.
|
|
8
|
+
export let apiRequestCache: iCacheAPI[] = [];
|
|
9
|
+
|
|
10
|
+
export let userCustomClearCache: (() => void)[] = [];
|
|
11
|
+
|
|
12
|
+
interface iClearCache {
|
|
13
|
+
ignoreWarning: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function clearCache(props?: iClearCache) {
|
|
17
|
+
|
|
18
|
+
if (false === props?.ignoreWarning) {
|
|
19
|
+
|
|
20
|
+
console.warn('The rest api clearCache should only be used with extreme care! Avoid using this in favor of using `cacheResults : boolean`.')
|
|
21
|
+
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
userCustomClearCache.map((f) => 'function' === typeof f && f());
|
|
25
|
+
|
|
26
|
+
userCustomClearCache = apiRequestCache = []
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function checkCache<ResponseDataType = any, RestShortTableNames = string>(cacheResult: iCacheAPI<ResponseDataType>, requestMethod: string, tableName: RestShortTableNames | RestShortTableNames[], request: any): false | undefined | null | AxiosPromise<ResponseDataType> {
|
|
31
|
+
|
|
32
|
+
if (undefined === cacheResult?.response) {
|
|
33
|
+
|
|
34
|
+
console.groupCollapsed('%c API: The request on (' + tableName + ') is in cache and the response is undefined. The request has not finished. Returning the request Promise!', 'color: #0c0')
|
|
35
|
+
|
|
36
|
+
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #0c0')
|
|
37
|
+
|
|
38
|
+
console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #0c0', request)
|
|
39
|
+
|
|
40
|
+
console.groupEnd()
|
|
41
|
+
|
|
42
|
+
return cacheResult.request;
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (true === cacheResult?.final) {
|
|
47
|
+
|
|
48
|
+
if (false === isTest || true === isVerbose) {
|
|
49
|
+
|
|
50
|
+
console.groupCollapsed('%c API: Rest api cache (' + requestMethod + ' ' + tableName + ') has reached the final result. Returning undefined!', 'color: #cc0')
|
|
51
|
+
|
|
52
|
+
console.log('%c ' + requestMethod + ' ' + tableName, 'color: #cc0')
|
|
53
|
+
|
|
54
|
+
console.log('%c Request Data (note you may see the success and/or error prompt):', 'color: #cc0', request)
|
|
55
|
+
|
|
56
|
+
console.log('%c Response Data:', 'color: #cc0', cacheResult?.response?.data?.rest || cacheResult?.response?.data || cacheResult?.response)
|
|
57
|
+
|
|
58
|
+
console.groupEnd()
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return undefined;
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {iC6RestfulModel} from "../types/ormInterfaces";
|
|
2
|
+
|
|
3
|
+
type JsPrimitive = 'string' | 'number' | 'boolean' | 'buffer' | 'object';
|
|
4
|
+
|
|
5
|
+
export function determineRuntimeJsType(mysqlType: string): JsPrimitive {
|
|
6
|
+
const base = mysqlType.toLowerCase().split('(')[0];
|
|
7
|
+
|
|
8
|
+
if ([
|
|
9
|
+
'binary', 'varbinary', 'blob', 'tinyblob', 'mediumblob', 'longblob'
|
|
10
|
+
].includes(base)) return 'buffer';
|
|
11
|
+
|
|
12
|
+
if ([
|
|
13
|
+
'json', 'geometry', 'point', 'polygon', 'multipoint', 'multilinestring', 'multipolygon', 'geometrycollection'
|
|
14
|
+
].includes(base)) return 'object';
|
|
15
|
+
|
|
16
|
+
if ([
|
|
17
|
+
'tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint',
|
|
18
|
+
'decimal', 'dec', 'numeric', 'float', 'double', 'real'
|
|
19
|
+
].includes(base)) return 'number';
|
|
20
|
+
|
|
21
|
+
if ([
|
|
22
|
+
'boolean', 'bool'
|
|
23
|
+
].includes(base)) return 'boolean';
|
|
24
|
+
|
|
25
|
+
return 'string';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function getPrimaryKeyTypes(
|
|
29
|
+
table: iC6RestfulModel<string, any, any>
|
|
30
|
+
): Record<string, JsPrimitive> {
|
|
31
|
+
const result: Record<string, JsPrimitive> = {};
|
|
32
|
+
|
|
33
|
+
for (const key of table.PRIMARY_SHORT) {
|
|
34
|
+
const fullKey = Object.entries(table.COLUMNS).find(([_, short]) => short === key)?.[0];
|
|
35
|
+
|
|
36
|
+
if (typeof fullKey === 'string') {
|
|
37
|
+
const validation = table.TYPE_VALIDATION[fullKey];
|
|
38
|
+
if (!validation) continue;
|
|
39
|
+
|
|
40
|
+
result[key] = determineRuntimeJsType(validation.MYSQL_TYPE);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import isVerbose from "variables/isVerbose";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Conditionally group a log if verbose.
|
|
5
|
+
*/
|
|
6
|
+
export function group(title: string, data?: any): void {
|
|
7
|
+
if (!isVerbose) return;
|
|
8
|
+
console.groupCollapsed(`%c${title}`, "color: #007acc");
|
|
9
|
+
if (data !== undefined) console.log(data);
|
|
10
|
+
console.groupEnd();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function info(message: string, ...optional: any[]): void {
|
|
14
|
+
if (!isVerbose) return;
|
|
15
|
+
console.info(`%cINFO: ${message}`, "color: #0a0", ...optional);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function warn(message: string, ...optional: any[]): void {
|
|
19
|
+
console.warn(`%cWARN: ${message}`, "color: #e90", ...optional);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function error(message: string, ...optional: any[]): void {
|
|
23
|
+
console.error(`%cERROR: ${message}`, "color: #c00", ...optional);
|
|
24
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
export function sortAndSerializeQueryObject(tables: String, query: Object) {
|
|
3
|
+
const orderedQuery = Object.keys(query).sort().reduce(
|
|
4
|
+
(obj, key) => {
|
|
5
|
+
obj[key] = query[key];
|
|
6
|
+
return obj;
|
|
7
|
+
},
|
|
8
|
+
{}
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
return tables + ' ' + JSON.stringify(orderedQuery);
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {apiRequestCache} from "./cacheManager";
|
|
2
|
+
|
|
3
|
+
export function checkAllRequestsComplete(): true | (string[]) {
|
|
4
|
+
|
|
5
|
+
const stillRunning = apiRequestCache.filter((cache) => undefined === cache.response)
|
|
6
|
+
|
|
7
|
+
if (stillRunning.length !== 0) {
|
|
8
|
+
|
|
9
|
+
if (document === null || document === undefined) {
|
|
10
|
+
|
|
11
|
+
throw new Error('document is undefined while waiting for API requests to complete (' + JSON.stringify(apiRequestCache) + ')')
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// when requests return emtpy sets in full renders, it may not be possible to track their progress.
|
|
16
|
+
console.warn('stillRunning...', stillRunning)
|
|
17
|
+
|
|
18
|
+
return stillRunning.map((cache) => cache.requestArgumentsSerialized)
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return true
|
|
23
|
+
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { toast } from "react-toastify";
|
|
2
|
+
import { toastOptions, toastOptionsDevs } from "variables/toastOptions";
|
|
3
|
+
import isLocal from "variables/isLocal";
|
|
4
|
+
|
|
5
|
+
export function onSuccess(message: string): void {
|
|
6
|
+
toast.success(message, isLocal ? toastOptionsDevs : toastOptions);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function onError(message: string): void {
|
|
10
|
+
toast.error(message, isLocal ? toastOptionsDevs : toastOptions);
|
|
11
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,14 +5,27 @@
|
|
|
5
5
|
export * from "./api/C6Constants";
|
|
6
6
|
export { default as axiosInstance } from "./api/axiosInstance";
|
|
7
7
|
export * from "./api/axiosInstance";
|
|
8
|
-
export * from "./api/carbonSqlExecutor";
|
|
9
8
|
export { default as convertForRequestBody } from "./api/convertForRequestBody";
|
|
10
9
|
export * from "./api/convertForRequestBody";
|
|
11
10
|
export { default as restRequest } from "./api/restRequest";
|
|
12
11
|
export * from "./api/restRequest";
|
|
13
12
|
export { default as timeout } from "./api/timeout";
|
|
14
13
|
export * from "./api/timeout";
|
|
15
|
-
export * from "./api/
|
|
14
|
+
export * from "./api/builders/sqlBuilder";
|
|
15
|
+
export * from "./api/executors/Executor";
|
|
16
|
+
export * from "./api/executors/HttpExecutor";
|
|
17
|
+
export * from "./api/executors/SqlExecutor";
|
|
18
|
+
export * from "./api/types/dynamicFetching";
|
|
19
|
+
export * from "./api/types/modifyTypes";
|
|
20
|
+
export * from "./api/types/mysqlTypes";
|
|
21
|
+
export * from "./api/types/ormInterfaces";
|
|
22
|
+
export * from "./api/utils/apiHelpers";
|
|
23
|
+
export * from "./api/utils/cacheManager";
|
|
24
|
+
export * from "./api/utils/determineRuntimeJsType";
|
|
25
|
+
export * from "./api/utils/logger";
|
|
26
|
+
export * from "./api/utils/sortAndSerializeQueryObject";
|
|
27
|
+
export * from "./api/utils/testHelpers";
|
|
28
|
+
export * from "./api/utils/toastNotifier";
|
|
16
29
|
export * from "./variables/getEnvVar";
|
|
17
30
|
export { default as isLocal } from "./variables/isLocal";
|
|
18
31
|
export * from "./variables/isLocal";
|