@syntropix/database 0.0.5 → 0.1.0

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 CHANGED
@@ -1,31 +1,31 @@
1
1
  # DB TypeScript SDK
2
2
 
3
- 一个类似于 Python ORM TypeScript SDK,用于数据库操作。
3
+ A TypeScript SDK for database operations, similar to a Python ORM.
4
4
 
5
- ## 安装
5
+ ## Installation
6
6
 
7
7
  ```bash
8
8
  yarn add reflect-metadata
9
9
  ```
10
10
 
11
- ## 功能特性
11
+ ## Features
12
12
 
13
- - 🎯 **装饰器支持** - 使用 TypeScript 装饰器定义模型
14
- - 🔑 **自动主键** - 如果未定义主键,自动创建 `id` 字段
15
- - 🔗 **外键关系** - 支持外键定义和关系
16
- - 📝 **完整的 CRUD** - 提供 create, read, update, delete 操作
17
- - 🔍 **高级查询** - 支持过滤、排序、聚合、连接等
18
- - 🚀 **批量操作** - 支持批量创建和更新
19
- - 🎨 **类型安全** - 完整的 TypeScript 类型支持
13
+ - 🎯 **Decorator Support** - Define models using TypeScript decorators
14
+ - 🔑 **Automatic Primary Keys** - `id` field is automatically created if not defined
15
+ - 🔗 **Foreign Key Relations** - Supports defining and handling foreign key relations
16
+ - 📝 **Full CRUD** - Create, read, update, and delete operations
17
+ - 🔍 **Advanced Queries** - Filtering, sorting, aggregation, joins, etc.
18
+ - 🚀 **Batch Operations** - Bulk create and update support
19
+ - 🎨 **Type Safety** - Full TypeScript types, type-safe models
20
20
 
21
- ## 快速开始
21
+ ## Quick Start
22
22
 
23
- ### 1. 定义模型
23
+ ### 1. Define Models
24
24
 
25
25
  ```typescript
26
26
  import { BaseModel, Column } from 'db-ts-sdk';
27
27
 
28
- // 基础审计模型
28
+ // Audited base model
29
29
  export class Audited extends BaseModel {
30
30
  @Column({ type: 'date', name: 'created_at' })
31
31
  createdAt!: Date;
@@ -34,7 +34,7 @@ export class Audited extends BaseModel {
34
34
  updatedAt!: Date;
35
35
  }
36
36
 
37
- // 用户模型
37
+ // User model
38
38
  export class User extends Audited {
39
39
  static tableName = 'users';
40
40
 
@@ -55,28 +55,28 @@ export class User extends Audited {
55
55
  }
56
56
  ```
57
57
 
58
- ### 2. 表操作
58
+ ### 2. Table Operations
59
59
 
60
60
  ```typescript
61
- // 创建表
61
+ // Create table
62
62
  await User.createTable();
63
63
 
64
- // 删除表
64
+ // Drop table
65
65
  await User.dropTable();
66
66
 
67
- // 重命名表
67
+ // Rename table
68
68
  await User.renameTable('new_users');
69
69
 
70
- // 清空表
70
+ // Truncate table
71
71
  await User.truncateTable();
72
72
  ```
73
73
 
74
- ### 3. 数据操作
74
+ ### 3. Data Operations
75
75
 
76
- #### 创建数据
76
+ #### Create Data
77
77
 
78
78
  ```typescript
79
- // 单条创建
79
+ // Single insert
80
80
  const user = await User.create({
81
81
  id: '1',
82
82
  email: 'user@example.com',
@@ -86,7 +86,7 @@ const user = await User.create({
86
86
  updatedAt: new Date(),
87
87
  });
88
88
 
89
- // 批量创建
89
+ // Bulk insert
90
90
  await User.bulkCreate(
91
91
  [
92
92
  {
@@ -106,19 +106,19 @@ await User.bulkCreate(
106
106
  updatedAt: new Date(),
107
107
  },
108
108
  ],
109
- 32,
110
- ); // 批次大小
109
+ 32, // Batch size
110
+ );
111
111
  ```
112
112
 
113
- #### 查询数据
113
+ #### Query Data
114
114
 
