@ecopex/ecopex-framework 1.0.10 → 1.0.12

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/index.js CHANGED
@@ -15,7 +15,7 @@ const start = async (config) => {
15
15
 
16
16
  module.exports = {
17
17
  start,
18
- db: knex.connection.db,
18
+ knex: knex.connection,
19
19
  date: date,
20
20
  jwt: jwt,
21
21
  bcrypt: bcrypt,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecopex/ecopex-framework",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "Javascript Framework for API and Admin Panel",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -26,6 +26,7 @@ async function getAll(request, reply, routeOptions = {}) {
26
26
  const routeConfig = routeOptions.routeConfig || {};
27
27
  const primaryKey = routeOptions.primaryKey || 'id';
28
28
  const filters = routeOptions.filters || {};
29
+ const joinTables = routeOptions.joinTables || {};
29
30
  const splitOrder = order.split(':');
30
31
  const orderBy = `${tableName}.${(splitOrder[0] || primaryKey)}`;
31
32
  const orderDirection = splitOrder[1] || 'desc';
@@ -49,18 +50,18 @@ async function getAll(request, reply, routeOptions = {}) {
49
50
  query.where(routeConfig.owned, request.user?.id || 0);
50
51
  query.where(routeConfig.owned_type, request.user?.type || 'user');
51
52
  }
52
-
53
- if(routeConfig.join_tables) {
54
- for(let i = 0; i < Object.values(routeConfig.join_tables).length; i++) {
55
- const tableKey = Object.keys(routeConfig.join_tables)[i];
56
- let joinTable = Object.values(routeConfig.join_tables)[i];
53
+
54
+ if(joinTables) {
55
+ for(let i = 0; i < Object.values(joinTables).length; i++) {
56
+ const tableKey = Object.keys(joinTables)[i];
57
+ let joinTable = Object.values(joinTables)[i];
57
58
  if(joinTable.type == 'one-to-one') {
58
59
  if(joinTable.extra_where) {
59
60
  query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key} = ${tableKey}.${joinTable.primary_key} AND ${joinTable.extra_where}`);
60
61
  } else {
61
62
  query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key}`, `${tableKey}.${joinTable.primary_key}`);
62
63
  }
63
- query.select(`${tableKey}.*`);
64
+ query.select(knex.connection.db.raw(Object.entries(joinTable.properties || {}).map(n => `${tableKey}.${n[0]} as ${n[0]}`).join(', ')));
64
65
  }
65
66
  }
66
67
 
@@ -107,14 +108,11 @@ async function getAll(request, reply, routeOptions = {}) {
107
108
 
108
109
  const total = parseInt(count);
109
110
 
110
- const rows = structureRows(items, tableName, routeConfig.join_tables)
111
+ const rows = structureRows(items, tableName, joinTables)
111
112
 
112
113
  // Process join tables if configured
113
- const processedItems = await processJoinTables(rows, routeConfig.join_tables);
114
+ const processedItems = await processJoinTables(rows, joinTables);
114
115
 
115
- // console.log(processedItems);
116
-
117
-
118
116
  const totalPages = Math.ceil(total / limit);
119
117
 
120
118
  return reply.send({
@@ -143,33 +141,30 @@ async function getAll(request, reply, routeOptions = {}) {
143
141
  * @param {Object} routeOptions - The route options
144
142
  * @returns {Promise<Object>} - The response object
145
143
  */
146
- async function getById(request, reply, routeOptions = {}) {
144
+ async function getById(request, reply, routeOptions = {}, inner = false) {
147
145
 
148
146
  if(routeOptions.store) {
149
147
  return get_by_primary_key(routeOptions.store, request.params[routeOptions.primaryKey], reply, routeOptions);
150
148
  }
151
149
 
152
150
  try {
153
- const primaryKey = routeOptions.primaryKey || 'id';
154
- const { [primaryKey]: id } = request.params;
155
151
  const tableName = routeOptions.tableName || 'users';
156
- const routeConfig = routeOptions.routeConfig || {};
157
-
152
+ const joinTables = routeOptions.joinTables || {};
158
153
  const item_query = knex.connection.db(tableName)
159
154
  .select(`${tableName}.*`)
160
- .where(primaryKey, id);
161
-
162
- if(routeConfig.join_tables) {
163
- for(let i = 0; i < Object.values(routeConfig.join_tables).length; i++) {
164
- const tableKey = Object.keys(routeConfig.join_tables)[i];
165
- let joinTable = Object.values(routeConfig.join_tables)[i];
155
+ .where(request.params);
156
+
157
+ if(joinTables) {
158
+ for(let i = 0; i < Object.values(joinTables).length; i++) {
159
+ const tableKey = Object.keys(joinTables)[i];
160
+ let joinTable = Object.values(joinTables)[i];
166
161
  if(joinTable.type == 'one-to-one') {
167
162
  if(joinTable.extra_where) {
168
163
  item_query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key} = ${tableKey}.${joinTable.primary_key} AND ${joinTable.extra_where}`);
169
164
  } else {
170
165
  item_query.leftJoin(joinTable.table + ' as ' + tableKey, `${tableName}.${joinTable.foreign_key}`, `${tableKey}.${joinTable.primary_key}`);
171
166
  }
172
- item_query.select(`${tableKey}.*`);
167
+ item_query.select(knex.connection.db.raw(Object.entries(joinTable.properties || {}).map(n => `${tableKey}.${n[0]} as ${n[0]}`).join(', ')));
173
168
  }
174
169
  }
175
170
 
@@ -177,16 +172,15 @@ async function getById(request, reply, routeOptions = {}) {
177
172
  }
178
173
 
179
174
  const item_data = await item_query.first();
180
- console.log(item_data);
181
175
 
182
176
  let item = {}
183
177
 
184
178
 
185
- if(routeConfig.join_tables) {
179
+ if(joinTables) {
186
180
  item = {
187
181
  ...item_data[tableName],
188
182
  }
189
- const join_one_to_one = Object.entries(routeConfig.join_tables).filter(n => n[1].type === 'one-to-one');
183
+ const join_one_to_one = Object.entries(joinTables).filter(n => n[1].type === 'one-to-one');
190
184
  if(join_one_to_one.length > 0) {
191
185
  for(let i = 0; i < join_one_to_one.length; i++) {
192
186
  const join_table = join_one_to_one[i];
@@ -198,26 +192,44 @@ async function getById(request, reply, routeOptions = {}) {
198
192
  }
199
193
 
200
194
  if (!item) {
201
- return reply.status(404).send({
202
- status: false,
203
- message: request.t('messages.record_not_found')
204
- });
195
+ if(!inner) {
196
+ return reply.status(404).send({
197
+ status: false,
198
+ message: request.t('messages.record_not_found')
199
+ });
200
+ } else {
201
+ return {
202
+ status: false,
203
+ message: request.t('messages.record_not_found')
204
+ };
205
+ }
205
206
  }
206
207
 
207
208
  // Process join tables if configured
208
- const processedItem = await processJoinTables([item], routeConfig.join_tables);
209
+ const processedItem = await processJoinTables([item], joinTables);
209
210
  const result = processedItem[0];
210
211
 
211
- return reply.send({
212
- status: true,
213
- data: result
214
- });
212
+ if(!inner) {
213
+ return reply.send({
214
+ status: true,
215
+ data: result
216
+ });
217
+ } else {
218
+ return result;
219
+ }
215
220
  } catch (error) {
216
221
  console.error('Error getting record by ID:', error);
217
- return reply.status(500).send({
218
- status: false,
219
- message: request.t('messages.internal_server_error')
220
- });
222
+ if(!inner) {
223
+ return reply.status(500).send({
224
+ status: false,
225
+ message: request.t('messages.internal_server_error')
226
+ });
227
+ } else {
228
+ return {
229
+ status: false,
230
+ message: request.t('messages.internal_server_error')
231
+ };
232
+ }
221
233
  }
222
234
  }
223
235
 
@@ -237,7 +249,6 @@ async function create(request, reply, routeOptions = {}) {
237
249
  try {
238
250
  const tableName = routeOptions.tableName || 'users';
239
251
  const primaryKey = routeOptions.primaryKey || 'id';
240
- const routeConfig = routeOptions.routeConfig || {};
241
252
  const schema = routeOptions.schema || {};
242
253
 
243
254
  // Use payload field if available, otherwise use request.body directly
@@ -259,18 +270,14 @@ async function create(request, reply, routeOptions = {}) {
259
270
  }
260
271
  }
261
272
  }
262
-
273
+
263
274
  try {
264
275
  const [id] = await knex.connection.db(tableName)
265
276
  .insert({
266
- ...data,
267
- created_at: new Date(),
268
- updated_at: new Date()
277
+ ...data
269
278
  });
270
279
 
271
- const item = await knex.connection.db(tableName)
272
- .where(primaryKey, id)
273
- .first();
280
+ const item = await getById({ ...request, params: { [primaryKey]: id } }, {}, { ...routeOptions, primaryKey: primaryKey }, true)
274
281
 
275
282
  return reply.send({
276
283
  status: true,
@@ -314,8 +321,8 @@ async function update(request, reply, routeOptions = {}) {
314
321
  try {
315
322
  const tableName = routeOptions.tableName || 'users';
316
323
  const primaryKey = routeOptions.primaryKey || 'id';
317
- const routeConfig = routeOptions.routeConfig || {};
318
324
  const schema = routeOptions.schema || {};
325
+ const routeConfig = routeOptions.routeConfig || {};
319
326
 
320
327
  // Use payload field if available, otherwise use request.body directly
321
328
  let data = request.body;
@@ -370,9 +377,7 @@ async function update(request, reply, routeOptions = {}) {
370
377
  updated_at: new Date()
371
378
  })
372
379
 
373
- const updatedItem = await knex.connection.db(tableName)
374
- .where(request.params)
375
- .first();
380
+ const updatedItem = await getById({ ...request }, {}, { ...routeOptions, primaryKey: primaryKey }, true);
376
381
 
377
382
  return reply.send({
378
383
  status: true,
@@ -403,11 +408,10 @@ async function upload(request, reply, routeOptions = {}) {
403
408
  try {
404
409
  const tableName = routeOptions.tableName || 'users';
405
410
  const primaryKey = routeOptions.primaryKey || 'id';
406
- const { [primaryKey]: id } = request.params;
407
411
  const routeConfig = routeOptions.routeConfig || {};
408
412
 
409
413
  const existingItem = await knex.connection.db(tableName)
410
- .where(primaryKey, id)
414
+ .where(request.params)
411
415
  .first();
412
416
 
413
417
  if (!existingItem) {
@@ -417,7 +421,7 @@ async function upload(request, reply, routeOptions = {}) {
417
421
  });
418
422
  }
419
423
 
420
- const uploadResult = await uploadFile(request.body[routeConfig.upload_field], id, tableName);
424
+ const uploadResult = await uploadFile(request.body[routeConfig.upload_field], request.params[primaryKey], tableName);
421
425
  if(!uploadResult.status) {
422
426
  return reply.status(500).send({
423
427
  status: false,
@@ -426,7 +430,7 @@ async function upload(request, reply, routeOptions = {}) {
426
430
  }
427
431
 
428
432
  await knex.connection.db(tableName)
429
- .where(primaryKey, id)
433
+ .where(request.params)
430
434
  .update({
431
435
  [routeConfig.upload_field]: uploadResult.file.fileUrl
432
436
  });
@@ -67,6 +67,7 @@ class JsonRouteLoader {
67
67
  const store = config.store || null;
68
68
  const routes = config.routes || {};
69
69
  const schema = config.schema || {};
70
+ const joinTables = config.join_tables || {};
70
71
 
71
72
  // Validate configuration
72
73
  this.validateConfig(config);
@@ -76,7 +77,7 @@ class JsonRouteLoader {
76
77
  const routeName = route.action;
77
78
  const routeConfig = route;
78
79
  if (this.supportedRoutes.includes(routeName)) {
79
- await this.registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, type);
80
+ await this.registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, joinTables, type);
80
81
  if(store) {
81
82
  await add_model(store, primaryKey, schema);
82
83
  }
@@ -112,9 +113,9 @@ class JsonRouteLoader {
112
113
  * @param {string} routeName - Route name (list, get, create, update, delete)
113
114
  * @param {Object} routeConfig - Route configuration
114
115
  */
115
- async registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, type = 'service') {
116
+ async registerRoute(fastify, tableName, routeName, routeConfig, primaryKey, workerName, fileName, store, schema, joinTables, type = 'service') {
116
117
 
117
- const routeDefinition = this.generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type);
118
+ const routeDefinition = this.generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type, joinTables);
118
119
  const routeKey = `${routeDefinition.method}:${routeDefinition.url}`;
119
120
 
120
121
  if (this.registeredRoutes.has(routeKey)) {
@@ -149,7 +150,7 @@ class JsonRouteLoader {
149
150
  },
150
151
  handler: async (request, reply) => {
151
152
  // Pass table name and route config to handler as additional parameters
152
- return handler(request, reply, { tableName, routeConfig, schema, primaryKey, store, filters });
153
+ return handler(request, reply, { tableName, routeConfig, schema, primaryKey, store, filters, joinTables });
153
154
  }
154
155
  });
155
156
 
@@ -167,7 +168,7 @@ class JsonRouteLoader {
167
168
  * @param {Object} routeConfig - Route configuration
168
169
  * @returns {Object} Route definition
169
170
  */
170
- generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type = 'service') {
171
+ generateRouteDefinition(tableName, routeName, routeConfig, primaryKey, fileName, schema, type = 'service', joinTables = {}) {
171
172
  const prefix = configStore.prefix ? configStore.prefix + '/' : '';
172
173
  const baseUrl = `/${prefix}${fileName}`;
173
174
  primaryKey = primaryKey || 'id';
@@ -176,32 +177,32 @@ class JsonRouteLoader {
176
177
  list: {
177
178
  method: 'GET',
178
179
  url: baseUrl,
179
- schema: this.generateListSchema(tableName, routeConfig, primaryKey, schema, type)
180
+ schema: this.generateListSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
180
181
  },
181
182
  get: {
182
183
  method: 'GET',
183
184
  url: `${baseUrl}/:${primaryKey}`,
184
- schema: this.generateGetSchema(tableName, routeConfig, primaryKey, schema, type)
185
+ schema: this.generateGetSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
185
186
  },
186
187
  create: {
187
188
  method: 'POST',
188
189
  url: baseUrl,
189
- schema: this.generateCreateSchema(tableName, routeConfig, primaryKey, schema, type)
190
+ schema: this.generateCreateSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
190
191
  },
191
192
  update: {
192
193
  method: 'PUT',
193
194
  url: `${baseUrl}/:${primaryKey}`,
194
- schema: this.generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type)
195
+ schema: this.generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
195
196
  },
196
197
  delete: {
197
198
  method: 'DELETE',
198
199
  url: `${baseUrl}/:${primaryKey}`,
199
- schema: this.generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type)
200
+ schema: this.generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type, joinTables)
200
201
  },
201
202
  upload: {
202
203
  method: 'POST',
203
- url: `${baseUrl}/:${primaryKey}/upload`,
204
- schema: this.generateUploadSchema(tableName, routeConfig, primaryKey, schema, type),
204
+ url: `${baseUrl}/:${primaryKey}/${routeConfig.upload_field || 'upload'}`,
205
+ schema: this.generateUploadSchema(tableName, routeConfig, primaryKey, schema, type, joinTables),
205
206
  validatorCompiler: ({ schema }) => {
206
207
  return (data) => {
207
208
  return true;
@@ -222,8 +223,8 @@ class JsonRouteLoader {
222
223
  * @param {Object} filters - Filters object
223
224
  * @returns {Object} Schema
224
225
  */
225
- generateListSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
226
- const itemSchema = this.generateItemSchema(schema, primaryKey);
226
+ generateListSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
227
+ const itemSchema = this.generateItemSchema(schema, primaryKey, joinTables);
227
228
 
228
229
  return {
229
230
  description: `Get all ${tableName} with pagination and search`,
@@ -281,8 +282,8 @@ class JsonRouteLoader {
281
282
  * @param {Object} routeConfig - Route configuration
282
283
  * @returns {Object} Schema
283
284
  */
284
- generateGetSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
285
- const itemSchema = this.generateItemSchema(schema, primaryKey);
285
+ generateGetSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
286
+ const itemSchema = this.generateItemSchema(schema, primaryKey, joinTables);
286
287
  primaryKey = primaryKey || 'id';
287
288
 
288
289
  return {
@@ -322,7 +323,7 @@ class JsonRouteLoader {
322
323
  * @param {Object} routeConfig - Route configuration
323
324
  * @returns {Object} Schema
324
325
  */
325
- generateCreateSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
326
+ generateCreateSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
326
327
  const bodySchema = this.generateBodySchema(schema, false, primaryKey);
327
328
 
328
329
  return {
@@ -335,7 +336,7 @@ class JsonRouteLoader {
335
336
  type: 'object',
336
337
  properties: {
337
338
  status: { type: 'boolean', default: true },
338
- data: this.generateItemSchema(schema, primaryKey)
339
+ data: this.generateItemSchema(schema, primaryKey, joinTables)
339
340
  },
340
341
  additionalProperties: false
341
342
  },
@@ -356,7 +357,7 @@ class JsonRouteLoader {
356
357
  * @param {Object} routeConfig - Route configuration
357
358
  * @returns {Object} Schema
358
359
  */
359
- generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
360
+ generateUpdateSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
360
361
  const bodySchema = this.generateBodySchema(schema, true, primaryKey, 'updatable');
361
362
 
362
363
  return {
@@ -377,7 +378,7 @@ class JsonRouteLoader {
377
378
  type: 'object',
378
379
  properties: {
379
380
  status: { type: 'boolean', default: true },
380
- data: this.generateItemSchema(schema, primaryKey)
381
+ data: this.generateItemSchema(schema, primaryKey, joinTables)
381
382
  },
382
383
  additionalProperties: false
383
384
  },
@@ -398,7 +399,7 @@ class JsonRouteLoader {
398
399
  * @param {Object} routeConfig - Route configuration
399
400
  * @returns {Object} Schema
400
401
  */
401
- generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
402
+ generateDeleteSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
402
403
  return {
403
404
  description: `Delete ${tableName} by ID`,
404
405
  tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(tableName)],
@@ -416,7 +417,7 @@ class JsonRouteLoader {
416
417
  type: 'object',
417
418
  properties: {
418
419
  status: { type: 'boolean', default: true },
419
- data: this.generateItemSchema(schema, primaryKey)
420
+ data: this.generateItemSchema(schema, primaryKey, joinTables)
420
421
  },
421
422
  additionalProperties: false
422
423
  },
@@ -437,7 +438,7 @@ class JsonRouteLoader {
437
438
  * @param {Object} routeConfig - Route configuration
438
439
  * @returns {Object} Schema
439
440
  */
440
- generateUploadSchema(tableName, routeConfig, primaryKey, schema, type = 'service') {
441
+ generateUploadSchema(tableName, routeConfig, primaryKey, schema, type = 'service', joinTables = {}) {
441
442
  const uploadField = routeConfig.upload_field || 'file';
442
443
  return {
443
444
  description: `Upload file for ${tableName} by ${primaryKey}`,
@@ -464,7 +465,7 @@ class JsonRouteLoader {
464
465
  type: 'object',
465
466
  properties: {
466
467
  status: { type: 'boolean', default: true },
467
- data: this.generateItemSchema(schema, primaryKey)
468
+ data: this.generateItemSchema(schema, primaryKey, joinTables)
468
469
  },
469
470
  additionalProperties: false
470
471
  },
@@ -484,7 +485,7 @@ class JsonRouteLoader {
484
485
  * @param {Object} itemSchema - Item schema from config
485
486
  * @returns {Object} Item schema
486
487
  */
487
- generateItemSchema(schema, primaryKey) {
488
+ generateItemSchema(schema, primaryKey, joinTables = {}) {
488
489
  if (!schema) {
489
490
  return { type: 'object' };
490
491
  }
@@ -509,6 +510,18 @@ class JsonRouteLoader {
509
510
  }
510
511
  }
511
512
 
513
+ if(Object.entries(joinTables).length > 0) {
514
+ for(const [key, value] of Object.entries(joinTables)) {
515
+ if(value.type == 'one-to-one') {
516
+ withoutReferences[value.table] = {
517
+ type: 'object',
518
+ properties: value.properties,
519
+ additionalProperties: false
520
+ };
521
+ }
522
+ }
523
+ }
524
+
512
525
  return {
513
526
  type: 'object',
514
527
  properties: withoutReferences,
@@ -147,18 +147,6 @@ async function registerRoute(fastify, routeConfig, moduleName, workerName, type
147
147
  // Build full URL
148
148
  const fullUrl = path;
149
149
 
150
- if(schema.success_response && schema.success_response.type === 'object' && schema.success_response.properties && schema.success_response.properties.pagination) {
151
- schema.success_response.properties.pagination = {
152
- type: 'object',
153
- properties: {
154
- total: { type: 'integer' },
155
- page: { type: 'integer' },
156
- limit: { type: 'integer' },
157
- totalPages: { type: 'integer' }
158
- }
159
- }
160
- }
161
-
162
150
  const schemaRoute = {
163
151
  tags: [(type == 'service' ? general.titleCase(configStore.name) + ' | ' : 'Common | ') + 'Specs | ' + general.titleCase(moduleName)],
164
152
  response: {
@@ -213,6 +201,38 @@ async function registerRoute(fastify, routeConfig, moduleName, workerName, type
213
201
  schemaRoute.security = [{ bearer: [] }];
214
202
  }
215
203
 
204
+ if(schema.pagination) {
205
+
206
+ if(schemaRoute.querystring && schemaRoute.querystring.properties) {
207
+ schemaRoute.querystring.properties = Object.assign(schemaRoute.querystring.properties || {}, {
208
+ page: { type: 'integer', minimum: 1, default: 1 },
209
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 25 },
210
+ search: { type: 'string' },
211
+ order: { type: 'string' }
212
+ });
213
+ } else {
214
+ schemaRoute.querystring = {
215
+ type: 'object',
216
+ properties: {
217
+ page: { type: 'integer', minimum: 1, default: 1 },
218
+ limit: { type: 'integer', minimum: 1, maximum: 100, default: 25 },
219
+ search: { type: 'string' },
220
+ order: { type: 'string' }
221
+ }
222
+ }
223
+ }
224
+
225
+ schemaRoute.response[200].properties.pagination = {
226
+ type: 'object',
227
+ properties: {
228
+ total: { type: 'integer' },
229
+ page: { type: 'integer' },
230
+ limit: { type: 'integer' },
231
+ totalPages: { type: 'integer' }
232
+ }
233
+ }
234
+ }
235
+
216
236
  // Register the route
217
237
  fastify.route({
218
238
  method: method.toUpperCase(),