vona-module-a-orm 5.0.84 → 5.0.86

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.
@@ -1,4 +1,7 @@
1
+ import type { IDecoratorDatabaseDialectOptions } from 'vona-module-a-orm';
1
2
  import { BeanDatabaseDialectBase, DatabaseDialect } from 'vona-module-a-orm';
2
3
 
3
- @DatabaseDialect()
4
+ export interface IDatabaseDialectOptions<%=argv.beanNameCapitalize%> extends IDecoratorDatabaseDialectOptions {}
5
+
6
+ @DatabaseDialect<IDatabaseDialectOptions<%=argv.beanNameCapitalize%>>()
4
7
  export class DatabaseDialect<%=argv.beanNameCapitalize%> extends BeanDatabaseDialectBase {}
@@ -1,12 +1,14 @@
1
1
  import type { FunctionAsync } from 'vona';
2
2
  import type { ConfigDatabaseClient } from '../types/config.ts';
3
- import type { IDatabaseClientRecord, IDbInfo } from '../types/database.ts';
3
+ import type { IDatabaseClientDialectRecord, IDatabaseClientRecord, IDbInfo } from '../types/database.ts';
4
+ import type { BeanDatabaseDialectBase } from './bean.databaseDialectBase.ts';
4
5
  import { BeanBase } from 'vona';
5
6
  import { ServiceDatabaseClient } from '../service/databaseClient_.ts';
6
7
  export declare class BeanDatabase extends BeanBase {
7
8
  get current(): import("vona-module-a-orm").ServiceDb;
8
9
  getClient(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord, clientConfig?: ConfigDatabaseClient): ServiceDatabaseClient;
9
10
  getDb(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord, clientConfig?: ConfigDatabaseClient): import("vona-module-a-orm").ServiceDb;
11
+ getDialect(client: keyof IDatabaseClientDialectRecord): BeanDatabaseDialectBase;
10
12
  switchDbIsolate<RESULT>(fn: FunctionAsync<RESULT>, dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): Promise<RESULT>;
11
13
  switchDb<RESULT>(fn: FunctionAsync<RESULT>, dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): Promise<RESULT>;
12
14
  }
@@ -2,18 +2,25 @@ import type { Knex } from 'knex';
2
2
  import type { TableIdentity } from 'table-identity';
3
3
  import type { ITableColumn } from '../types/columns.ts';
4
4
  import type { ConfigDatabaseClient } from '../types/config.ts';
5
- import type { IFetchDatabasesResultItem, IFetchIndexesResultItem } from '../types/dialect.ts';
5
+ import type { IDatabaseDialectCapabilities, IFetchDatabasesResultItem, IFetchIndexesResultItem, TypeDatabaseDialectTableColumnsFn } from '../types/dialect.ts';
6
6
  import { BeanBase } from 'vona';