115
115
  ```typescript
116
116
  import { AND, EQ, OR, GTE } from 'db-ts-sdk';
117
117
 
118
- // 获取单个记录
118
+ // Get a single record
119
119
  const user = await User.get(OR(AND(EQ('email', 'user@example.com'))));
120
120
 
121
- // 过滤查询
121
+ // Filter query
122
122
  const activeUsers = await User.filter({
123
123
  filter: OR(AND(EQ('is_active', true))),
124
124
  limit: 10,
@@ -126,38 +126,38 @@ const activeUsers = await User.filter({
126
126
  sort: { column: 'created_at', order: 'DESC' },
127
127
  });
128
128
 
129
- // 统计数量
129
+ // Count records
130
130
  const count = await User.count({
131
131
  filter: OR(AND(EQ('is_active', true))),
132
132
  });
133
133
  ```
134
134
 
135
- #### 更新数据
135
+ #### Update Data
136
136
 
137
137
  ```typescript
138
- // 实例更新
138
+ // Instance update
139
139
  const user = await User.get(OR(AND(EQ('id', '1'))));
140
140
  user.fullName = 'Jane Doe';
141
141
  await user.save();
142
142
 
143
- // 批量更新
143
+ // Bulk update
144
144
  await User.update(OR(AND(EQ('is_active', false))), { isActive: true });
145
145
  ```
146
146
 
147
- #### 删除数据
147
+ #### Delete Data
148
148
 
149
149
  ```typescript
150
- // 实例删除
150
+ // Instance delete
151
151
  const user = await User.get(OR(AND(EQ('id', '1'))));
152
152
  await user.remove();
153
153
 
154
- // 批量删除
154
+ // Bulk delete
155
155
  await User.delete(OR(AND(EQ('is_active', false))));
156
156
  ```
157
157
 
158
- ## 字段类型
158
+ ## Field Types
159
159
 
160
- SDK 支持多种字段类型:
160
+ The SDK supports various field types:
161
161
 
162
162
  ```typescript
163
163
  import {
@@ -180,22 +180,22 @@ import {
180
180
  } from 'db-ts-sdk';
181
181
  ```
182
182
 
183
- ### 使用装饰器
183
+ ### Using Decorators
184
184
 
185
185
  ```typescript
186
186
  @Column({
187
- type: 'string', // 字段类型
188
- name: 'column_name', // 数据库列名(可选)
189
- description: 'desc', // 描述(可选)
190
- primary: false, // 是否主键(可选)
191
- nullable: false, // 是否可为空(可选)
192
- auto_increment: false, // 是否自增(可选)
193
- default: null // 默认值(可选)
187
+ type: 'string', // Field type
188
+ name: 'column_name', // Database column name (optional)
189
+ description: 'desc', // Description (optional)
190
+ primary: false, // Is primary key (optional)
191
+ nullable: false, // Nullable (optional)
192
+ auto_increment: false, // Auto increment (optional)
193
+ default: null // Default value (optional)
194
194
  })
195
195
  fieldName!: string;
196
196
  ```
197
197
 
198
- ### 外键字段
198
+ ### Foreign Key Fields
199
199
 
200
200
  ```typescript
201
201
  import { ForeignKey } from 'db-ts-sdk';
@@ -208,42 +208,42 @@ import { ForeignKey } from 'db-ts-sdk';
208
208
  userId!: number;
209
209
  ```
210
210
 
211
- ## 过滤器构建
211
+ ## Filter Builder
212
212
 
213
213
  ```typescript
214
214
  import { AND, OR, EQ, NE, GT, GTE, LT, LTE, IN, LIKE } from 'db-ts-sdk';
215
215
 
216
- // 等于
216
+ // Equals
217
217
  EQ('field', value);
218
218
 
219
- // 不等于
219
+ // Not equals
220
220
  NE('field', value);
221
221
 
222
- // 大于
222
+ // Greater than
223
223
  GT('field', value);
224
224
 
225
- // 大于等于
225
+ // Greater than or equal
226
226
  GTE('field', value);
227
227
 
228
- // 小于
228
+ // Less than
229
229
  LT('field', value);
230
230
 
231
- // 小于等于
231
+ // Less than or equal
232
232
  LTE('field', value);
233
233
 
234
- // 包含
234
+ // In array
235
235
  IN('field', [value1, value2]);
236
236
 
237
- // 模糊匹配
237
+ // Pattern matching (LIKE)
238
238
  LIKE('field', '%pattern%');
239
239
 
240
- // 组合条件
240
+ // Combine conditions
241
241
  OR(AND(EQ('status', 'active'), GTE('age', 18)), AND(EQ('status', 'pending')));
242
242
  ```
