@drax/crud-back 0.11.5 → 0.12.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.
Files changed (74) hide show
  1. package/dist/builders/CrudSchemaBuilder.js +349 -0
  2. package/dist/controllers/AbstractFastifyController.js +105 -176
  3. package/dist/index.js +15 -1
  4. package/dist/regexs/QueryFilterRegex.js +3 -0
  5. package/dist/repository/AbstractMongoRepository.js +114 -28
  6. package/dist/repository/AbstractSqliteRepository.js +131 -41
  7. package/dist/schemas/DeleteBodyResponseSchema.js +9 -0
  8. package/dist/schemas/ErrorBodyResponseSchema.js +16 -0
  9. package/dist/schemas/ExportBodyResponseSchema.js +9 -0
  10. package/dist/schemas/FindBySchema.js +6 -0
  11. package/dist/schemas/FindSchema.js +9 -0
  12. package/dist/schemas/IdParamSchema.js +6 -0
  13. package/dist/schemas/PaginateBodySchema.js +20 -0
  14. package/dist/schemas/PaginateSchema.js +17 -0
  15. package/dist/schemas/SearchSchema.js +5 -0
  16. package/dist/services/AbstractService.js +8 -5
  17. package/dist/zod/DeleteBodySchema.js +6 -0
  18. package/dist/zod/IdParamSchema.js +6 -0
  19. package/dist/zod/PaginateBodySchema.js +20 -0
  20. package/package.json +7 -6
  21. package/src/builders/CrudSchemaBuilder.ts +420 -0
  22. package/src/controllers/AbstractFastifyController.ts +149 -165
  23. package/src/index.ts +28 -0
  24. package/src/regexs/QueryFilterRegex.ts +4 -0
  25. package/src/repository/AbstractMongoRepository.ts +153 -40
  26. package/src/repository/AbstractSqliteRepository.ts +196 -72
  27. package/src/schemas/DeleteBodyResponseSchema.ts +12 -0
  28. package/src/schemas/ErrorBodyResponseSchema.ts +20 -0
  29. package/src/schemas/ExportBodyResponseSchema.ts +12 -0
  30. package/src/schemas/FindBySchema.ts +9 -0
  31. package/src/schemas/FindSchema.ts +13 -0
  32. package/src/schemas/IdParamSchema.ts +9 -0
  33. package/src/schemas/PaginateSchema.ts +21 -0
  34. package/src/schemas/SearchSchema.ts +8 -0
  35. package/src/services/AbstractService.ts +42 -33
  36. package/tsconfig.tsbuildinfo +1 -1
  37. package/types/builders/CrudSchemaBuilder.d.ts +2401 -0
  38. package/types/builders/CrudSchemaBuilder.d.ts.map +1 -0
  39. package/types/controllers/AbstractFastifyController.d.ts +6 -1
  40. package/types/controllers/AbstractFastifyController.d.ts.map +1 -1
  41. package/types/index.d.ts +10 -1
  42. package/types/index.d.ts.map +1 -1
  43. package/types/regexs/QueryFilterRegex.d.ts +4 -0
  44. package/types/regexs/QueryFilterRegex.d.ts.map +1 -0
  45. package/types/repository/AbstractMongoRepository.d.ts +6 -3
  46. package/types/repository/AbstractMongoRepository.d.ts.map +1 -1
  47. package/types/repository/AbstractSqliteRepository.d.ts +23 -8
  48. package/types/repository/AbstractSqliteRepository.d.ts.map +1 -1
  49. package/types/schemas/DeleteBodyResponseSchema.d.ts +20 -0
  50. package/types/schemas/DeleteBodyResponseSchema.d.ts.map +1 -0
  51. package/types/schemas/ErrorBodyResponseSchema.d.ts +60 -0
  52. package/types/schemas/ErrorBodyResponseSchema.d.ts.map +1 -0
  53. package/types/schemas/ExportBodyResponseSchema.d.ts +20 -0
  54. package/types/schemas/ExportBodyResponseSchema.d.ts.map +1 -0
  55. package/types/schemas/FindBySchema.d.ts +13 -0
  56. package/types/schemas/FindBySchema.d.ts.map +1 -0
  57. package/types/schemas/FindSchema.d.ts +19 -0
  58. package/types/schemas/FindSchema.d.ts.map +1 -0
  59. package/types/schemas/IdParamSchema.d.ts +11 -0
  60. package/types/schemas/IdParamSchema.d.ts.map +1 -0
  61. package/types/schemas/PaginateBodySchema.d.ts +61 -0
  62. package/types/schemas/PaginateBodySchema.d.ts.map +1 -0
  63. package/types/schemas/PaginateSchema.d.ts +41 -0
  64. package/types/schemas/PaginateSchema.d.ts.map +1 -0
  65. package/types/schemas/SearchSchema.d.ts +10 -0
  66. package/types/schemas/SearchSchema.d.ts.map +1 -0
  67. package/types/services/AbstractService.d.ts +5 -5
  68. package/types/services/AbstractService.d.ts.map +1 -1
  69. package/types/zod/DeleteBodySchema.d.ts +11 -0
  70. package/types/zod/DeleteBodySchema.d.ts.map +1 -0
  71. package/types/zod/IdParamSchema.d.ts +11 -0
  72. package/types/zod/IdParamSchema.d.ts.map +1 -0
  73. package/types/zod/PaginateBodySchema.d.ts +61 -0
  74. package/types/zod/PaginateBodySchema.d.ts.map +1 -0