7
7
  export declare class BeanDatabaseDialectBase extends BeanBase {
8
- getConfigBase(): ConfigDatabaseClient | undefined;
8
+ protected _capabilities?: IDatabaseDialectCapabilities;
9
+ protected _configBase?: Partial<ConfigDatabaseClient>;
10
+ get capabilities(): IDatabaseDialectCapabilities;
11
+ get configBase(): Partial<ConfigDatabaseClient> | undefined;
9
12
  fetchDatabases(_schemaBuilder: Knex.SchemaBuilder, _databasePrefix: string): Promise<IFetchDatabasesResultItem[]>;
10
- createDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<void>;
13
+ createDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<string>;
11
14
  dropDatabase(_schemaBuilder: Knex.SchemaBuilder, _databaseName: string): Promise<void>;
12
15
  fetchIndexes(_schemaBuilder: Knex.SchemaBuilder, _tableName: string): Promise<IFetchIndexesResultItem[]>;
13
16
  insert(_builder: Knex.QueryBuilder, _datas: any[]): Promise<TableIdentity[]>;
17
+ select(_builder: Knex.QueryBuilder, datas: any[], _fn: TypeDatabaseDialectTableColumnsFn): Promise<any[]>;
14
18
  query(_result: any): void;
15
19
  viewDependents(_builder: Knex.QueryBuilder, _viewName: string): Promise<string[]>;
16
20
  coerceColumn(column: Knex.ColumnInfo): ITableColumn;
21
+ protected selectAsSqlite3(_builder: Knex.QueryBuilder, datas: any[], fn: TypeDatabaseDialectTableColumnsFn): Promise<any[]>;
22
+ protected insertAsMysql(builder: Knex.QueryBuilder, datas: any[]): Promise<TableIdentity[]>;
23
+ protected insertAsPg(builder: Knex.QueryBuilder, datas: any[]): Promise<TableIdentity[]>;
17
24
  protected _coerceColumnValue(type: string, value: any): any;
18
25
  protected _safeNumber(value: any): number | undefined;
19
26
  protected _columnTypePrefixes(type: string, prefixes: string[]): boolean;
@@ -1,3 +1,4 @@
1
1
  import type { Knex } from 'knex';
2
+ import type { ServiceDb } from '../service/db_.ts';
2
3
  import type { TypeModelWhere } from '../types/modelWhere.ts';
3
- export declare function buildWhere<TRecord>(knex: Knex, builder: Knex.QueryBuilder, wheres: TypeModelWhere<TRecord>, having?: boolean): void;
4
+ export declare function buildWhere<TRecord>(db: ServiceDb, builder: Knex.QueryBuilder, wheres: TypeModelWhere<TRecord>, having?: boolean): void;
@@ -1,9 +1,8 @@
1
1
  import type { TableIdentityType } from 'table-identity';
2
- import type { TypeBeanRecordGeneralSelectorKeys, VonaApplication } from 'vona';
2
+ import type { VonaApplication } from 'vona';
3
3
  import type { IOnionOptionsMeta } from 'vona-module-a-onion';
4
4
  import type { TSummerCachePreset } from 'vona-module-a-summer';
5
- import type { IDatabaseClientDialectRecord } from '../types/database.ts';
6
- export type TypeDataBaseConfigDialects = Record<keyof IDatabaseClientDialectRecord, TypeBeanRecordGeneralSelectorKeys<'databaseDialect'>>;
5
+ import type { IDataBaseConfigDialects } from '../types/config.ts';
7
6
  export declare function config(_app: VonaApplication): {
8
7
  sharding: {
9
8
  cache: {
@@ -34,7 +33,7 @@ export declare function config(_app: VonaApplication): {
34
33
  enable: boolean;
35
34
  expired: number;
36
35
  };
37
- dialects: TypeDataBaseConfigDialects;
36
+ dialects: IDataBaseConfigDialects;
38
37
  summer: {
39
38
  enable: boolean;
40
39
  meta: IOnionOptionsMeta;
@@ -5,7 +5,7 @@ declare module 'knex' {
5
5
  namespace Knex {
6
6
  interface SchemaBuilder {
7
7
  fetchDatabases(databasePrefix: string): Promise<IFetchDatabasesResultItem[]>;
8
- createDatabase(databaseName: string): Promise<void>;
8
+ createDatabase(databaseName: string): Promise<string>;
9
9
  dropDatabase(databaseName: string): Promise<void>;
10
10
  fetchIndexes(tableName: string): Promise<IFetchIndexesResultItem[]>;
11
11
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import BigNumber from 'bignumber.js';
2
- import { BeanInfo, BeanAopMethodBase, BeanBase, deepExtend, appResource, Virtual, beanFullNameFromOnionName, cast, useApp, BeanSimple, combineConfigDefault, BeanScopeBase, createBeanDecorator, PickClassInner, $Class } from 'vona';
2
+ import { BeanInfo, BeanAopMethodBase, BeanBase, deepExtend, appResource, beanFullNameFromOnionName, Virtual, cast, useApp, BeanSimple, combineConfigDefault, BeanScopeBase, createBeanDecorator, PickClassInner, $Class } from 'vona';
3
3
  import { AopMethod } from 'vona-module-a-aspect';
4
4
  import { Service, Bean, Scope } from 'vona-module-a-bean';
5
5
  import { AsyncLocalStorage, AsyncResource } from 'node:async_hooks';
@@ -190,27 +190,20 @@ let ServiceDatabase = (_dec$r = Service(), _dec2$r = BeanInfo({
190
190
  get configDatabase() {
191
191
  return this.app.config.database;
192
192
  }
193
- getDialect(client) {
194
- if (!client) throw new Error('database dialect not specified');
195
- const beanFullName = this.scope.config.dialects[client];
196
- const dialect = this.app.bean._getBean(beanFullName);
197
- if (!dialect) throw new Error(`database dialect not found: ${client}`);
198
- return dialect;
199
- }
200
- getClientConfig(clientName, original = false) {
193
+ getClientConfig(clientName, clientConfig, original) {
201
194
  // clientConfig
202
- let clientConfig = this.configDatabase.clients[clientName];
203
- if (original) return clientConfig;
195
+ if (!clientConfig) {
196
+ clientConfig = this.configDatabase.clients[clientName];
197
+ }
204
198
  // check
205
199
  if (!clientConfig) {
206
200
  throw new Error(`database config not found: ${clientName}`);
207
201
  }
202
+ if (original) return clientConfig;
208
203
  // configBaseClient
209
- const dialect = this.scope.service.database.getDialect(clientConfig.client);
210
- const configBaseClient = dialect.getConfigBase();
204
+ const dialect = this.bean.database.getDialect(clientConfig.client);
211
205
  // combine
212
- const configBase = this.configDatabase.base;
213
- clientConfig = deepExtend({}, configBase, configBaseClient, clientConfig);
206
+ clientConfig = deepExtend({}, this.configDatabase.base, dialect.configBase, clientConfig);
214
207
  // ready
215
208
  return clientConfig;
216
209
  }
@@ -235,7 +228,9 @@ let ServiceDatabase = (_dec$r = Service(), _dec2$r = BeanInfo({
235
228
  clientName
236
229
  };
237
230
  }
238
- prepareClientNameSelector(dbInfo) {
231
+ prepareClientNameSelector(dbInfo, dialect) {
232
+ const dialect2 = typeof dialect === 'string' ? this.bean.database.getDialect(dialect) : dialect;
233
+ if (!dialect2.capabilities.level) return dbInfo.clientName;
239
234
  // combine
240
235
  return dbInfo.level === 0 ? dbInfo.clientName : `${dbInfo.clientName}:${dbInfo.level}`;
241
236
  }
@@ -390,18 +385,18 @@ let ServiceTransactionState = (_dec$o = Service(), _dec2$o = BeanInfo({
390
385
  get serviceDatabase() {
391
386
  return this.bean._getBean(ServiceDatabase);
392
387
  }
393
- get(dbInfo) {
394
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
388
+ get(db) {
389
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
395
390
  return this._fibers[selector];
396
391
  }
397
- add(dbInfo, connection) {
398
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
392
+ add(db, connection) {
393
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
399
394
  const fiber = this.bean._newBean(ServiceTransactionFiber, connection);
400
395
  this._fibers[selector] = fiber;
401
396
  return fiber;
402
397
  }
403
- remove(dbInfo) {
404
- const selector = this.serviceDatabase.prepareClientNameSelector(dbInfo);
398
+ remove(db) {
399
+ const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
405
400
  delete this._fibers[selector];
406
401
  }
407
402
  }) || _class$o) || _class$o);
@@ -447,7 +442,7 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
447
442
  return this.bean._getBean(ServiceTransactionAsyncLocalStorage).transactionState;
448
443
  }
449
444
  get transactionFiber() {
450
- return this.transactionState.get(this._db.info);
445
+ return this.transactionState.get(this._db);
451
446
  }
452
447
  get inTransaction() {
453
448
  return !!this.transactionFiber;
@@ -528,7 +523,7 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
528
523
  if (!this.inTransaction) {
529
524
  const connection = this._db.client.connection;
530
525
  const transactionConnection = await connection.transaction(_translateTransactionOptions(options));
531
- fiber = this.transactionState.add(this._db.info, transactionConnection);
526
+ fiber = this.transactionState.add(this._db, transactionConnection);
532
527
  }
533
528
  // fn
534
529
  try {
@@ -536,19 +531,19 @@ let ServiceTransaction = (_dec$m = Service(), _dec2$m = BeanInfo({
536
531
  } catch (err) {
537
532
  if (fiber) {
538
533
  await fiber.doRollback();
539
- this.transactionState.remove(this._db.info);
534
+ this.transactionState.remove(this._db);
540
535
  }
541
536
  throw err;
542
537
  }
543
538
  try {
544
539
  if (fiber) {
545
540
  await fiber.doCommit();
546
- this.transactionState.remove(this._db.info);
541
+ this.transactionState.remove(this._db);
547
542
  }
548
543
  } catch (err) {
549
544
  if (fiber) {
550
545
  await fiber.doRollback();
551
- this.transactionState.remove(this._db.info);
546
+ this.transactionState.remove(this._db);
552
547
  }
553
548
  throw err;
554
549
  }
@@ -613,7 +608,7 @@ let ServiceDb = (_dec$l = Service(), _dec2$l = BeanInfo({
613
608
  return this.client.clientConfig.client;
614
609
  }
615
610
  get dialect() {
616
- return this.scope.service.database.getDialect(this.dialectName);
611
+ return this.bean.database.getDialect(this.dialectName);
617
612
  }
618
613
  async commit(cb, options) {
619
614
  return await this.transaction.commit(cb, options);
@@ -680,8 +675,8 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
680
675
  const dbInfo = this.scope.service.database.parseClientNameSelector(clientNameSelector);
681
676
  this.level = dbInfo.level;
682
677
  this.clientName = dbInfo.clientName;
683
- // config
684
- this.clientConfig = clientConfig ? deepExtend({}, clientConfig) : this.scope.service.database.getClientConfig(this.clientName);
678
+ // config: inited by bean.database.getClient
679
+ this.clientConfig = clientConfig;
685
680
  // knex
686
681
  this._knex = knex(this.clientConfig);
687
682
  }
@@ -694,8 +689,9 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
694
689
  }
695
690
  }
696
691
  async reload(clientConfig) {
692
+ const clientConfigReal = this.scope.service.database.getClientConfig(this.clientName, clientConfig);
697
693
  await this.__close();
698
- this.__load(this.clientNameSelector, clientConfig);
694
+ this.__load(this.clientNameSelector, clientConfigReal);
699
695
  }
700
696
  getDatabaseName() {
701
697
  const connection = this.clientConfig.connection;
@@ -704,9 +700,9 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
704
700
  _prepareDatabaseName(databaseName) {
705
701
  const result = {};
706
702
  const connection = this.clientConfig.connection;
707
- if (connection.database) {
703
+ if (connection.database !== undefined) {
708
704
  result.database = databaseName;
709
- } else if (connection.filename) {
705
+ } else if (connection.filename !== undefined) {
710
706
  result.filename = databaseName;
711
707
  }
712
708
  return result;
@@ -718,7 +714,7 @@ let ServiceDatabaseClient = (_dec$k = Service(), _dec2$k = BeanInfo({
718
714
  const connDatabaseName = this._prepareDatabaseName(databaseName);
719
715
  // set config
720
716
  // * should not use this.clientConfig.connection, because password is hidden
721
- const config = this.scope.service.database.getClientConfig(this.clientName, true);
717
+ const config = this.scope.service.database.getClientConfig(this.clientName, undefined, true);
722
718
  config.connection = Object.assign({}, config.connection, connDatabaseName);
723
719
  // only used by startup, so no consider that workers broadcast
724
720
  this.configDatabase.clients[this.clientName] = config;
@@ -737,16 +733,26 @@ let BeanDatabase = (_dec$j = Bean(), _dec2$j = BeanInfo({
737
733
  }
738
734
  getClient(dbInfoOrClientName, clientConfig) {
739
735
  const dbInfo = this.scope.service.database.prepareDbInfo(dbInfoOrClientName);
740
- const selector = this.scope.service.database.prepareClientNameSelector(dbInfo);
741
- return this.app.bean._getBeanSelector(ServiceDatabaseClient, selector, clientConfig);
736
+ const clientConfigReal = this.scope.service.database.getClientConfig(dbInfo.clientName, clientConfig);
737
+ const selector = this.scope.service.database.prepareClientNameSelector(dbInfo, clientConfigReal.client);
738
+ return this.app.bean._getBeanSelector(ServiceDatabaseClient, selector, clientConfigReal);
742
739
  }
743
740
  getDb(dbInfoOrClientName, clientConfig) {
744
741
  return this.getClient(dbInfoOrClientName, clientConfig).db;
745
742
  }
743
+ getDialect(client) {
744
+ if (!client) throw new Error('database dialect not specified');
745
+ const beanFullName = beanFullNameFromOnionName(this.scope.config.dialects[client], 'databaseDialect');
746
+ const dialect = this.app.bean._getBean(beanFullName);
747
+ if (!dialect) throw new Error(`database dialect not found: ${client}`);
748
+ return dialect;
749
+ }
746
750
  async switchDbIsolate(fn, dbInfoOrClientName) {
747
751
  const dbInfo = this.scope.service.database.prepareDbInfo(dbInfoOrClientName);
752
+ // const level = this.app.config.database.defaultClient === 'sqlite3' ? dbInfo.level : dbInfo.level + 1;
753
+ const level = dbInfo.level + 1;
748
754
  return this.switchDb(fn, {
749
- level: dbInfo.level + 1,
755
+ level,
750
756
  clientName: dbInfo.clientName
751
757
  });
752
758
  }
@@ -767,8 +773,17 @@ var _dec$i, _dec2$i, _dec3$7, _class$i;
767
773
  let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = BeanInfo({
768
774
  module: "a-orm"
769
775
  }), _dec$i(_class$i = _dec2$i(_class$i = _dec3$7(_class$i = class BeanDatabaseDialectBase extends BeanBase {
770
- getConfigBase() {
771
- return undefined;
776
+ constructor(...args) {
777
+ super(...args);
778
+ this._capabilities = void 0;
779
+ this._configBase = void 0;
780
+ }
781
+ get capabilities() {
782
+ if (!this._capabilities) throw new Error('Should provide dialect capabilities');
783
+ return this._capabilities;
784
+ }
785
+ get configBase() {
786
+ return this._configBase;
772
787
  }
773
788
  async fetchDatabases(_schemaBuilder, _databasePrefix) {
774
789
  throw new Error('Not Implemented');
@@ -785,6 +800,9 @@ let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = B
785
800
  async insert(_builder, _datas) {
786
801
  throw new Error('Not Implemented');
787
802
  }
803
+ async select(_builder, datas, _fn) {
804
+ return datas;
805
+ }
788
806
  query(_result) {
789
807
  throw new Error('Not Implemented');
790
808
  }
@@ -801,6 +819,51 @@ let BeanDatabaseDialectBase = (_dec$i = Bean(), _dec2$i = Virtual(), _dec3$7 = B
801
819
  // ok
802
820
  return result;
803
821
  }
822
+ async selectAsSqlite3(_builder, datas, fn) {
823
+ const columns = await fn();
824
+ // data
825
+ for (const data of datas) {
826
+ for (const columnName in columns) {
827
+ const column = columns[columnName];
828
+ if (Object.prototype.hasOwnProperty.call(data, columnName)) {
829
+ const value = data[columnName];
830
+ if (column.type === 'json' && value !== undefined && typeof value === 'string') {
831
+ data[columnName] = JSON.parse(value);
832
+ }
833
+ }
834
+ }
835
+ }
836
+ return datas;
837
+ }
838
+ async insertAsMysql(builder, datas) {
839
+ if (datas.length === 0) return [];
840
+ if (isNil(datas[0].id)) {
841
+ const ids = [];
842
+ for (const data of datas) {
843
+ const builder2 = builder.clone();
844
+ builder2.insert(data);
845
+ const items = await builder2;
846
+ ids.push(items[0]);
847
+ }
848
+ return ids;
849
+ } else {
850
+ builder.insert(datas);
851
+ await builder;
852
+ return datas.map(item => item.id);
853
+ }
854
+ }
855
+ async insertAsPg(builder, datas) {
856
+ if (datas.length === 0) return [];
857
+ if (isNil(datas[0].id)) {
858
+ builder.insert(datas).returning('id');
859
+ const items = await builder;
860
+ return items.map(item => item.id);
861
+ } else {
862
+ builder.insert(datas);
863
+ await builder;
864
+ return datas.map(item => item.id);
865
+ }
866
+ }
804
867
  _coerceColumnValue(type, value) {
805
868
  // null
806
869
  if (isNil(value)) return undefined;
@@ -934,10 +997,10 @@ function getClassEntityFromClassModel(modelClass) {
934
997
  // return arr;
935
998
  // }
936
999
 
937
- function buildWhere(knex, builder, wheres, having = false) {
938
- _buildWhereInner(having, knex, builder, wheres);
1000
+ function buildWhere(db, builder, wheres, having = false) {
1001
+ _buildWhereInner(having, db, builder, wheres);
939
1002
  }
940
- function _buildWhereInner(having, knex, builder, wheres, column) {
1003
+ function _buildWhereInner(having, db, builder, wheres, column) {
941
1004
  // skip
942
1005
  if (wheres === Op.skip) {
943
1006
  return;
@@ -952,22 +1015,22 @@ function _buildWhereInner(having, knex, builder, wheres, column) {
952
1015
  const value = wheres[key];
953
1016
  if (key[0] !== '_') {
954
1017
  // columns
955
- _buildWhereColumn(having, knex, builder, key, value);
1018
+ _buildWhereColumn(having, db, builder, key, value);
956
1019
  } else if (OpNormalValues.includes(key)) {
957
1020
  // op: normal
958
1021
  if (column) {
959
- _buildWhereColumn(having, knex, builder, column, value, key);
1022
+ _buildWhereColumn(having, db, builder, column, value, key);
960
1023
  }
961
1024
  } else {
962
1025
  const op = _checkOpJoint(key);
963
1026
  if (op) {
964
1027
  // op: joint
965
- _buildWhereOpJoint(having, knex, builder, column, value, op);
1028
+ _buildWhereOpJoint(having, db, builder, column, value, op);
966
1029
  }
967
1030
  }
968
1031
  }
969
1032
  }
970
- function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1033
+ function _buildWhereOpJoint(having, db, builder, column, wheres, op) {
971
1034
  // skip
972
1035
  if (wheres === Op.skip) {
973
1036
  return;
@@ -977,7 +1040,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
977
1040
  builder[having ? 'having' : 'where'](builder => {
978
1041
  for (const key in wheres) {
979
1042
  builder.andWhere(builder => {
980
- _buildWhereInner(false, knex, builder, {
1043
+ _buildWhereInner(false, db, builder, {
981
1044
  [key]: wheres[key]
982
1045
  }, column);
983
1046
  });
@@ -990,7 +1053,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
990
1053
  builder[having ? 'having' : 'where'](builder => {
991
1054
  for (const key in wheres) {
992
1055
  builder.orWhere(builder => {
993
- _buildWhereInner(false, knex, builder, {
1056
+ _buildWhereInner(false, db, builder, {
994
1057
  [key]: wheres[key]
995
1058
  }, column);
996
1059
  });
@@ -1001,7 +1064,7 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1001
1064
  // not
1002
1065
  if (op === Op.not) {
1003
1066
  builder[having ? 'havingNot' : 'whereNot'](builder => {
1004
- _buildWhereInner(false, knex, builder, wheres, column);
1067
+ _buildWhereInner(false, db, builder, wheres, column);
1005
1068
  });
1006
1069
  return;
1007
1070
  }
@@ -1015,59 +1078,52 @@ function _buildWhereOpJoint(having, knex, builder, column, wheres, op) {
1015
1078
  builder[having ? 'havingNotExists' : 'whereNotExists'](wheres);
1016
1079
  }
1017
1080
  }
1018
- function _buildWhereColumn(having, knex, builder, column, value, op) {
1081
+ function _buildWhereColumn(having, db, builder, column, value, op) {
1019
1082
  // skip
1020
1083
  if (value === Op.skip) {
1021
1084
  return;
1022
1085
  }
1023
1086
  // raw
1024
1087
  if (isRaw(value) || isRef(value)) {
1025
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1088
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1026
1089
  return;
1027
1090
  }
1028
1091
  // null/undefined
1029
1092
  if (isNil(value)) {
1030
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.is);
1093
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.is);
1031
1094
  return;
1032
1095
  }
1033
1096
  // array
1034
1097
  if (Array.isArray(value)) {
1035
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.in);
1098
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.in);
1036
1099
  return;
1037
1100
  }
1038
1101
  // date
1039
1102
  if (value instanceof Date) {
1040
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1103
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1041
1104
  return;
1042
1105
  }
1043
1106
  // object
1044
1107
  if (typeof value === 'object') {
1045
1108
  builder[having ? 'having' : 'where'](builder => {
1046
- _buildWhereInner(false, knex, builder, value, column);
1109
+ _buildWhereInner(false, db, builder, value, column);
1047
1110
  });
1048
1111
  return;
1049
1112
  }
1050
1113
  // column
1051
- _buildWhereColumnOpNormal(having, knex, builder, column, value, op ?? Op.eq);
1114
+ _buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
1052
1115
  }
1053
- function _buildWhereColumnOpNormal(having, knex, builder, column, value, op) {
1054
- column = _checkHavingColumn(knex, column);
1055
- if (_shouldPatchLike(knex)) {
1056
- if (op === Op.startsWith) op = Op.startsWithI;
1057
- if (op === Op.endsWith) op = Op.endsWithI;
1058
- if (op === Op.includes) op = Op.includesI;
1059
- if (op === Op.eqI) op = Op.eq;
1060
- if (op === Op.notEqI) op = Op.notEq;
1061
- }
1116
+ function _buildWhereColumnOpNormal(having, db, builder, column, value, op) {
1117
+ column = _checkHavingColumn(db, column);
1062
1118
  if (op === Op.eq) {
1063
1119
  builder[having ? 'having' : 'where'](column, '=', value);
1064
1120
  } else if (op === Op.notEq) {
1065
1121
  builder[having ? 'having' : 'where'](column, '<>', value);
1066
1122
  } else if (op === Op.eqI) {
1067
- builder[having ? 'havingILike' : 'whereILike'](column, value);
1123
+ builder[_getOpILikeReal(having, db)](column, value);
1068
1124
  } else if (op === Op.notEqI) {
1069
1125
  builder[having ? 'havingNot' : 'whereNot'](builder => {
1070
- builder[having ? 'havingILike' : 'whereILike'](column, value);
1126
+ builder[_getOpILikeReal(having, db)](column, value);
1071
1127
  });
1072
1128
  } else if (op === Op.gt) {
1073
1129
  builder[having ? 'having' : 'where'](column, '>', value);
@@ -1096,27 +1152,23 @@ function _buildWhereColumnOpNormal(having, knex, builder, column, value, op) {
1096
1152
  } else if (op === Op.includes) {
1097
1153
  builder[having ? 'havingLike' : 'whereLike'](column, `%${value}%`);
1098
1154
  } else if (op === Op.startsWithI) {
1099
- builder[having ? 'havingILike' : 'whereILike'](column, `${value}%`);
1155
+ builder[_getOpILikeReal(having, db)](column, `${value}%`);
1100
1156
  } else if (op === Op.endsWithI) {
1101
- builder[having ? 'havingILike' : 'whereILike'](column, `%${value}`);
1157
+ builder[_getOpILikeReal(having, db)](column, `%${value}`);
1102
1158
  } else if (op === Op.includesI) {
1103
- builder[having ? 'havingILike' : 'whereILike'](column, `%${value}%`);
1159
+ builder[_getOpILikeReal(having, db)](column, `%${value}%`);
1104
1160
  } else if (op === Op.ref) {
1105
- builder[having ? 'having' : 'where'](column, '=', knex.ref(value));
1161
+ builder[having ? 'having' : 'where'](column, '=', db.connection.ref(value));
1106
1162
  }
1107
1163
  }
1108
- function _shouldPatchLike(knex) {
1109
- const dialectName = _getDialectName(knex);
1110
- return dialectName === 'mysql' || dialectName === 'mysql2';
1111
- }
1112
- function _getDialectName(knex) {
1113
- return knex.client.config.client;
1164
+ function _getOpILikeReal(having, db) {
1165
+ return db.dialect.capabilities.ilike ? having ? 'havingILike' : 'whereILike' : having ? 'havingLike' : 'whereLike';
1114
1166
  }
1115
- function _checkHavingColumn(knex, column) {
1167
+ function _checkHavingColumn(db, column) {
1116
1168
  let [aggr, name] = cast(column).split('_');
1117
1169
  if (!OpAggrs.includes(aggr) || !name) return column;
1118
1170
  if (aggr === 'count' && name === 'all') name = '*';
1119
- return knex.raw(`${_safeOp(aggr)}(${_safeColumn(name)})`);
1171
+ return db.connection.raw(`${_safeOp(aggr)}(${_safeColumn(name)})`);
1120
1172
  }
1121
1173
  function _checkOpJoint(op) {
1122
1174
  for (const item of OpJointValues) {
@@ -1589,7 +1641,7 @@ class BeanModelUtils extends BeanModelMeta {
1589
1641
 
1590
1642
  buildWhere(builder, wheres) {
1591
1643
  if (!wheres) return;
1592
- return buildWhere(this.connection, builder, wheres);
1644
+ return buildWhere(this.db, builder, wheres);
1593
1645
  }
1594
1646
  buildJoin(builder, join) {
1595
1647
  if (!join) return;
@@ -1677,7 +1729,7 @@ class BeanModelUtils extends BeanModelMeta {
1677
1729
  this.buildHaving(builder, having);
1678
1730
  }
1679
1731
  buildHaving(builder, having) {
1680
- return buildWhere(this.connection, builder, having, true);
1732
+ return buildWhere(this.db, builder, having, true);
1681
1733
  }
1682
1734
  prepareWhere(builder, table, where, options) {
1683
1735
  // table
@@ -1958,7 +2010,9 @@ class BeanModelCrudInner extends BeanModelView {
1958
2010
  builder = builder ?? this._select_buildParams(table, params, options);
1959
2011
  // ready
1960
2012
  this.$loggerChild('model').debug(() => `model.select: ${builder.toQuery()}`);
1961
- return await builder;
2013
+ // datas
2014
+ const datas = await builder;
2015
+ return await this.dialect.select(builder, datas, () => this.columns(table));
1962
2016
  }
1963
2017
  _select_buildParams(table, params, options) {
1964
2018
  // builder
@@ -3718,9 +3772,10 @@ function config(_app) {
3718
3772
  expired: 14 * 24 * 3600 * 1000
3719
3773
  },
3720
3774
  dialects: {
3721
- mysql: 'a-ormdialect.databaseDialect.mysql',
3722
- mysql2: 'a-ormdialect.databaseDialect.mysql3',
3723
- pg: 'a-ormdialect.databaseDialect.pg'
3775
+ 'better-sqlite3': 'a-ormdialect:betterSqlite3',
3776
+ 'mysql': 'a-ormdialect:mysql',
3777
+ 'mysql2': 'a-ormdialect:mysql3',
3778
+ 'pg': 'a-ormdialect:pg'
3724
3779
  },
3725
3780
  summer: {
3726
3781
  enable: true,
@@ -3763,7 +3818,7 @@ function ExtendSchemaBuilder(app) {
3763
3818
  ['fetchDatabases', 'createDatabase', 'dropDatabase', 'fetchIndexes'].forEach(method => {
3764
3819
  knex.SchemaBuilder.extend(method, async function (...args) {
3765
3820
  const client = cast(cast(this).client).config.client;
3766
- const dialect = app.scope('a-orm').service.database.getDialect(client);
3821
+ const dialect = app.bean.database.getDialect(client);
3767
3822
  return await dialect[method](this, ...args);
3768
3823
  });
3769
3824
  });
@@ -3911,8 +3966,8 @@ function $locale(key) {
3911
3966
  }
3912
3967
  /** scope: end */
3913
3968
 
3914
- function DatabaseDialect() {
3915
- return createBeanDecorator('databaseDialect');
3969
+ function DatabaseDialect(options) {
3970
+ return createBeanDecorator('databaseDialect', options);
3916
3971
  }
3917
3972
 
3918
3973
  function DtoAggregate(modelLike, aggrs) {
@@ -1 +1,2 @@
1
- export declare function DatabaseDialect(): ClassDecorator;
1
+ import type { IDecoratorDatabaseDialectOptions } from '../types/index.ts';
2
+ export declare function DatabaseDialect<T extends IDecoratorDatabaseDialectOptions>(options?: T): ClassDecorator;
@@ -4,10 +4,9 @@ import type { IDatabaseClientDialectRecord, IDatabaseClientRecord, IDbInfo } fro
4
4
  import { BeanBase } from 'vona';
5
5
  export declare class ServiceDatabase extends BeanBase {
6
6
  get configDatabase(): import("../types/config.ts").ConfigDatabase;
7
- getDialect(client: keyof IDatabaseClientDialectRecord): BeanDatabaseDialectBase;
8
- getClientConfig(clientName: keyof IDatabaseClientRecord, original?: boolean): ConfigDatabaseClient;
7
+ getClientConfig(clientName: keyof IDatabaseClientRecord, clientConfig?: ConfigDatabaseClient, original?: boolean): ConfigDatabaseClient;
9
8
  prepareDbInfo(dbInfoOrClientName?: Partial<IDbInfo> | keyof IDatabaseClientRecord): IDbInfo;
10
- prepareClientNameSelector(dbInfo: IDbInfo): string;
9
+ prepareClientNameSelector(dbInfo: IDbInfo, dialect: BeanDatabaseDialectBase | keyof IDatabaseClientDialectRecord): string;
11
10
  parseClientNameSelector(clientNameSelector: string): IDbInfo;
12
11
  prepareClientName(clientName?: keyof IDatabaseClientRecord): keyof IDatabaseClientRecord;
13
12
  getDefaultClientName(): keyof IDatabaseClientRecord;
@@ -1,11 +1,11 @@
1
1
  import type knex from 'knex';
2
- import type { IDbInfo } from '../types/index.ts';
2
+ import type { ServiceDb } from './db_.ts';
3
3
  import { BeanBase } from 'vona';
4
4
  import { ServiceTransactionFiber } from './transactionFiber_.ts';
5
5
  export declare class ServiceTransactionState extends BeanBase {
6
6
  private _fibers;
7
7
  private get serviceDatabase();
8
- get(dbInfo: IDbInfo): ServiceTransactionFiber | undefined;
9
- add(dbInfo: IDbInfo, connection: knex.Knex.Transaction): ServiceTransactionFiber;
10
- remove(dbInfo: IDbInfo): void;
8
+ get(db: ServiceDb): ServiceTransactionFiber | undefined;
9
+ add(db: ServiceDb, connection: knex.Knex.Transaction): ServiceTransactionFiber;
10
+ remove(db: ServiceDb): void;
11
11
  }
@@ -1,6 +1,7 @@
1
1
  import type { Knex } from 'knex';
2
2
  import type { VonaContext } from 'vona';
3
3
  import type { IDatabaseClientDialectRecord, IDatabaseClientRecord } from './database.ts';
4
+ import type { IDatabaseDialectRecord } from './onion/databaseDialect.ts';
4
5
  export type TypeDefaultClientNameFn = (ctx?: VonaContext) => keyof IDatabaseClientRecord;
5
6
  export type TypeDefaultClientName = TypeDefaultClientNameFn | keyof IDatabaseClientRecord;
6
7
  export interface ConfigDatabaseClient extends Omit<Knex.Config, 'client'> {
@@ -12,3 +13,6 @@ export interface ConfigDatabase {
12
13
  clients: Record<keyof IDatabaseClientRecord, ConfigDatabaseClient>;
13
14
  base: ConfigDatabaseClient;
14
15
  }
16
+ export type IDataBaseConfigDialects = {
17
+ [KEY in keyof IDatabaseClientDialectRecord]: keyof IDatabaseDialectRecord;
18
+ };
@@ -8,13 +8,15 @@ export interface IDbInfo {
8
8
  }
9
9
  export interface IDatabaseClientRecord {
10
10
  default: never;
11
+ sqlite3: never;
11
12
  pg: never;
12
13
  mysql: never;
13
14
  }
14
15
  export interface IDatabaseClientDialectRecord {
15
- pg: never;
16
- mysql: never;
17
- mysql2: never;
16
+ 'better-sqlite3': never;
17
+ 'pg': never;
18
+ 'mysql': never;
19
+ 'mysql2': never;
18
20
  }
19
21
  export interface IDatabaseSwitchOptions {
20
22
  clientName?: keyof IDatabaseClientRecord;
@@ -33,6 +35,8 @@ declare module 'vona' {
33
35
  }
34
36
  interface VonaConfigEnv {
35
37
  DATABASE_DEFAULT_CLIENT: string | undefined;
38
+ DATABASE_CLIENT_SQLITE3_FILENAME: string | undefined;
39
+ DATABASE_CLIENT_SQLITE3_NATIVEBINDING: string | undefined;
36
40
  DATABASE_CLIENT_PG_HOST: string | undefined;
37
41
  DATABASE_CLIENT_PG_PORT: string | undefined;
38
42
  DATABASE_CLIENT_PG_USER: string | undefined;
@@ -1,6 +1,12 @@
1
+ import type { ITableColumns } from './columns.ts';
1
2
  export interface IFetchDatabasesResultItem {
2
3
  name: string;
3
4
  }
4
5
  export interface IFetchIndexesResultItem {
5
6
  indexName: string;
6
7
  }
8
+ export type TypeDatabaseDialectTableColumnsFn = () => Promise<ITableColumns>;
9
+ export interface IDatabaseDialectCapabilities {
10
+ ilike: boolean;
11
+ level: boolean;
12
+ }
@@ -1,3 +1,4 @@
1
+ import type { OmitNever } from 'vona';
1
2
  import type { ServiceOnion } from 'vona-module-a-onion';
2
3
  export interface IDatabaseDialectRecord {
3
4
  }
@@ -10,6 +11,7 @@ declare module 'vona-module-a-onion' {
10
11
  }
11
12
  declare module 'vona' {
12
13
  interface ConfigOnions {
14
+ databaseDialect: OmitNever<IDatabaseDialectRecord>;
13
15
  }
14
16
  interface IBeanSceneRecord {
15
17
  databaseDialect: never;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vona-module-a-orm",
3
3
  "type": "module",
4
- "version": "5.0.84",
4
+ "version": "5.0.86",
5
5
  "title": "a-orm",
6
6
  "vonaModule": {
7
7
  "capabilities": {
@@ -33,6 +33,8 @@
33
33
  },
34
34
  "databaseDialect": {
35
35
  "beanGeneral": true,
36
+ "optionsGlobalInterfaceName": "IDecoratorDatabaseDialectOptions",
37
+ "optionsGlobalInterfaceFrom": "vona-module-a-orm",
36
38
  "boilerplate": "cli/databaseDialect/boilerplate"
37
39
  }
38
40
  }