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.
- package/cli/databaseDialect/boilerplate/{{sceneName}}.{{beanName}}.ts_ +4 -1
- package/dist/bean/bean.database.d.ts +3 -1
- package/dist/bean/bean.databaseDialectBase.d.ts +10 -3
- package/dist/common/buildWhere.d.ts +2 -1
- package/dist/config/config.d.ts +3 -4
- package/dist/extend/schemaBuilder.d.ts +1 -1
- package/dist/index.js +143 -88
- package/dist/lib/databaseDialect.d.ts +2 -1
- package/dist/service/database.d.ts +2 -3
- package/dist/service/transactionState_.d.ts +4 -4
- package/dist/types/config.d.ts +4 -0
- package/dist/types/database.d.ts +7 -3
- package/dist/types/dialect.d.ts +6 -0
- package/dist/types/onion/databaseDialect.d.ts +2 -0
- package/package.json +3 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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<
|
|
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>(
|
|
4
|
+
export declare function buildWhere<TRecord>(db: ServiceDb, builder: Knex.QueryBuilder, wheres: TypeModelWhere<TRecord>, having?: boolean): void;
|
package/dist/config/config.d.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { TableIdentityType } from 'table-identity';
|
|
2
|
-
import type {
|
|
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 {
|
|
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:
|
|
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<
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
203
|
-
|
|
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.
|
|
210
|
-
const configBaseClient = dialect.getConfigBase();
|
|
204
|
+
const dialect = this.bean.database.getDialect(clientConfig.client);
|
|
211
205
|
// combine
|
|
212
|
-
|
|
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(
|
|
394
|
-
const selector = this.serviceDatabase.prepareClientNameSelector(
|
|
388
|
+
get(db) {
|
|
389
|
+
const selector = this.serviceDatabase.prepareClientNameSelector(db.info, db.dialect);
|
|
395
390
|
return this._fibers[selector];
|
|
396
391
|
}
|
|
397
|
-
add(
|
|
398
|
-
const selector = this.serviceDatabase.prepareClientNameSelector(
|
|
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(
|
|
404
|
-
const selector = this.serviceDatabase.prepareClientNameSelector(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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,
|
|
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
|
|
741
|
-
|
|
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
|
|
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
|
-
|
|
771
|
-
|
|
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(
|
|
938
|
-
_buildWhereInner(having,
|
|
1000
|
+
function buildWhere(db, builder, wheres, having = false) {
|
|
1001
|
+
_buildWhereInner(having, db, builder, wheres);
|
|
939
1002
|
}
|
|
940
|
-
function _buildWhereInner(having,
|
|
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,
|
|
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,
|
|
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,
|
|
1028
|
+
_buildWhereOpJoint(having, db, builder, column, value, op);
|
|
966
1029
|
}
|
|
967
1030
|
}
|
|
968
1031
|
}
|
|
969
1032
|
}
|
|
970
|
-
function _buildWhereOpJoint(having,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
1109
|
+
_buildWhereInner(false, db, builder, value, column);
|
|
1047
1110
|
});
|
|
1048
1111
|
return;
|
|
1049
1112
|
}
|
|
1050
1113
|
// column
|
|
1051
|
-
_buildWhereColumnOpNormal(having,
|
|
1114
|
+
_buildWhereColumnOpNormal(having, db, builder, column, value, op ?? Op.eq);
|
|
1052
1115
|
}
|
|
1053
|
-
function _buildWhereColumnOpNormal(having,
|
|
1054
|
-
column = _checkHavingColumn(
|
|
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
|
|
1123
|
+
builder[_getOpILikeReal(having, db)](column, value);
|
|
1068
1124
|
} else if (op === Op.notEqI) {
|
|
1069
1125
|
builder[having ? 'havingNot' : 'whereNot'](builder => {
|
|
1070
|
-
builder[having
|
|
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
|
|
1155
|
+
builder[_getOpILikeReal(having, db)](column, `${value}%`);
|
|
1100
1156
|
} else if (op === Op.endsWithI) {
|
|
1101
|
-
builder[having
|
|
1157
|
+
builder[_getOpILikeReal(having, db)](column, `%${value}`);
|
|
1102
1158
|
} else if (op === Op.includesI) {
|
|
1103
|
-
builder[having
|
|
1159
|
+
builder[_getOpILikeReal(having, db)](column, `%${value}%`);
|
|
1104
1160
|
} else if (op === Op.ref) {
|
|
1105
|
-
builder[having ? 'having' : 'where'](column, '=',
|
|
1161
|
+
builder[having ? 'having' : 'where'](column, '=', db.connection.ref(value));
|
|
1106
1162
|
}
|
|
1107
1163
|
}
|
|
1108
|
-
function
|
|
1109
|
-
|
|
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(
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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(
|
|
9
|
-
add(
|
|
10
|
-
remove(
|
|
8
|
+
get(db: ServiceDb): ServiceTransactionFiber | undefined;
|
|
9
|
+
add(db: ServiceDb, connection: knex.Knex.Transaction): ServiceTransactionFiber;
|
|
10
|
+
remove(db: ServiceDb): void;
|
|
11
11
|
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -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
|
+
};
|
package/dist/types/database.d.ts
CHANGED
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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;
|
package/dist/types/dialect.d.ts
CHANGED
|
@@ -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.
|
|
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
|
}
|