@@ -1,103 +1,190 @@
1
1
  import "mongoose-paginate-v2";
2
- import mongoose, {Cursor} from "mongoose";
3
- import {MongooseQueryFilter, MongooseSort, MongooseErrorToValidationError} from "@drax/common-back";
2
+ import mongoose from "mongoose";
3
+ import type {Cursor, PopulateOptions} from "mongoose";
4
+ import {
5
+ MongooseQueryFilter,
6
+ MongooseSort,
7
+ MongooseValidationErrorToValidationError,
8
+ MongooseCastErrorToValidationError,
9
+ MongoServerErrorToValidationError
10
+ } from "@drax/common-back";
4
11
  import type {DeleteResult} from "mongodb";
5
12
  import type {IDraxPaginateOptions, IDraxPaginateResult, IDraxFindOptions, IDraxCrud, IDraxFieldFilter} from "@drax/crud-share";
6
13
  import type {PaginateModel, PaginateOptions, PaginateResult} from "mongoose";
14
+ import {InvalidIdError} from "@drax/common-back";
15
+ import {MongoServerError} from "mongodb";
7
16
 
8
17
 
9
18
  class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
10
19
 
11
20
  protected _model: mongoose.Model<T> & PaginateModel<T>
12
21
  protected _searchFields: string[] = []
13
- protected _populateFields: string[] = []
22
+ protected _populateFields: string[] | PopulateOptions[] = []
23
+ protected _lean: boolean = true
24
+
25
+ assertId(id: string): void {
26
+ if(!mongoose.Types.ObjectId.isValid(id)){
27
+ console.log(`Invalid ID: ${id} is not a valid ObjectId.`)
28
+ throw new InvalidIdError(id)
29
+ }
30
+ }
14
31
 
15
32
 
16
33
  async create(data: C): Promise<T> {
17
34
  try {
18
- const item: mongoose.HydratedDocument<T> = new this._model(data)
19
- await item.save()
35
+ const item: mongoose.HydratedDocument<T> = await this._model.create(data)
20
36
 
21
- //@ts-ignore
22
- await item.populate(this._populateFields)
23
-
24
- return item
37
+ if(this._populateFields && this._populateFields.length > 0){
38
+ //@ts-ignore
39
+ await item.populate(this._populateFields)
40
+ }
41
+ return this._lean ? item : item.toObject()
25
42
  } catch (e) {
26
43
  if (e instanceof mongoose.Error.ValidationError) {
27
- throw MongooseErrorToValidationError(e)
44
+ throw MongooseValidationErrorToValidationError(e)
45
+ }
46
+ if (e instanceof mongoose.Error.CastError) {
47
+ throw MongooseCastErrorToValidationError(e)
48
+ }
49
+ if(e instanceof MongoServerError || e.name === 'MongoServerError'){
50
+ throw MongoServerErrorToValidationError(e)
28
51
  }
29
52
  throw e
30
53
  }
31
54
  }
