@avleon/core 0.0.26 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +601 -561
- package/package.json +38 -6
- package/src/application.ts +104 -125
- package/src/authentication.ts +16 -16
- package/src/cache.ts +91 -91
- package/src/collection.test.ts +71 -0
- package/src/collection.ts +344 -254
- package/src/config.test.ts +35 -0
- package/src/config.ts +85 -42
- package/src/constants.ts +1 -1
- package/src/container.ts +54 -54
- package/src/controller.ts +125 -127
- package/src/decorators.ts +27 -27
- package/src/environment-variables.ts +53 -46
- package/src/exceptions/http-exceptions.ts +86 -86
- package/src/exceptions/index.ts +1 -1
- package/src/exceptions/system-exception.ts +35 -34
- package/src/file-storage.ts +206 -206
- package/src/helpers.ts +324 -328
- package/src/icore.ts +66 -90
- package/src/index.ts +30 -30
- package/src/interfaces/avleon-application.ts +32 -40
- package/src/logger.ts +72 -72
- package/src/map-types.ts +159 -159
- package/src/middleware.ts +119 -98
- package/src/multipart.ts +116 -116
- package/src/openapi.ts +372 -372
- package/src/params.ts +111 -111
- package/src/queue.ts +126 -126
- package/src/response.ts +74 -74
- package/src/results.ts +30 -30
- package/src/route-methods.ts +186 -186
- package/src/swagger-schema.ts +213 -213
- package/src/testing.ts +220 -220
- package/src/types/app-builder.interface.ts +18 -19
- package/src/types/application.interface.ts +7 -9
- package/src/utils/hash.ts +8 -5
- package/src/utils/index.ts +2 -2
- package/src/utils/optional-require.ts +50 -50
- package/src/validation.ts +160 -156
- package/src/validator-extend.ts +25 -25
package/src/collection.ts
CHANGED
|
@@ -1,254 +1,344 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @copyright 2024
|
|
3
|
-
* @author Tareq Hossain
|
|
4
|
-
* @email xtrinsic96@gmail.com
|
|
5
|
-
* @url https://github.com/xtareq
|
|
6
|
-
*/
|
|
7
|
-
import Container from "typedi";
|
|
8
|
-
import { NotFoundException } from "./exceptions";
|
|
9
|
-
import {
|
|
10
|
-
DataSource,
|
|
11
|
-
EntityTarget,
|
|
12
|
-
FindOneOptions,
|
|
13
|
-
ObjectLiteral,
|
|
14
|
-
Repository,
|
|
15
|
-
} from "typeorm";
|
|
16
|
-
import { UpsertOptions } from "typeorm/repository/UpsertOptions";
|
|
17
|
-
|
|
18
|
-
type ObjKey<T> = keyof T;
|
|
19
|
-
type ObjKeys<T> = ObjKey<T>[];
|
|
20
|
-
type PaginationOptions = {
|
|
21
|
-
take: number;
|
|
22
|
-
skip?: number;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type Predicate<T> = (item: T) => boolean;
|
|
26
|
-
interface TypeormEnitity extends ObjectLiteral {}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.items
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @copyright 2024
|
|
3
|
+
* @author Tareq Hossain
|
|
4
|
+
* @email xtrinsic96@gmail.com
|
|
5
|
+
* @url https://github.com/xtareq
|
|
6
|
+
*/
|
|
7
|
+
import Container from "typedi";
|
|
8
|
+
import { NotFoundException } from "./exceptions";
|
|
9
|
+
import {
|
|
10
|
+
DataSource,
|
|
11
|
+
EntityTarget,
|
|
12
|
+
FindOneOptions,
|
|
13
|
+
ObjectLiteral,
|
|
14
|
+
Repository,
|
|
15
|
+
} from "typeorm";
|
|
16
|
+
import { UpsertOptions } from "typeorm/repository/UpsertOptions";
|
|
17
|
+
|
|
18
|
+
type ObjKey<T> = keyof T;
|
|
19
|
+
type ObjKeys<T> = ObjKey<T>[];
|
|
20
|
+
type PaginationOptions = {
|
|
21
|
+
take: number;
|
|
22
|
+
skip?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type Predicate<T> = (item: T) => boolean;
|
|
26
|
+
interface TypeormEnitity extends ObjectLiteral {}
|
|
27
|
+
type Primitive = string | number | boolean | null;
|
|
28
|
+
|
|
29
|
+
type ValueOperator<T> = {
|
|
30
|
+
$in?: T[];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type FieldCondition<T> = T | ValueOperator<T>;
|
|
34
|
+
|
|
35
|
+
type WhereCondition<T> = {
|
|
36
|
+
[K in keyof T]?: FieldCondition<T[K]>;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type LogicalOperators<T> =
|
|
40
|
+
| { $and: Where<T>[] }
|
|
41
|
+
| { $or: Where<T>[] }
|
|
42
|
+
| { $not: Where<T> };
|
|
43
|
+
|
|
44
|
+
type Where<T> = WhereCondition<T> | LogicalOperators<T>;
|
|
45
|
+
|
|
46
|
+
export interface IFindOneOptions<T = any> {
|
|
47
|
+
where: Where<T>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type PaginationResult<T> = {
|
|
51
|
+
total: number;
|
|
52
|
+
data: T[];
|
|
53
|
+
next?: number | null;
|
|
54
|
+
prev?: number | null;
|
|
55
|
+
first?: number | null;
|
|
56
|
+
last?: number | null;
|
|
57
|
+
totalPage?: number;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type ICollection<T> = {
|
|
61
|
+
findAll(): T[] | Promise<T[]>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type EntityCollection<T extends ObjectLiteral> = {};
|
|
65
|
+
|
|
66
|
+
export interface BasicCollection<T> {
|
|
67
|
+
clear(): void;
|
|
68
|
+
find(predicate?: Predicate<T>): T[];
|
|
69
|
+
findAsync(predicate?: Predicate<T>): Promise<T[]>;
|
|
70
|
+
findOne(predicate: Predicate<T> | IFindOneOptions<T>): T | undefined;
|
|
71
|
+
findOneAsync(
|
|
72
|
+
predicate: Predicate<T> | IFindOneOptions<T>,
|
|
73
|
+
): Promise<T | undefined>;
|
|
74
|
+
}
|
|
75
|
+
class BasicCollectionImpl<T> implements BasicCollection<T> {
|
|
76
|
+
private items: T[];
|
|
77
|
+
|
|
78
|
+
private constructor(items: T[]) {
|
|
79
|
+
this.items = items;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static from<T>(items: T[]): BasicCollectionImpl<T> {
|
|
83
|
+
return new BasicCollectionImpl(items);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
clear() {
|
|
87
|
+
this.items = [];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
find(predicate?: Predicate<T>) {
|
|
91
|
+
if (this.isFunction(predicate)) {
|
|
92
|
+
return this.items.filter(predicate as Predicate<T>) as T[];
|
|
93
|
+
}
|
|
94
|
+
const results = Array.from(this.items);
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async findAsync(predicate?: Predicate<T>): Promise<T[]> {
|
|
99
|
+
const results = Array.from(this.items);
|
|
100
|
+
return results;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private _matches<T>(item: T, where: Where<T>): boolean {
|
|
104
|
+
if ("$or" in where) {
|
|
105
|
+
return where.$or.some((cond) => this._matches(item, cond));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if ("$and" in where) {
|
|
109
|
+
return where.$and.every((cond) => this._matches(item, cond));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if ("$not" in where) {
|
|
113
|
+
return !this._matches(item, where.$not);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Field-based matching
|
|
117
|
+
return Object.entries(where).every(([key, condition]) => {
|
|
118
|
+
const itemValue = item[key as keyof T];
|
|
119
|
+
if (
|
|
120
|
+
condition &&
|
|
121
|
+
typeof condition === "object" &&
|
|
122
|
+
!Array.isArray(condition)
|
|
123
|
+
) {
|
|
124
|
+
const op = condition as ValueOperator<any>;
|
|
125
|
+
|
|
126
|
+
if ("$in" in op && Array.isArray(op.$in)) {
|
|
127
|
+
return op.$in.includes(itemValue);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return itemValue === condition;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
findOne(predicate: Predicate<T> | IFindOneOptions<T>): T | undefined {
|
|
136
|
+
if (this.isFunction(predicate)) {
|
|
137
|
+
return this.items.find(predicate as Predicate<T>) as T;
|
|
138
|
+
}
|
|
139
|
+
const result = this.items.filter((item) =>
|
|
140
|
+
this._matches(item, predicate.where),
|
|
141
|
+
);
|
|
142
|
+
if (result.length > 0) {
|
|
143
|
+
return result[0];
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async findOneAsync(
|
|
149
|
+
predicate: Predicate<T> | IFindOneOptions<T>,
|
|
150
|
+
): Promise<T | undefined> {
|
|
151
|
+
if (this.isFunction(predicate)) {
|
|
152
|
+
return this.items.find(predicate as Predicate<T>) as T;
|
|
153
|
+
}
|
|
154
|
+
return this.items.find((item) => this._matches(item, predicate.where));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Utility function to check if a value is a function
|
|
158
|
+
private isFunction(value: unknown): value is Function {
|
|
159
|
+
return typeof value === "function";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
add(item: Partial<T>): T;
|
|
163
|
+
add(item: Partial<T>): T | Promise<T> {
|
|
164
|
+
this.items.push(item as T);
|
|
165
|
+
return this.items[this.items.length - 1];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
addAll(items: T[]): void {
|
|
169
|
+
this.items.push(...items);
|
|
170
|
+
}
|
|
171
|
+
update(predicate: (item: T) => boolean, updater: Partial<T>): void {
|
|
172
|
+
const item = this.items.find(predicate);
|
|
173
|
+
if (item) {
|
|
174
|
+
const index = this.items.indexOf(item)!;
|
|
175
|
+
this.items[index] = { ...item, ...updater };
|
|
176
|
+
} else {
|
|
177
|
+
throw new NotFoundException("Item not found");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
updateAll(predicate: (item: T) => boolean, updater: (item: T) => T): void {
|
|
182
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
183
|
+
if (predicate(this.items[i])) {
|
|
184
|
+
this.items[i] = updater(this.items[i]);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
delete(predicate: (item: T) => boolean): void {
|
|
189
|
+
const index = this.items.findIndex(predicate);
|
|
190
|
+
if (index !== -1) {
|
|
191
|
+
this.items.splice(index, 1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
deleteAll(predicate: (item: T) => boolean): void {
|
|
195
|
+
this.items = this.items.filter((item) => !predicate(item));
|
|
196
|
+
}
|
|
197
|
+
max<K extends keyof T>(key: K & string): number {
|
|
198
|
+
return Math.max(...this.items.map((item) => item[key] as number));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
min<K extends keyof T>(key: K & string): number {
|
|
202
|
+
return Math.max(...this.items.map((item) => item[key] as number));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
sum<K extends keyof T>(key: K & string): number {
|
|
206
|
+
const nums = this.items.flatMap((x) => x[key]) as number[];
|
|
207
|
+
return nums.reduce((sum, num) => sum + num, 0);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
avg<K extends keyof T>(key: K & string): number {
|
|
211
|
+
const nums = this.items.flatMap((x) => x[key]) as number[];
|
|
212
|
+
return nums.reduce((sum, num) => sum + num, 0) / nums.length;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
paginate(options?: PaginationOptions) {
|
|
216
|
+
const take = options?.take || 10;
|
|
217
|
+
const skip = options?.skip || 0;
|
|
218
|
+
const total = this.items.length;
|
|
219
|
+
const data = this.items.slice(skip, take);
|
|
220
|
+
return {
|
|
221
|
+
total,
|
|
222
|
+
totalPage: Math.ceil(total / take),
|
|
223
|
+
next: skip + take < total ? skip + take : null,
|
|
224
|
+
data,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private getDeepValue(item: any, path: string | keyof T): any {
|
|
229
|
+
if (typeof path !== "string") return item[path];
|
|
230
|
+
return path.split(".").reduce((acc, key) => acc?.[key], item);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
class AsynchronousCollection<T extends ObjectLiteral> {
|
|
235
|
+
private model: EntityTarget<T>;
|
|
236
|
+
private repo?: Repository<T>;
|
|
237
|
+
|
|
238
|
+
private constructor(model: EntityTarget<T>) {
|
|
239
|
+
this.model = model;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static fromRepository<T extends ObjectLiteral>(
|
|
243
|
+
model: EntityTarget<T>,
|
|
244
|
+
): AsynchronousCollection<T> {
|
|
245
|
+
return new AsynchronousCollection(model);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
getRepository() {
|
|
249
|
+
if (!this.repo) {
|
|
250
|
+
const dataSourceKey = "idatasource";
|
|
251
|
+
const dataSource = Container.get(dataSourceKey) as DataSource;
|
|
252
|
+
console.log("datasource", dataSource);
|
|
253
|
+
const repository = dataSource.getRepository<T>(this.model);
|
|
254
|
+
this.repo = repository;
|
|
255
|
+
return repository;
|
|
256
|
+
}
|
|
257
|
+
return this.repo;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Pagination with query builder
|
|
261
|
+
async paginate(options?: PaginationOptions): Promise<PaginationResult<T>> {
|
|
262
|
+
const take = options?.take || 10;
|
|
263
|
+
const skip = options?.skip || 0;
|
|
264
|
+
|
|
265
|
+
const [data, total] = await this.getRepository().findAndCount({
|
|
266
|
+
take,
|
|
267
|
+
skip,
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
return {
|
|
271
|
+
total,
|
|
272
|
+
totalPage: Math.ceil(total / take),
|
|
273
|
+
next: skip + take < total ? skip + take : null,
|
|
274
|
+
prev: skip + take < total ? skip + take : null,
|
|
275
|
+
data,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export class Collection {
|
|
281
|
+
private constructor() {}
|
|
282
|
+
|
|
283
|
+
static from<T>(items: T[]): BasicCollection<T> {
|
|
284
|
+
return BasicCollectionImpl.from(items);
|
|
285
|
+
}
|
|
286
|
+
// Example refactoring of Collection.fromRepository for better type safety
|
|
287
|
+
static fromRepository<T extends ObjectLiteral>(
|
|
288
|
+
entity: EntityTarget<T>,
|
|
289
|
+
): Repository<T> {
|
|
290
|
+
const asyncCollection = AsynchronousCollection.fromRepository(entity);
|
|
291
|
+
// Assuming AsynchronousCollection has a method to get the Repository<T>
|
|
292
|
+
return asyncCollection.getRepository();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function InjectRepository<T extends Repository<T>>(
|
|
297
|
+
model: EntityTarget<T>,
|
|
298
|
+
) {
|
|
299
|
+
return function (
|
|
300
|
+
object: any,
|
|
301
|
+
propertyName: string | undefined,
|
|
302
|
+
index?: number,
|
|
303
|
+
) {
|
|
304
|
+
let repo!: any | Repository<T>;
|
|
305
|
+
try {
|
|
306
|
+
Container.registerHandler({
|
|
307
|
+
object,
|
|
308
|
+
propertyName,
|
|
309
|
+
index,
|
|
310
|
+
value: (containerInstance) => {
|
|
311
|
+
const dataSource = containerInstance.get<DataSource>("idatasource");
|
|
312
|
+
|
|
313
|
+
repo = dataSource
|
|
314
|
+
.getRepository<T>(model)
|
|
315
|
+
.extend({ paginate: () => {} });
|
|
316
|
+
repo.paginate = async function (
|
|
317
|
+
options: PaginationOptions = { take: 10, skip: 0 },
|
|
318
|
+
): Promise<PaginationResult<T>> {
|
|
319
|
+
const [data, total] = await this.findAndCount({
|
|
320
|
+
take: options.take || 10,
|
|
321
|
+
skip: options.skip || 0,
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
total,
|
|
326
|
+
totalPage: Math.ceil(total / (options.take || 10)),
|
|
327
|
+
next:
|
|
328
|
+
options.skip! + options.take! < total
|
|
329
|
+
? options.skip! + options.take!
|
|
330
|
+
: null,
|
|
331
|
+
data,
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
return repo;
|
|
335
|
+
},
|
|
336
|
+
});
|
|
337
|
+
} catch (error: any) {
|
|
338
|
+
console.log(error);
|
|
339
|
+
if (error.name && error.name == "ServiceNotFoundError") {
|
|
340
|
+
console.log("Database didn't initialized.");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { Config, CreateConfig, GetConfig, IConfig } from "./config";
|
|
3
|
+
import { Environment } from "./environment-variables";
|
|
4
|
+
|
|
5
|
+
type AppConfig = { name: string; os: string };
|
|
6
|
+
|
|
7
|
+
describe("Config", () => {
|
|
8
|
+
describe("class", () => {
|
|
9
|
+
it("should be call by get config", () => {
|
|
10
|
+
@Config
|
|
11
|
+
class MyConfig {
|
|
12
|
+
config(env: Environment) {
|
|
13
|
+
return {
|
|
14
|
+
name: "avleon",
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const mConfig = GetConfig(MyConfig);
|
|
19
|
+
expect(mConfig).toHaveProperty("name");
|
|
20
|
+
expect(mConfig["name"]).toBe("avleon");
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe("createConfig()", () => {
|
|
25
|
+
it("it should create config and called with GetConfig", () => {
|
|
26
|
+
CreateConfig("myconfig", (env) => ({
|
|
27
|
+
firstname: "tareq",
|
|
28
|
+
os: env.get("name"),
|
|
29
|
+
}));
|
|
30
|
+
const mConfig = GetConfig("myconfig");
|
|
31
|
+
expect(mConfig).toHaveProperty("firstname");
|
|
32
|
+
expect(mConfig.firstname).toBe("tareq");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|