243
243
 
244
- ## 高级查询
244
+ ## Advanced Queries
245
245
 
246
- ### 聚合查询
246
+ ### Aggregate Query
247
247
 
248
248
  ```typescript
249
249
  import { AggregateFunction } from 'db-ts-sdk';
@@ -261,7 +261,7 @@ const results = await User.filter({
261
261
  });
262
262
  ```
263
263
 
264
- ### 连接查询
264
+ ### Join Query
265
265
 
266
266
  ```typescript
267
267
  const results = await User.filter({
@@ -274,9 +274,9 @@ const results = await User.filter({
274
274
  });
275
275
  ```
276
276
 
277
- ## 配置
277
+ ## Configuration
278
278
 
279
- `tsconfig.json` 中确保启用装饰器支持:
279
+ In your `tsconfig.json`, make sure to enable decorator support:
280
280
 
281
281
  ```json
282
282
  {
@@ -287,34 +287,34 @@ const results = await User.filter({
287
287
  }
288
288
  ```
289
289
 
290
- 在应用入口导入 reflect-metadata
290
+ And at the entrypoint of your app, import reflect-metadata:
291
291
 
292
292
  ```typescript
293
293
  import 'reflect-metadata';
294
294
  ```
295
295
 
296
- ## API 参考
296
+ ## API Reference
297
297
 
298
- ### BaseModel 静态方法
298
+ ### BaseModel Static Methods
299
299
 
300
- - `createTable()` - 创建表
301
- - `dropTable()` - 删除表
302
- - `renameTable(newName)` - 重命名表
303
- - `truncateTable()` - 清空表
304
- - `create(data)` - 创建记录
305
- - `bulkCreate(datas, batchSize)` - 批量创建
306
- - `get(filter, select?)` - 获取单个记录
307
- - `filter(options)` - 过滤查询
308
- - `update(filter, data)` - 批量更新
309
- - `delete(filter)` - 批量删除
310
- - `count(options)` - 统计数量
300
+ - `createTable()` - Create table
301
+ - `dropTable()` - Drop table
302
+ - `renameTable(newName)` - Rename table
303
+ - `truncateTable()` - Truncate table
304
+ - `create(data)` - Create a record
305
+ - `bulkCreate(datas, batchSize)` - Create records in bulk
306
+ - `get(filter, select?)` - Get a single record
307
+ - `filter(options)` - Filter query
308
+ - `update(filter, data)` - Bulk update
309
+ - `delete(filter)` - Bulk delete
310
+ - `count(options)` - Count records
311
311
 
312
- ### BaseModel 实例方法
312
+ ### BaseModel Instance Methods
313
313
 
314
- - `save()` - 保存实例(创建或更新)
315
- - `remove(filter?)` - 删除实例
316
- - `toString()` - 转换为字符串
317
- - `toJSON()` - 转换为 JSON 对象
314
+ - `save()` - Save instance (create or update)
315
+ - `remove(filter?)` - Remove instance
316
+ - `toString()` - Convert to string
317
+ - `toJSON()` - Convert to JSON object
318
318
 
319
319
  ## License
320
320
 
@@ -1,3 +1,4 @@
1
+ import { FilterWrapper } from '../types/filter';
1
2
  import { Client } from './client';
2
3
  import { ClientConfig } from './config';