32
55
 
33
56
  async update(id: string, data: U): Promise<T> {
57
+
58
+ this.assertId(id)
59
+
34
60
  try {
35
61
  const item: mongoose.HydratedDocument<T> = await this._model.findOneAndUpdate({_id: id}, data, {new: true}).populate(this._populateFields).exec()
36
- return item
62
+
63
+ return this._lean ? item : item.toObject()
37
64
  } catch (e) {
38
65
  if (e instanceof mongoose.Error.ValidationError) {
39
- throw MongooseErrorToValidationError(e)
66
+ throw MongooseValidationErrorToValidationError(e)
67
+ }
68
+ if (e instanceof mongoose.Error.CastError) {
69
+ throw MongooseCastErrorToValidationError(e)
70
+ }
71
+ if(e instanceof MongoServerError || e.name === 'MongoServerError'){
72
+ throw MongoServerErrorToValidationError(e)
40
73
  }
41
74
  throw e
42
75
  }
43
76
  }
44
77
 
45
78
  async updatePartial(id: string, data: any): Promise<T> {
79
+
80
+ this.assertId(id)
81
+
46
82
  try {
83
+
47
84
  const item: mongoose.HydratedDocument<T> = await this._model.findOneAndUpdate({_id: id}, data, {new: true}).populate(this._populateFields).exec()
48
- return item
85
+ return this._lean ? item : item.toObject()
49
86
  } catch (e) {
50
87
  if (e instanceof mongoose.Error.ValidationError) {
51
- throw MongooseErrorToValidationError(e)
88
+ throw MongooseValidationErrorToValidationError(e)
89
+ }
90
+ if (e instanceof mongoose.Error.CastError) {
91
+ throw MongooseCastErrorToValidationError(e)
92
+ }
93
+ if(e instanceof MongoServerError || e.name === 'MongoServerError'){
94
+ throw MongoServerErrorToValidationError(e)
52
95
  }
53
96
  throw e
54
97
  }
55
98
  }
56
99
 
57
100
  async delete(id: string): Promise<boolean> {
101
+ this.assertId(id)
58
102
  const result: DeleteResult = await this._model.deleteOne({_id: id}).exec()
59
103
  return result.deletedCount == 1
60
104
  }
61
105
 
62
106
  async findById(id: string): Promise<T | null> {
63
- const item: mongoose.HydratedDocument<T> | null = await this._model.findById(id).populate(this._populateFields).exec()
64
- return item
107
+
108
+ const item = await this._model
109
+ .findById(id)
110
+ .populate(this._populateFields)
111
+ .lean(this._lean)
112
+ .exec()
113
+
114
+ return item as T;
65
115
  }
66
116
 
67
117
  async findByIds(ids: Array<string>): Promise<T[]> {
68
- const items: mongoose.HydratedDocument<T>[] = await this._model.find({_id: {$in: ids}}).populate(this._populateFields).exec()
69
- return items
118
+
119
+ const items = await this._model
120
+ .find({_id: {$in: ids}})
121
+ .populate(this._populateFields)
122
+ .lean(this._lean)
123
+ .exec()
124
+
125
+
126
+ return items as T[]
70
127
  }
71
128
 
72
129
  async findOneBy(field: string, value: any): Promise<T | null> {
73
130
  const filter: any = {[field]: value}
74
- const item: mongoose.HydratedDocument<T> | null = await this._model.findOne(filter).populate(this._populateFields).exec()
75
- return item
131
+
132
+ const item = await this._model
133
+ .findOne(filter)
134
+ .populate(this._populateFields)
135
+ .lean(this._lean)
136
+ .exec()
137
+
138
+
139
+ return item as T
76
140
  }
77
141
 
78
- async findBy(field: string, value: any): Promise<T[]> {
142
+ async findBy(field: string, value: any, limit: number = 0): Promise<T[]> {
79
143
  const filter: any = {[field]: value}
80
- const items: mongoose.HydratedDocument<T>[] = await this._model.find(filter).populate(this._populateFields).exec()
81
- return items
144
+ const items = await this._model
145
+ .find(filter)
146
+ .limit(limit)
147
+ .populate(this._populateFields)
148
+ .lean(this._lean)
149
+ .exec()
150
+
151
+
152
+ return items as T[]
82
153
  }
83
154
 
84
155
  async fetchAll(): Promise<T[]> {
85
- const items: mongoose.HydratedDocument<T>[] = await this._model.find().populate(this._populateFields).exec()
86
- return items
156
+
157
+ const items = await this._model
158
+ .find()
159
+ .populate(this._populateFields)
160
+ .lean(this._lean)
161
+ .exec()
162
+
163
+
164
+ return items as T[]
87
165
  }
88
166
 
89
167
  async search(value: string, limit: number = 1000, filters: IDraxFieldFilter[] =[]): Promise<T[]> {
90
168
 
91
169
  const query = {}
92
170
 
93
- if (value) {
171
+ if(mongoose.Types.ObjectId.isValid(value)) {
172
+ query['_id'] = new mongoose.Types.ObjectId(value)
173
+ }else if (value) {
94
174
  query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(value.toString(), 'i')}))
95
175
  }
96
176
 
97
177
  MongooseQueryFilter.applyFilters(query, filters)
98
178
 
99
- const items: mongoose.HydratedDocument<T>[] = await this._model.find(query).limit(limit).exec()
100
- return items
179
+ const items = await this._model
180
+ .find(query)
181
+ .limit(limit)
182
+ .populate(this._populateFields)
183
+ .lean(this._lean)
184
+ .exec()
185
+
186
+
187
+ return items as T[]
101
188
  }
102
189
 
103
190
 
@@ -105,22 +192,27 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
105
192
  page = 1,
106
193
  limit = 5,
107
194
  orderBy = '',
108
- order = false,
195
+ order = "asc",
109
196
  search = '',
110
197
  filters = []
111
198
  }: IDraxPaginateOptions): Promise<IDraxPaginateResult<T>> {
112
199
 
113
200
  const query = {}
114
201
 
115
- if (search) {
116
- query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search, 'i')}))
202
+ if(search){
203
+ if(mongoose.Types.ObjectId.isValid(search)) {
204
+ query['_id'] = new mongoose.Types.ObjectId(search)
205
+ }else{
206
+ query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search.toString(), 'i')}))
207
+ }
117
208
  }
118
209
 
119
210
  MongooseQueryFilter.applyFilters(query, filters)
120
211
 
121
212
  const sort = MongooseSort.applySort(orderBy, order)
122
213
  const populate = this._populateFields
123
- const options = {page, limit, sort, populate} as PaginateOptions
214
+ const lean = this._lean
215
+ const options = {page, limit, sort, populate, lean} as PaginateOptions
124
216
  const items: PaginateResult<T> = await this._model.paginate(query, options)
125
217
  return {
126
218
  page: page,
@@ -137,14 +229,23 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
137
229
 
138
230
  const query = {}
139
231
 
140
- if (search) {
141
- query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search, 'i')}))
232
+ if(search){
233
+ if(mongoose.Types.ObjectId.isValid(search)) {
234
+ query['_id'] = new mongoose.Types.ObjectId(search)
235
+ }else{
236
+ query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search.toString(), 'i')}))
237
+ }
142
238
  }
143
239
 
144
240
  MongooseQueryFilter.applyFilters(query, filters)
145
241
 
146
- const populate = this._populateFields
147
- return this._model.findOne(query).populate(populate)
242
+ const item = this._model
243
+ .findOne(query)
244
+ .populate(this._populateFields)
245
+ .lean(this._lean)
246
+ .exec()
247
+
248
+ return item as T
148
249
  }
149
250
 