3
4
  export class DataClient {
@@ -27,6 +28,7 @@ export class DataClient {
27
28
  throw new Error(response.message);
28
29
  }
29
30
  async queryOne(data, model) {
31
+ data.query.filter = FilterWrapper(data.query.filter);
30
32
  const response = await this.client.post('/query', { One: data });
31
33
  if (response.status === 'success') {
32
34
  const responseData = response.data;
@@ -38,6 +40,7 @@ export class DataClient {
38
40
  throw new Error(response.message);
39
41
  }
40
42
  async queryMany(data, model) {
43
+ data.query.filter = FilterWrapper(data.query.filter);
41
44
  const response = await this.client.post('/query', { Many: data });
42
45
  if (response.status === 'success') {
43
46
  const responseData = response.data;
@@ -5,7 +5,7 @@ export declare class SyntropixClient {
5
5
  private config;
6
6
  private _tableClient?;
7
7
  private _dataClient?;
8
- constructor(config: ClientConfig);
8
+ constructor(config?: ClientConfig);
9
9
  get table(): TableClient;
10
10
  get data(): DataClient;
11
11
  }
@@ -1,10 +1,11 @@
1
+ import { ClientConfig } from './config';
1
2
  import { DataClient } from './dataClient';
2
3
  import { TableClient } from './tableClient';
3
4
  export class SyntropixClient {
4
5
  config;
5
6
  _tableClient;
6
7
  _dataClient;
7
- constructor(config) {
8
+ constructor(config = new ClientConfig()) {
8
9
  this.config = config;
9
10
  }
10
11
  get table() {
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export * from './core/config';
3
3
  export { SyntropixClient } from './core/syntropix';
4
4
  export { BaseModel, Column, ForeignKey } from './types/basemodel';
5
5
  export * from './types/common';
6
- export { DataType } from './types/data-type';
6
+ export { ColumnType } from './types/data-type';
7
7
  export * from './types/field';
8
8
  export * from './types/filter';
9
9
  export * from './types/requests';
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export * from './core/config';
4
4
  export { SyntropixClient } from './core/syntropix';
5
5
  export { BaseModel, Column, ForeignKey } from './types/basemodel';
6
6
  export * from './types/common';
7
- export { DataType } from './types/data-type';
7
+ export { ColumnType } from './types/data-type';
8
8
  export * from './types/field';
9
9
  export * from './types/filter';
10
10
  export * from './types/requests';
@@ -1,21 +1,22 @@
1
1
  import 'reflect-metadata';
2
2
  import { SyntropixClient } from '../core/syntropix';
3
3
  import { Aggregate, GroupBy, Index, Join, Sort } from './common';
4
+ import { ColumnType } from './data-type';
4
5
  import { TableCreateResponse } from './dto/table';
5
6
  import { Field, ForeignKeyField } from './field';
6
7
  import { Filter } from './filter';
7
8
  export declare function Column(options?: {
8
- type?: string | Record<string, any>;
9
+ type?: ColumnType;
9
10
  name?: string;
10
11
  description?: string;
11
12
  primary?: boolean;
12
13
  nullable?: boolean;
13
- auto_increment?: boolean;
14
+ autoIncrement?: boolean;
14
15
  default?: any;
15
16
  }): (target: any, propertyKey: string) => void;
16
17
  export declare function Description(description: string): (target: any) => void;
17
18
  export declare function ForeignKey(tableName: string, columnName: string, options?: {
18
- type?: string | Record<string, any>;
19
+ type?: ColumnType;
19
20
  name?: string;
20
21
  onDelete?: string;
21
22
  onUpdate?: string;
@@ -3,6 +3,7 @@ import 'reflect-metadata';
3
3
  import { ClientConfig } from '../core/config';
4
4
  import { SyntropixClient } from '../core/syntropix';
5
5
  import { AggregateFunction } from './common';
6
+ import { ColumnType } from './data-type';
6
7
  import { Field, ForeignKeyField, IntegerField } from './field';
7
8
  import { AND, EQ, GTE, OR, Value } from './filter';
8
9
  // Metadata keys
@@ -15,15 +16,15 @@ export function Column(options = {}) {
15
16
  return function (target, propertyKey) {
16
17
  const fields = Reflect.getMetadata(FIELDS_KEY, target.constructor) || {};
17
18
  const fieldName = options.name || propertyKey.toLowerCase();
18
- const column_type = options.type || 'Text';
19
+ const columnType = options.type || ColumnType.Text;
19
20
  const field = new (class extends Field {
20
21
  constructor() {
21
- super(column_type, {
22
+ super(columnType, {
22
23
  name: fieldName,
23
24
  description: options.description,
24
- is_primary_key: options.primary,
25
- is_nullable: options.nullable,
26
- auto_increment: options.auto_increment,
25
+ isPrimaryKey: options.primary,
26
+ isNullable: options.nullable,
27
+ autoIncrement: options.autoIncrement,
27
28
  default: options.default,
28
29
  });
29
30
  }
@@ -42,11 +43,11 @@ export function Description(description) {
42
43
  export function ForeignKey(tableName, columnName, options = {}) {
43
44
  return function (target, propertyKey) {
44
45
  const fields = Reflect.getMetadata(FIELDS_KEY, target.constructor) || {};
45
- const field = new ForeignKeyField(options.type || 'Integer', tableName, columnName, {
46
+ const field = new ForeignKeyField(options.type || ColumnType.Integer, tableName, columnName, {
46
47
  onDelete: options.onDelete,
47
48
  onUpdate: options.onUpdate,
48
49
  description: options.description,
49
- is_nullable: options.nullable,
50
+ isNullable: options.nullable,
50
51
  default: options.default,
51
52
  });
52
53
  field.name = options.name || propertyKey.toLowerCase();
@@ -108,18 +109,18 @@ export class BaseModel {
108
109
  // Check if there's a primary key
109
110
  let hasPrimaryKey = false;
110
111
  for (const field of Object.values(fields)) {
111
- if (field.is_primary_key) {
112
+ if (field.isPrimaryKey) {
112
113
  hasPrimaryKey = true;
113
- field.is_nullable = false;
114
+ field.isNullable = false;
114
115
  break;
115
116
  }
116
117
  }
117
118
  // If no primary key, add default 'id' field
118
119
  if (!hasPrimaryKey && !('id' in fields)) {
119
120
  fields['id'] = new IntegerField({
120
- is_primary_key: true,
121
- is_nullable: false,
122
- auto_increment: true,
121
+ isPrimaryKey: true,
122
+ isNullable: false,
123
+ autoIncrement: true,
123
124
  description: 'Primary key',
124
125
  });
125
126
  fields['id'].name = 'id';
@@ -129,7 +130,7 @@ export class BaseModel {
129
130
  static getPrimaryKeyName() {
130
131
  const fields = this.getFields();
131
132
  for (const [key, field] of Object.entries(fields)) {
132
- if (field.is_primary_key) {
133
+ if (field.isPrimaryKey) {
133
134
  return field.name;
134
135
  }
135
136
  }
@@ -152,7 +153,7 @@ export class BaseModel {
152
153
  getPrimaryKey() {
153
154
  const fields = this.getFields();
154
155
  for (const field of Object.values(fields)) {
155
- if (field.is_primary_key) {
156
+ if (field.isPrimaryKey) {
156
157
  return field;
157
158
  }
158
159
  }
@@ -170,12 +171,12 @@ export class BaseModel {
170
171
  const fields = this.getFields();
171
172
  const columns = Object.values(fields).map((f) => f.into());
172
173
  const foreignKeys = this.getAssociations().map((f) => ({
173
- from_table: this.getTableName(),
174
- from_column: f.name,
175
- to_table: f.tableName,
176
- to_column: f.columnName,
177
- on_delete: f.onDelete,
178
- on_update: f.onUpdate,
174
+ fromTable: this.getTableName(),
175
+ fromColumn: f.name,
176
+ toTable: f.tableName,
177
+ toColumn: f.columnName,
178
+ onDelete: f.onDelete,
179
+ onUpdate: f.onUpdate,
179
180
  }));
180
181
  const indexes = this.getIndexes();
181
182
  const client = _client || new SyntropixClient(new ClientConfig());
@@ -183,7 +184,7 @@ export class BaseModel {
183
184
  name: this.getTableName(),
184
185
  description: this.getDescription() || 'No description',
185
186
  columns,
186
- foreign_keys: foreignKeys,
187
+ foreignKeys: foreignKeys,
187
188
  indexes,
188
189
  });
189
190
  }
@@ -195,7 +196,7 @@ export class BaseModel {
195
196
  const client = _client || new SyntropixClient(new ClientConfig());
196
197
  return client.table.renameTable({
197
198
  name: this.getTableName(),
198
- new_name: newName,
199
+ newName: newName,
199
200
  });
200
201
  }
201
202
  static async truncateTable(_client) {
@@ -219,7 +220,7 @@ export class BaseModel {
219
220
  }
220
221
  const client = _client || new SyntropixClient(new ClientConfig());
221
222
  return client.data.insertOne({
222
- table_name: model.getTableName(),
223
+ tableName: model.getTableName(),
223
224
  data: {
224
225
  columns,
225
226
  values: [values],
@@ -247,7 +248,7 @@ export class BaseModel {
247
248
  }
248
249
  return (_client ||
249
250
  this.client.data.updateByPrimaryKey(pkValue, {
250
- table_name: this.getTableName(),
251
+ tableName: this.getTableName(),
251
252
  payload: {
252
253
  filter: [[]],
253
254
  columns,
@@ -261,7 +262,7 @@ export class BaseModel {
261
262
  const finalFilter = filter || OR(AND(EQ(pk?.name || 'id', pkValue)));
262
263
  return (_client ||
263
264
  this.client.data.deleteData({
264
- table_name: this.getTableName(),
265
+ tableName: this.getTableName(),
265
266
  payload: {
266
267
  filter: finalFilter,
267
268
  },
@@ -292,7 +293,7 @@ export class BaseModel {
292
293
  values.push(columns.map((c) => data[c]));
293
294
  if (values.length === batchSize) {
294
295
  cnt += await client.data.insertData({
295
- table_name: model.getTableName(),
296
+ tableName: model.getTableName(),
296
297
  data: { columns: columns.map((c) => fields[c].name), values },
297
298
  });
298
299
  values = [];
@@ -300,7 +301,7 @@ export class BaseModel {
300
301
  }
301
302
  if (values.length > 0) {
302
303
  cnt += await client.data.insertData({
303
- table_name: model.getTableName(),
304
+ tableName: model.getTableName(),
304
305
  data: { columns: columns.map((c) => fields[c].name), values },
305
306
  });
306
307
  }
@@ -321,7 +322,7 @@ export class BaseModel {
321
322
  const values = columns.map((c) => data[c]);
322
323
  const client = _client || new SyntropixClient(new ClientConfig());
323
324
  return client.data.updateData({
324
- table_name: model.getTableName(),
325
+ tableName: model.getTableName(),
325
326
  payload: {
326
327
  filter,
327
328
  columns: columns.map((c) => fields[c].name),
@@ -333,7 +334,7 @@ export class BaseModel {
333
334
  const model = this;
334
335
  const client = _client || new SyntropixClient(new ClientConfig());
335
336
  return client.data.deleteData({
336
- table_name: model.getTableName(),
337
+ tableName: model.getTableName(),
337
338
  payload: { filter },
338
339
  });
339
340
  }
@@ -342,7 +343,7 @@ export class BaseModel {
342
343
  const fields = model.getFields();
343
344
  const client = _client || new SyntropixClient(new ClientConfig());
344
345
  const data = await client.data.queryOne({
345
- table_name: model.getTableName(),
346
+ tableName: model.getTableName(),
346
347
  query: {
347
348
  filter,
348
349
  select: select || Object.values(fields).map((f) => f.name),
@@ -355,7 +356,7 @@ export class BaseModel {
355
356
  const model = this;
356
357
  const client = options._client || new SyntropixClient(new ClientConfig());
357
358
  const data = await client.data.queryMany({
358
- table_name: model.getTableName(),
359
+ tableName: model.getTableName(),
359
360
  query: {
360
361
  filter: options.filter,
361
362
  sort: options.sort,
@@ -363,7 +364,7 @@ export class BaseModel {
363
364
  join: options.join ? [options.join] : undefined,
364
365
  limit: options.limit,
365
366
  offset: options.offset,
366
- group_by: options.groupBy,
367
+ groupBy: options.groupBy,
367
368
  select: options.select,
368
369
  },
369
370
  });
@@ -373,20 +374,20 @@ export class BaseModel {
373
374
  const model = this;
374
375
  const client = options._client || new SyntropixClient(new ClientConfig());
375
376
  const data = await client.data.queryMany({
376
- table_name: model.getTableName(),
377
+ tableName: model.getTableName(),
377
378
  query: {
378
379
  filter: options.filter || [[GTE('id', Value(0))]],
379
380
  aggregate: [
380
381
  {
381
382
  column: 'id',
382
- function: AggregateFunction.COUNT,
383
+ function: AggregateFunction.Count,
383
384
  alias: 'count',
384
385
  },
385
386
  ],
386
387
  join: options.join ? [options.join] : undefined,
387
388
  limit: 1,
388
389
  offset: 0,
389
- group_by: options.groupBy,
390
+ groupBy: options.groupBy,
390
391
  select: ['count'],
391
392
  },
392
393
  });