150
251
  async find({
@@ -157,15 +258,27 @@ class AbstractMongoRepository<T, C, U> implements IDraxCrud<T, C, U> {
157
258
 
158
259
  const query = {}
159
260
 
160
- if (search) {
161
- query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search, 'i')}))
261
+ if(search){
262
+ if(mongoose.Types.ObjectId.isValid(search)) {
263
+ query['_id'] = new mongoose.Types.ObjectId(search)
264
+ }else{
265
+ query['$or'] = this._searchFields.map(field => ({[field]: new RegExp(search.toString(), 'i')}))
266
+ }
162
267
  }
163
268
 
164
269
  MongooseQueryFilter.applyFilters(query, filters)
165
270
 
166
271
  const sort = MongooseSort.applySort(orderBy, order)
167
- const populate = this._populateFields
168
- return this._model.find(query).limit(limit).sort(sort).populate(populate)
272
+ const items = await this._model
273
+ .find(query)
274
+ .limit(limit)
275
+ .sort(sort)
276
+ .populate(this._populateFields)
277
+ .lean(this._lean)
278
+ .exec()
279
+
280
+
281
+ return items as T[]
169
282
  }
170
283
 
171
284
  async findCursor({
@@ -1,59 +1,103 @@
1
1
  import sqlite from "better-sqlite3";
2
- import type {IDraxCrud, IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
2
+ import type {IDraxCrud, IDraxFindOptions, IDraxPaginateOptions, IDraxPaginateResult} from "@drax/crud-share";
3
3
  import {randomUUID} from "node:crypto";
4
4
  import {
5
5
  SqlSort, SqlQueryFilter, SqliteTableBuilder, SqliteTableField,
6
- SqliteErrorToValidationError} from "@drax/common-back";
6
+ SqliteErrorToValidationError
7
+ } from "@drax/common-back";
7
8
 
8
9
 
9
-
10
- class AbstractSqliteRepository<T> implements IDraxCrud<T, T, T>{
10
+ class AbstractSqliteRepository<T, C, U> implements IDraxCrud<T, C, U> {
11
11
  protected db: any;
12
- protected tableName: string;
13
- protected dataBase: string;
12
+ protected dataBaseFile: string;
13
+ protected tableName: string = '';
14
14
  protected searchFields: string[] = [];
15
15
  protected booleanFields: string[] = [];
16
- protected identifier: string = 'id';
17
- protected verbose: boolean;
16
+ protected identifier: string = '_id';
17
+ protected populateFields: { field: string, table: string, identifier: string }[]
18
18
  protected tableFields: SqliteTableField[];
19
+ protected verbose: boolean;
19
20
 
20
- constructor(dataBase:string, tableName: string, identifier:string = 'id',searchFields:string[] = [], booleanFields:string[] = [], verbose:boolean = false) {
21
- if(!dataBase){
22
- throw new Error("dataBase is required")
23
- }
24
-
25
- if(!tableName){
26
- throw new Error("tableName is required")
21
+ constructor(dataBaseFile: string, verbose: boolean = false) {
22
+ if (!dataBaseFile) {
23
+ throw new Error("dataBaseFile is required")
27
24
  }
28
25
 
29
-
30
- this.dataBase = dataBase;
31
- this.tableName = tableName
32
- this.identifier = identifier
33
- this.searchFields = searchFields
34
- this.booleanFields = booleanFields
26
+ this.dataBaseFile = dataBaseFile;
35
27
  this.verbose = verbose;
36
- this.db = new sqlite(dataBase, {verbose: verbose ? console.log : null});
28
+ this.db = new sqlite(dataBaseFile, {verbose: verbose ? console.log : null});
37
29
  }
38
30
 
39
31
  build() {
40
- const builder = new SqliteTableBuilder(this.dataBase, this.tableName, this.tableFields, this.verbose);
32
+ const builder = new SqliteTableBuilder(this.dataBaseFile, this.tableName, this.tableFields, this.verbose);
41
33
  builder.build(this.identifier)
42
34
  }
43
35
 
36
+ hasCreatedAt() {
37
+ return this.tableFields.some(field => field.name === 'createdAt')
38
+ }
39
+
40
+ hasUpdatedAt() {
41
+ return this.tableFields.some(field => field.name === 'updatedAt')
42
+ }
43
+
44
+ async prepareData(data: any){
45
+ return data
46
+ }
47
+
48
+ async prepareItem(item: any) {
49
+ return item
50
+ }
51
+
52
+ async execPopulate(item: any) {
53
+ for (const field of this.populateFields) {
54
+ if (item[field.field]) {
55
+ item[field.field] = this.db.prepare(`SELECT *
56
+ FROM ${field.table}
57
+ WHERE ${field.identifier} = ?`).get(item[field.field]);
58
+ }
59
+ }
60
+ return item
61
+ }
62
+
63
+ castToBoolean(item: any) {
64
+ for (const field of this.booleanFields) {
65
+ if(item[field] != undefined){
66
+ item[field] = item[field] === 1 || item[field] === 'true'
67
+ }
68
+
69
+ }
70
+ }
71
+
72
+ async decorate(item: any) {
73
+ await this.execPopulate(item)
74
+ this.castToBoolean(item)
75
+ await this.prepareItem(item)
76
+ }
77
+
44
78
  async create(data: any): Promise<T> {
45
- try{
79
+ try {
46
80
 
47
- if(!data[this.identifier]){
81
+ if (!data[this.identifier]) {
48
82
  data[this.identifier] = randomUUID()
49
83
  }
50
84
 
51
- for(const key in data){
52
- if(typeof data[key] === 'boolean'){
53
- data[key] = data[key]? 1 : 0
85
+ for (const key in data) {
86
+ if (typeof data[key] === 'boolean') {
87
+ data[key] = data[key] ? 1 : 0
54
88
  }
55
89
  }
56
90
 
91
+ if (this.hasCreatedAt()) {
92
+ data.createdAt = (new Date().toISOString())
93
+ }
94
+
95
+ if (this.hasUpdatedAt()) {
96
+ data.updatedAt = (new Date().toISOString())
97
+ }
98
+
99
+ await this.prepareData(data)
100
+
57
101
  const fields = Object.keys(data)
58
102
  .map(field => `${field}`)
59
103
  .join(', ');
@@ -62,47 +106,53 @@ class AbstractSqliteRepository<T> implements IDraxCrud<T, T, T>{
62
106
  .map(field => `@${field}`)
63
107
  .join(', ');
64
108
 
65
- const stmt = this.db.prepare(`INSERT INTO ${this.tableName} (${fields}) VALUES (${values})`);
109
+ const stmt = this.db.prepare(`INSERT INTO ${this.tableName} (${fields})
110
+ VALUES (${values})`);
66
111
  stmt.run(data)
67
- return this.findById(data[this.identifier])
68
- }catch (e){
112
+
113
+ const item = await this.findById(data[this.identifier])
114
+ return item
115
+
116
+ } catch (e) {
69
117
  console.log(e)
70
118
  throw SqliteErrorToValidationError(e, data)
71
119
  }
72
120
  }
73
121
 
74
- async findById(id: string): Promise<T | null>{
75
- const item = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE ${this.identifier} = ?`).get(id);
76
- return item
77
- }
78
-
79
- async findBy(field: string, value: any): Promise<T[] | null>{
80
- const item = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE ${field} = ?`).all(value);
81
- return item
122
+ async updatePartial(id: string, data: any): Promise<T> {
123
+ return await this.update(id, data)
82
124
  }
83
125
 
84
- async findOneBy(field: string, value: any): Promise<T | null>{
85
- const item = this.db.prepare(`SELECT * FROM ${this.tableName} WHERE ${field} = ?`).get(value);
86
- return item
87
- }
88
126
 
89
127
  async update(id: string, data: any): Promise<T> {
90
- try{
128
+ try {
91
129
 
92
- for(const key in data){
93
- if(typeof data[key] === 'boolean'){
94
- data[key] = data[key]? 1 : 0
130
+ for (const key in data) {
131
+ if (typeof data[key] === 'boolean') {
132
+ data[key] = data[key] ? 1 : 0
95
133
  }
96
134
  }
97
135
 
136
+ if (this.hasUpdatedAt()) {
137
+ data.updatedAt = (new Date().toISOString())
138
+ }
139
+
140
+ await this.prepareData(data)
141
+
98
142
  const setClauses = Object.keys(data)
99
143
  .map(field => `${field} = @${field}`)
100
144
  .join(', ');
145
+
101
146
  data.identifier = id
102
- const stmt = this.db.prepare( `UPDATE ${this.tableName} SET ${setClauses} WHERE ${this.identifier} = @identifier `);
147
+
148
+ const stmt = this.db.prepare(`UPDATE ${this.tableName}
149
+ SET ${setClauses}
150
+ WHERE ${this.identifier} = @identifier `);
103
151
  stmt.run(data);
104
- return this.findById(id)
105
- }catch (e){
152
+ const item = await this.findById(id)
153
+ return item
154
+
155
+ } catch (e) {
106
156
  console.log(e)
107
157
  throw SqliteErrorToValidationError(e, data)
108
158
  }
@@ -111,24 +161,33 @@ class AbstractSqliteRepository<T> implements IDraxCrud<T, T, T>{
111
161
 
112
162
 
113
163
  async delete(id: string): Promise<boolean> {
114
- const stmt = this.db.prepare(`DELETE FROM ${this.tableName} WHERE ${this.identifier} = ?`);
164
+ const stmt = this.db.prepare(`DELETE
165
+ FROM ${this.tableName}
166
+ WHERE ${this.identifier} = ?`);
115
167
  stmt.run(id);
116
168
  return true
117
169
  }
118
170
 
171
+ async deleteAll(): Promise<boolean> {
172
+ const stmt = this.db.prepare(`DELETE
173
+ FROM ${this.tableName}`);
174
+ stmt.run();
175
+ return true
176
+ }
119
177
 
120
178
 
121
179
  async paginate({
122
- page= 1,
123
- limit= 5,
124
- orderBy= '',
125
- order= 'desc',
126
- search= '',
127
- filters= []} : IDraxPaginateOptions): Promise<IDraxPaginateResult<T>>{
180
+ page = 1,
181
+ limit = 5,
182
+ orderBy = '',
183
+ order = 'desc',
184
+ search = '',
185
+ filters = []
186
+ }: IDraxPaginateOptions): Promise<IDraxPaginateResult<T>> {
128
187
 
129
188
  const offset = page > 1 ? (page - 1) * limit : 0
130
189
 
131
- let where=""
190
+ let where = ""
132
191
  if (search && this.searchFields.length > 0) {
133
192
  where = ` WHERE ${this.searchFields.map(field => `${field} LIKE '%${search}%'`).join(" OR ")}`
134
193
  }
@@ -139,16 +198,14 @@ class AbstractSqliteRepository<T> implements IDraxCrud<T, T, T>{
139
198
 
140
199
  const sort = SqlSort.applySort(orderBy, order)
141
200
 
142
- const rCount = this.db.prepare(`SELECT COUNT(*) as count FROM ${this.tableName} ${where}`).get();
143
- const items = this.db.prepare(`SELECT * FROM ${this.tableName} ${where} ${sort} LIMIT ? OFFSET ? `).all([limit, offset]) as T[];
201
+ const rCount = this.db.prepare(`SELECT COUNT(*) as count
202
+ FROM ${this.tableName} ${where}`).get();
203
+ const items = this.db.prepare(`SELECT *
204
+ FROM ${this.tableName} ${where} ${sort} LIMIT ?
205
+ OFFSET ? `).all([limit, offset]) as T[];
144
206
 
145
- for(const item of items){
146
- for(const key in item) {
147
- if (this.booleanFields.includes(key)) {
148
- //@ts-ignore
149
- item[key] = item[key] ? true : false
150
- }
151
- }
207
+ for (const item of items) {
208
+ await this.decorate(item)
152
209
  }
153
210
 
154
211
  return {
@@ -159,20 +216,87 @@ class AbstractSqliteRepository<T> implements IDraxCrud<T, T, T>{
159
216
  }
160
217
  }
161
218
 
162
- async fetchAll(): Promise<any[]>{
163
- const items = this.db.prepare(`SELECT * FROM ${this.tableName}`).all();
219
+ async find({
220
+ limit = 5,
221
+ orderBy = '',
222
+ order = 'desc',
223
+ search = '',
224
+ filters = []
225
+ }: IDraxFindOptions): Promise<any[]> {
226
+
227
+
228
+ let where = ""
229
+ if (search && this.searchFields.length > 0) {
230
+ where = ` WHERE ${this.searchFields.map(field => `${field} LIKE '%${search}%'`).join(" OR ")}`
231
+ }
232
+
233
+ if (filters.length > 0) {
234
+ where = SqlQueryFilter.applyFilters(where, filters)
235
+ }
236
+
237
+ const sort = SqlSort.applySort(orderBy, order)
238
+
239
+ const rCount = this.db.prepare(`SELECT COUNT(*) as count
240
+ FROM ${this.tableName} ${where}`).get();
241
+ const items = this.db.prepare(`SELECT *
242
+ FROM ${this.tableName} ${where} ${sort} LIMIT ? `).all([limit]) as T[];
243
+
244
+ for (const item of items) {
245
+ await this.decorate(item)
246
+ }
247
+
248
+ return items
249
+ }
250
+
251
+ async fetchAll(): Promise<any[]> {
252
+ const items = this.db.prepare(`SELECT *
253
+ FROM ${this.tableName}`).all();
254
+ for (const item of items) {
255
+ await this.decorate(item)
256
+ }
164
257
  return items
165
258
  }
166
259
 
167
- async search(value: any, limit: number = 1000): Promise<any[]>{
168
- let where=""
260
+ async search(value: any, limit: number = 1000): Promise<any[]> {
261
+ let where = ""
169
262
  if (value && this.searchFields.length > 0) {
170
263
  where = ` WHERE ${this.searchFields.map(field => `${field} LIKE '%${value}%'`).join(" OR ")}`
171
264
  }
172
- const items = this.db.prepare(`SELECT * FROM ${this.tableName} ${where}`).all();
265
+ const items = this.db.prepare(`SELECT *
266
+ FROM ${this.tableName} ${where} LIMIT ${limit}`).all();
267
+
268
+ for (const item of items) {
269
+ await this.decorate(item)
270
+ }
271
+
272
+ return items
273
+ }
274
+
275
+ async findById(id: string): Promise<T | null> {
276
+ const item = this.db.prepare(`SELECT *
277
+ FROM ${this.tableName}
278
+ WHERE ${this.identifier} = ?`).get(id);
279
+ await this.decorate(item)
280
+ return item
281
+ }
282
+
283
+ async findBy(field: string, value: any, limit: number = 0): Promise<T[] | null> {
284
+ const items = this.db.prepare(`SELECT *
285
+ FROM ${this.tableName}
286
+ WHERE ${field} = ? LIMIT ${limit}`).all(value);
287
+ for (const item of items) {
288
+ await this.decorate(item)
289
+ }
173
290
  return items
174
291
  }
175
292
 
293
+ async findOneBy(field: string, value: any): Promise<T | null> {
294
+ const item = this.db.prepare(`SELECT *
295
+ FROM ${this.tableName}
296
+ WHERE ${field} = ?`).get(value);
297
+ await this.decorate(item)
298
+ return item
299
+ }
176
300
  }
177
301
 
178
302
  export default AbstractSqliteRepository
@@ -0,0 +1,12 @@
1
+ import z from "zod"
2
+
3
+ const DeleteBodyResponseSchema = z.object({
4
+ id: z.string(),
5
+ deleted: z.boolean(),
6
+ deletedAt: z.string(),
7
+ message: z.string()
8
+ });
9
+
10
+ export default DeleteBodyResponseSchema
11
+
12
+ export {DeleteBodyResponseSchema}