@sqb/connect 4.1.5 → 4.5.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 +67 -0
- package/{dist/client/Adapter.js → cjs/client/adapter.js} +0 -0
- package/{dist/client/CursorStream.js → cjs/client/cursor-stream.js} +5 -2
- package/{dist/client/Cursor.js → cjs/client/cursor.js} +18 -11
- package/{dist → cjs}/client/extensions.js +0 -0
- package/{dist/client/FieldInfoMap.js → cjs/client/field-info-map.js} +2 -0
- package/{dist → cjs}/client/helpers.js +2 -2
- package/{dist/client/SqbClient.js → cjs/client/sqb-client.js} +16 -10
- package/{dist/client/SqbConnection.js → cjs/client/sqb-connection.js} +17 -14
- package/{dist → cjs}/client/types.js +0 -0
- package/cjs/index.js +42 -0
- package/{dist → cjs}/orm/backward.js +8 -8
- package/cjs/orm/base-entity.js +29 -0
- package/{dist → cjs}/orm/commands/command.helper.js +9 -9
- package/{dist → cjs}/orm/commands/count.command.js +2 -2
- package/{dist → cjs}/orm/commands/create.command.js +12 -12
- package/{dist → cjs}/orm/commands/destroy.command.js +2 -2
- package/{dist → cjs}/orm/commands/find.command.js +100 -88
- package/{dist → cjs}/orm/commands/row-converter.js +10 -7
- package/{dist → cjs}/orm/commands/update.command.js +10 -10
- package/{dist → cjs}/orm/decorators/column.decorator.js +3 -3
- package/{dist → cjs}/orm/decorators/embedded.decorator.js +3 -3
- package/cjs/orm/decorators/entity.decorator.js +179 -0
- package/{dist → cjs}/orm/decorators/events.decorator.js +13 -13
- package/{dist → cjs}/orm/decorators/foreignkey.decorator.js +3 -3
- package/{dist → cjs}/orm/decorators/index.decorator.js +5 -5
- package/cjs/orm/decorators/link.decorator.js +70 -0
- package/{dist → cjs}/orm/decorators/primarykey.decorator.js +7 -7
- package/{dist → cjs}/orm/decorators/transform.decorator.js +5 -5
- package/cjs/orm/model/association-field-metadata.js +24 -0
- package/{dist → cjs}/orm/model/association-node.js +5 -2
- package/{dist → cjs}/orm/model/association.js +31 -39
- package/{dist/orm/model/column-element-metadata.js → cjs/orm/model/column-field-metadata.js} +8 -8
- package/{dist/orm/model/embedded-element-metadata.js → cjs/orm/model/embedded-field-metadata.js} +8 -8
- package/{dist → cjs}/orm/model/entity-metadata.js +90 -91
- package/{dist/orm/model/element-metadata.js → cjs/orm/model/field-metadata.js} +0 -0
- package/{dist → cjs}/orm/model/index-metadata.js +0 -0
- package/{dist → cjs}/orm/model/link-chain.js +12 -15
- package/{dist → cjs}/orm/orm.const.js +0 -0
- package/{dist → cjs}/orm/orm.type.js +0 -0
- package/{dist → cjs}/orm/repository.class.js +25 -22
- package/{dist → cjs}/orm/util/apply-mixins.js +0 -0
- package/{dist → cjs}/orm/util/extract-keyvalues.js +5 -5
- package/{dist → cjs}/orm/util/orm.helper.js +10 -10
- package/{dist/orm/util/serialize-element.js → cjs/orm/util/serialize-field.js} +2 -2
- package/cjs/package.json +3 -0
- package/{dist → cjs}/types.js +0 -0
- package/{dist/client/Adapter.d.ts → esm/client/adapter.d.ts} +1 -1
- package/esm/client/adapter.js +1 -0
- package/{dist/client/CursorStream.d.ts → esm/client/cursor-stream.d.ts} +1 -1
- package/esm/client/cursor-stream.js +96 -0
- package/{dist/client/Cursor.d.ts → esm/client/cursor.d.ts} +5 -5
- package/esm/client/cursor.js +252 -0
- package/{dist → esm}/client/extensions.d.ts +1 -1
- package/esm/client/extensions.js +9 -0
- package/{dist/client/FieldInfoMap.d.ts → esm/client/field-info-map.d.ts} +1 -1
- package/esm/client/field-info-map.js +50 -0
- package/{dist → esm}/client/helpers.d.ts +3 -3
- package/esm/client/helpers.js +125 -0
- package/{dist/client/SqbClient.d.ts → esm/client/sqb-client.d.ts} +4 -10
- package/esm/client/sqb-client.js +166 -0
- package/{dist/client/SqbConnection.d.ts → esm/client/sqb-connection.d.ts} +4 -4
- package/esm/client/sqb-connection.js +270 -0
- package/{dist → esm}/client/types.d.ts +5 -13
- package/esm/client/types.js +1 -0
- package/esm/index.d.ts +33 -0
- package/esm/index.js +32 -0
- package/{dist → esm}/orm/backward.d.ts +1 -1
- package/esm/orm/backward.js +17 -0
- package/{dist → esm}/orm/base-entity.d.ts +1 -1
- package/esm/orm/base-entity.js +25 -0
- package/{dist → esm}/orm/commands/command.helper.d.ts +2 -2
- package/esm/orm/commands/command.helper.js +135 -0
- package/{dist → esm}/orm/commands/count.command.d.ts +3 -3
- package/esm/orm/commands/count.command.js +26 -0
- package/{dist → esm}/orm/commands/create.command.d.ts +2 -2
- package/esm/orm/commands/create.command.js +85 -0
- package/{dist → esm}/orm/commands/destroy.command.d.ts +3 -3
- package/esm/orm/commands/destroy.command.js +26 -0
- package/{dist → esm}/orm/commands/find.command.d.ts +9 -9
- package/esm/orm/commands/find.command.js +318 -0
- package/{dist → esm}/orm/commands/row-converter.d.ts +5 -5
- package/esm/orm/commands/row-converter.js +186 -0
- package/{dist → esm}/orm/commands/update.command.d.ts +3 -3
- package/esm/orm/commands/update.command.js +80 -0
- package/esm/orm/decorators/column.decorator.d.ts +4 -0
- package/esm/orm/decorators/column.decorator.js +19 -0
- package/esm/orm/decorators/embedded.decorator.d.ts +3 -0
- package/esm/orm/decorators/embedded.decorator.js +12 -0
- package/{dist → esm}/orm/decorators/entity.decorator.d.ts +17 -17
- package/esm/orm/decorators/entity.decorator.js +175 -0
- package/{dist → esm}/orm/decorators/events.decorator.d.ts +0 -0
- package/esm/orm/decorators/events.decorator.js +55 -0
- package/{dist → esm}/orm/decorators/foreignkey.decorator.d.ts +1 -1
- package/esm/orm/decorators/foreignkey.decorator.js +9 -0
- package/{dist → esm}/orm/decorators/index.decorator.d.ts +1 -1
- package/esm/orm/decorators/index.decorator.js +17 -0
- package/esm/orm/decorators/link.decorator.d.ts +13 -0
- package/esm/orm/decorators/link.decorator.js +66 -0
- package/{dist → esm}/orm/decorators/primarykey.decorator.d.ts +1 -1
- package/esm/orm/decorators/primarykey.decorator.js +20 -0
- package/{dist → esm}/orm/decorators/transform.decorator.d.ts +1 -1
- package/esm/orm/decorators/transform.decorator.js +19 -0
- package/esm/orm/model/association-field-metadata.d.ts +12 -0
- package/esm/orm/model/association-field-metadata.js +20 -0
- package/{dist → esm}/orm/model/association-node.d.ts +1 -1
- package/esm/orm/model/association-node.js +24 -0
- package/{dist → esm}/orm/model/association.d.ts +6 -7
- package/esm/orm/model/association.js +118 -0
- package/{dist/orm/model/column-element-metadata.d.ts → esm/orm/model/column-field-metadata.d.ts} +10 -14
- package/esm/orm/model/column-field-metadata.js +28 -0
- package/esm/orm/model/embedded-field-metadata.d.ts +14 -0
- package/esm/orm/model/embedded-field-metadata.js +25 -0
- package/esm/orm/model/entity-metadata.d.ts +50 -0
- package/esm/orm/model/entity-metadata.js +337 -0
- package/esm/orm/model/field-metadata.d.ts +16 -0
- package/esm/orm/model/field-metadata.js +1 -0
- package/{dist → esm}/orm/model/index-metadata.d.ts +0 -0
- package/esm/orm/model/index-metadata.js +1 -0
- package/esm/orm/model/link-chain.d.ts +13 -0
- package/esm/orm/model/link-chain.js +43 -0
- package/{dist → esm}/orm/orm.const.d.ts +0 -0
- package/esm/orm/orm.const.js +2 -0
- package/{dist → esm}/orm/orm.type.d.ts +3 -4
- package/esm/orm/orm.type.js +1 -0
- package/{dist → esm}/orm/repository.class.d.ts +23 -23
- package/esm/orm/repository.class.js +238 -0
- package/{dist → esm}/orm/util/apply-mixins.d.ts +0 -0
- package/esm/orm/util/apply-mixins.js +9 -0
- package/{dist → esm}/orm/util/extract-keyvalues.d.ts +1 -1
- package/esm/orm/util/extract-keyvalues.js +57 -0
- package/esm/orm/util/orm.helper.d.ts +13 -0
- package/esm/orm/util/orm.helper.js +28 -0
- package/esm/orm/util/serialize-field.d.ts +2 -0
- package/esm/orm/util/serialize-field.js +39 -0
- package/esm/types.d.ts +7 -0
- package/esm/types.js +1 -0
- package/package.json +56 -43
- package/dist/index.d.ts +0 -33
- package/dist/index.js +0 -42
- package/dist/orm/base-entity.js +0 -28
- package/dist/orm/decorators/column.decorator.d.ts +0 -4
- package/dist/orm/decorators/embedded.decorator.d.ts +0 -3
- package/dist/orm/decorators/entity.decorator.js +0 -179
- package/dist/orm/decorators/link.decorator.d.ts +0 -23
- package/dist/orm/decorators/link.decorator.js +0 -88
- package/dist/orm/model/association-element-metadata.d.ts +0 -10
- package/dist/orm/model/association-element-metadata.js +0 -15
- package/dist/orm/model/element-metadata.d.ts +0 -7
- package/dist/orm/model/embedded-element-metadata.d.ts +0 -14
- package/dist/orm/model/entity-metadata.d.ts +0 -50
- package/dist/orm/model/link-chain.d.ts +0 -15
- package/dist/orm/util/orm.helper.d.ts +0 -13
- package/dist/orm/util/serialize-element.d.ts +0 -2
- package/dist/types.d.ts +0 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import _debug from 'debug';
|
|
2
|
+
import { createPool, PoolState } from 'lightning-pool';
|
|
3
|
+
import { coerceToBoolean, coerceToInt } from 'putil-varhelpers';
|
|
4
|
+
import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
|
|
5
|
+
import { EntityMetadata } from '../orm/model/entity-metadata.js';
|
|
6
|
+
import { Repository } from '../orm/repository.class.js';
|
|
7
|
+
import { adapters } from './extensions.js';
|
|
8
|
+
import { SqbConnection } from './sqb-connection.js';
|
|
9
|
+
const debug = _debug('sqb:client');
|
|
10
|
+
const inspect = Symbol.for('nodejs.util.inspect.custom');
|
|
11
|
+
export class SqbClient extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
12
|
+
_adapter;
|
|
13
|
+
_pool;
|
|
14
|
+
_defaults;
|
|
15
|
+
_entities = {};
|
|
16
|
+
constructor(config) {
|
|
17
|
+
super();
|
|
18
|
+
if (!(config && typeof config === 'object'))
|
|
19
|
+
throw new TypeError('Configuration object required');
|
|
20
|
+
let adapter;
|
|
21
|
+
if (config.driver) {
|
|
22
|
+
adapter = adapters.find(x => x.driver === config.driver);
|
|
23
|
+
if (!adapter)
|
|
24
|
+
throw new Error(`No database adapter registered for "${config.driver}" driver`);
|
|
25
|
+
}
|
|
26
|
+
else if (config.dialect) {
|
|
27
|
+
adapter = adapters.find(x => x.dialect === config.dialect);
|
|
28
|
+
if (!adapter)
|
|
29
|
+
throw new Error(`No database adapter registered for "${config.dialect}" dialect`);
|
|
30
|
+
}
|
|
31
|
+
if (!adapter)
|
|
32
|
+
throw new Error(`You must provide one of "driver" or "dialect" properties`);
|
|
33
|
+
this._adapter = adapter;
|
|
34
|
+
this._defaults = config.defaults || {};
|
|
35
|
+
const poolOptions = {};
|
|
36
|
+
const popts = config.pool || {};
|
|
37
|
+
poolOptions.acquireMaxRetries = coerceToInt(popts.acquireMaxRetries, 0);
|
|
38
|
+
poolOptions.acquireRetryWait = coerceToInt(popts.acquireRetryWait, 2000);
|
|
39
|
+
poolOptions.acquireTimeoutMillis = coerceToInt(popts.acquireTimeoutMillis, 0);
|
|
40
|
+
poolOptions.idleTimeoutMillis = coerceToInt(popts.idleTimeoutMillis, 30000);
|
|
41
|
+
poolOptions.max = coerceToInt(popts.max, 10);
|
|
42
|
+
poolOptions.maxQueue = coerceToInt(popts.maxQueue, 1000);
|
|
43
|
+
poolOptions.max = coerceToInt(popts.max, 10);
|
|
44
|
+
poolOptions.min = coerceToInt(popts.min, 0);
|
|
45
|
+
poolOptions.minIdle = coerceToInt(popts.minIdle, 0);
|
|
46
|
+
poolOptions.validation = coerceToBoolean(popts.validation, false);
|
|
47
|
+
const cfg = { ...config };
|
|
48
|
+
const poolFactory = {
|
|
49
|
+
create: () => adapter.connect(cfg),
|
|
50
|
+
destroy: instance => instance.close(),
|
|
51
|
+
reset: instance => instance.reset(),
|
|
52
|
+
validate: instance => instance.test()
|
|
53
|
+
};
|
|
54
|
+
this._pool = createPool(poolFactory, poolOptions);
|
|
55
|
+
this._pool.on('closing', () => this.emit('closing'));
|
|
56
|
+
this._pool.on('close', () => this.emit('close'));
|
|
57
|
+
this._pool.on('terminate', () => this.emit('terminate'));
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
this._pool.on('error', (...args) => this.emit('error', ...args));
|
|
60
|
+
}
|
|
61
|
+
get defaults() {
|
|
62
|
+
return this._defaults;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns dialect
|
|
66
|
+
*/
|
|
67
|
+
get dialect() {
|
|
68
|
+
return this._adapter.dialect;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns database driver name
|
|
72
|
+
*/
|
|
73
|
+
get driver() {
|
|
74
|
+
return this._adapter.driver;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Returns true if pool is closed
|
|
78
|
+
*/
|
|
79
|
+
get isClosed() {
|
|
80
|
+
return this._pool.state === PoolState.CLOSED;
|
|
81
|
+
}
|
|
82
|
+
get pool() {
|
|
83
|
+
return this._pool;
|
|
84
|
+
}
|
|
85
|
+
async acquire(arg0, arg1) {
|
|
86
|
+
debug('acquire');
|
|
87
|
+
if (typeof arg0 === 'function') {
|
|
88
|
+
const connection = await this.acquire(arg1);
|
|
89
|
+
try {
|
|
90
|
+
return await arg0(connection);
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
connection.release();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const options = arg1;
|
|
97
|
+
const adapterConnection = await this._pool.acquire();
|
|
98
|
+
const opts = { autoCommit: this.defaults.autoCommit, ...options };
|
|
99
|
+
const connection = new SqbConnection(this, adapterConnection, opts);
|
|
100
|
+
await this.emitAsyncSerial('acquire', connection);
|
|
101
|
+
connection.on('execute', (request) => this.emit('execute', request));
|
|
102
|
+
connection.on('error', (error) => this.emit('error', error));
|
|
103
|
+
return connection;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Shuts down the pool and destroys all resources.
|
|
107
|
+
*/
|
|
108
|
+
async close(terminateWait) {
|
|
109
|
+
const ms = terminateWait == null ? Infinity : 0;
|
|
110
|
+
return this._pool.close(ms);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Executes a query or callback with a new acquired connection.
|
|
114
|
+
*/
|
|
115
|
+
async execute(query, options) {
|
|
116
|
+
debug('execute');
|
|
117
|
+
const connection = await this.acquire();
|
|
118
|
+
try {
|
|
119
|
+
const qr = await connection.execute(query, options);
|
|
120
|
+
if (qr && qr.cursor) {
|
|
121
|
+
connection.retain();
|
|
122
|
+
qr.cursor.once('close', () => connection.release());
|
|
123
|
+
}
|
|
124
|
+
return qr;
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
connection.release();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Tests the pool
|
|
132
|
+
*/
|
|
133
|
+
async test() {
|
|
134
|
+
const connection = await this.acquire();
|
|
135
|
+
try {
|
|
136
|
+
await connection.test();
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
connection.release();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
getRepository(entity, opts) {
|
|
143
|
+
let ctor;
|
|
144
|
+
if (typeof entity === 'string') {
|
|
145
|
+
ctor = this.getEntity(entity);
|
|
146
|
+
if (!ctor)
|
|
147
|
+
throw new Error(`Repository "${entity}" is not registered`);
|
|
148
|
+
}
|
|
149
|
+
else
|
|
150
|
+
ctor = entity;
|
|
151
|
+
const entityDef = EntityMetadata.get(ctor);
|
|
152
|
+
if (!entityDef)
|
|
153
|
+
throw new Error(`You must provide an @Entity annotated constructor`);
|
|
154
|
+
return new Repository(entityDef, this, opts?.schema);
|
|
155
|
+
}
|
|
156
|
+
getEntity(name) {
|
|
157
|
+
return this._entities[name];
|
|
158
|
+
}
|
|
159
|
+
toString() {
|
|
160
|
+
return '[object ' + Object.getPrototypeOf(this).constructor.name + '(' +
|
|
161
|
+
this.dialect + ')]';
|
|
162
|
+
}
|
|
163
|
+
[inspect]() {
|
|
164
|
+
return this.toString();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Type } from 'ts-gems';
|
|
2
2
|
import { classes } from '@sqb/builder';
|
|
3
|
-
import { Repository } from '../orm/repository.class';
|
|
4
|
-
import { Adapter } from './
|
|
5
|
-
import { SqbClient } from './
|
|
6
|
-
import { ConnectionOptions, QueryExecuteOptions, QueryRequest } from './types';
|
|
3
|
+
import { Repository } from '../orm/repository.class.js';
|
|
4
|
+
import { Adapter } from './adapter.js';
|
|
5
|
+
import { SqbClient } from './sqb-client.js';
|
|
6
|
+
import { ConnectionOptions, QueryExecuteOptions, QueryRequest } from './types.js';
|
|
7
7
|
interface SqbConnectionEvents {
|
|
8
8
|
close: () => void;
|
|
9
9
|
execute: (request: QueryRequest) => void;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import _debug from 'debug';
|
|
3
|
+
import TaskQueue from 'putil-taskqueue';
|
|
4
|
+
import { coalesce, coerceToBoolean, coerceToInt, coerceToString } from "putil-varhelpers";
|
|
5
|
+
import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
|
|
6
|
+
import { classes } from '@sqb/builder';
|
|
7
|
+
import { EntityMetadata } from '../orm/model/entity-metadata.js';
|
|
8
|
+
import { Repository } from '../orm/repository.class.js';
|
|
9
|
+
import { Cursor } from './cursor.js';
|
|
10
|
+
import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows, wrapAdapterFields } from './helpers.js';
|
|
11
|
+
const debug = _debug('sqb:connection');
|
|
12
|
+
export class SqbConnection extends TypedEventEmitterClass(AsyncEventEmitter) {
|
|
13
|
+
client;
|
|
14
|
+
_intlcon;
|
|
15
|
+
_tasks = new TaskQueue();
|
|
16
|
+
_options;
|
|
17
|
+
_inTransaction = false;
|
|
18
|
+
_refCount = 1;
|
|
19
|
+
constructor(client, adapterConnection, options) {
|
|
20
|
+
super();
|
|
21
|
+
this.client = client;
|
|
22
|
+
this._intlcon = adapterConnection;
|
|
23
|
+
this._options = options || {};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Returns session id
|
|
27
|
+
*/
|
|
28
|
+
get sessionId() {
|
|
29
|
+
return this._intlcon && this._intlcon.sessionId;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns reference counter value
|
|
33
|
+
*/
|
|
34
|
+
get refCount() {
|
|
35
|
+
return this._refCount;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns true if transaction started
|
|
39
|
+
*/
|
|
40
|
+
get inTransaction() {
|
|
41
|
+
if (this._intlcon && typeof this._intlcon.getInTransaction === 'function') {
|
|
42
|
+
this._inTransaction = this._intlcon.getInTransaction();
|
|
43
|
+
}
|
|
44
|
+
return this._inTransaction;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Increases internal reference counter to keep session alive
|
|
48
|
+
*/
|
|
49
|
+
retain() {
|
|
50
|
+
this._refCount++;
|
|
51
|
+
debug('[%s] retain | refCount: %s', this.sessionId, this._refCount);
|
|
52
|
+
this.emit('retain', this._refCount);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Decreases the internal reference counter.
|
|
56
|
+
* When reference count is 0, connection returns to the pool.
|
|
57
|
+
* Returns true if connection released.
|
|
58
|
+
*/
|
|
59
|
+
release() {
|
|
60
|
+
if (!this._intlcon)
|
|
61
|
+
return true;
|
|
62
|
+
const ref = --this._refCount;
|
|
63
|
+
this.emit('release', this._refCount);
|
|
64
|
+
debug('[%s] release | refCount: %s', this.sessionId, ref);
|
|
65
|
+
if (!ref) {
|
|
66
|
+
this.close().catch(() => 0);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Immediately releases the connection.
|
|
73
|
+
*/
|
|
74
|
+
async close() {
|
|
75
|
+
if (!this._intlcon)
|
|
76
|
+
return;
|
|
77
|
+
await this.emitAsyncSerial('close');
|
|
78
|
+
const intlcon = this._intlcon;
|
|
79
|
+
this._intlcon = undefined;
|
|
80
|
+
this.client.pool.release(intlcon)
|
|
81
|
+
.catch(e => this.client.emit('error', e));
|
|
82
|
+
debug('[%s] closed', intlcon.sessionId);
|
|
83
|
+
}
|
|
84
|
+
async execute(query, options) {
|
|
85
|
+
if (!this._intlcon)
|
|
86
|
+
throw new Error(`Can't execute query, because connection is released`);
|
|
87
|
+
return this._tasks.enqueue(() => this._execute(query, options));
|
|
88
|
+
}
|
|
89
|
+
getRepository(entity, opts) {
|
|
90
|
+
let ctor;
|
|
91
|
+
if (typeof entity === 'string') {
|
|
92
|
+
ctor = this.client.getEntity(entity);
|
|
93
|
+
if (!ctor)
|
|
94
|
+
throw new Error(`Repository "${entity}" is not registered`);
|
|
95
|
+
}
|
|
96
|
+
else
|
|
97
|
+
ctor = entity;
|
|
98
|
+
const entityDef = EntityMetadata.get(ctor);
|
|
99
|
+
if (!entityDef)
|
|
100
|
+
throw new Error(`You must provide an @Entity annotated constructor`);
|
|
101
|
+
return new Repository(entityDef, this, opts?.schema);
|
|
102
|
+
}
|
|
103
|
+
async getSchema() {
|
|
104
|
+
assert.ok(this._intlcon, `Can't set schema, because connection is released`);
|
|
105
|
+
assert.ok(this._intlcon.getSchema, `${this.client.dialect} adapter does have Schema support`);
|
|
106
|
+
return await this._intlcon.getSchema();
|
|
107
|
+
}
|
|
108
|
+
async setSchema(schema) {
|
|
109
|
+
assert.ok(this._intlcon, `Can't set schema, because connection is released`);
|
|
110
|
+
assert.ok(this._intlcon.setSchema, `${this.client.dialect} adapter does have Schema support`);
|
|
111
|
+
await this._intlcon.setSchema(schema);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Executes a query
|
|
115
|
+
*/
|
|
116
|
+
async _execute(query, options) {
|
|
117
|
+
assert.ok(this._intlcon, `Can't execute query, because connection is released`);
|
|
118
|
+
const intlcon = this._intlcon;
|
|
119
|
+
this.retain();
|
|
120
|
+
try {
|
|
121
|
+
const startTime = Date.now();
|
|
122
|
+
const request = this._prepareQueryRequest(query, options);
|
|
123
|
+
debug('[%s] execute | %o', this.sessionId, request);
|
|
124
|
+
this.emit('execute', request);
|
|
125
|
+
// Call execute hooks
|
|
126
|
+
if (request.executeHooks) {
|
|
127
|
+
for (const fn of request.executeHooks) {
|
|
128
|
+
await fn(this, request);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const response = await intlcon.execute(request);
|
|
132
|
+
if (!response)
|
|
133
|
+
throw new Error('Database adapter returned an empty response');
|
|
134
|
+
const result = {
|
|
135
|
+
executeTime: Date.now() - startTime
|
|
136
|
+
};
|
|
137
|
+
if (request.showSql)
|
|
138
|
+
result.query = request;
|
|
139
|
+
if (response.rows || response.cursor) {
|
|
140
|
+
if (!response.fields)
|
|
141
|
+
throw new Error('Adapter did not returned fields info');
|
|
142
|
+
if (!response.rowType)
|
|
143
|
+
throw new Error('Adapter did not returned rowType');
|
|
144
|
+
result.fields = wrapAdapterFields(response.fields, request.fieldNaming);
|
|
145
|
+
result.rowType = response.rowType;
|
|
146
|
+
if (response.rows) {
|
|
147
|
+
result.rows = request.objectRows ?
|
|
148
|
+
normalizeRowsToObjectRows(result.fields, response.rowType, response.rows, request) :
|
|
149
|
+
normalizeRowsToArrayRows(result.fields, response.rowType, response.rows, request);
|
|
150
|
+
callFetchHooks(result.rows, request);
|
|
151
|
+
}
|
|
152
|
+
else if (response.cursor) {
|
|
153
|
+
const cursor = result.cursor = new Cursor(this, result.fields, response.cursor, request);
|
|
154
|
+
const hook = () => cursor.close();
|
|
155
|
+
cursor.once('close', () => this.off('close', hook));
|
|
156
|
+
this.on('close', hook);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (response.rowsAffected)
|
|
160
|
+
result.rowsAffected = response.rowsAffected;
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
this.release();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async startTransaction() {
|
|
168
|
+
if (!this._intlcon)
|
|
169
|
+
throw new Error('Can not call startTransaction() on a released connection');
|
|
170
|
+
await this._intlcon.startTransaction();
|
|
171
|
+
this._inTransaction = true;
|
|
172
|
+
this.emit('start-transaction');
|
|
173
|
+
}
|
|
174
|
+
async commit() {
|
|
175
|
+
if (!this._intlcon)
|
|
176
|
+
throw new Error('Can not call commit() on a released connection');
|
|
177
|
+
await this._intlcon.commit();
|
|
178
|
+
this._inTransaction = false;
|
|
179
|
+
this.emit('commit');
|
|
180
|
+
}
|
|
181
|
+
async rollback() {
|
|
182
|
+
if (!this._intlcon)
|
|
183
|
+
throw new Error('Can not call rollback() on a released connection');
|
|
184
|
+
await this._intlcon.rollback();
|
|
185
|
+
this._inTransaction = false;
|
|
186
|
+
this.emit('rollback');
|
|
187
|
+
}
|
|
188
|
+
async setSavepoint(savepoint) {
|
|
189
|
+
if (!this._intlcon)
|
|
190
|
+
throw new Error('Can not call setSavepoint() on a released connection');
|
|
191
|
+
if (typeof this._intlcon.setSavepoint !== 'function')
|
|
192
|
+
throw new Error(this.client.driver + ' does not support setSavepoint method');
|
|
193
|
+
if (!this.inTransaction)
|
|
194
|
+
await this.startTransaction();
|
|
195
|
+
await this._intlcon.setSavepoint(savepoint);
|
|
196
|
+
this.emit('set-savepoint');
|
|
197
|
+
}
|
|
198
|
+
async releaseSavepoint(savepoint) {
|
|
199
|
+
if (!this._intlcon)
|
|
200
|
+
throw new Error('Can not call releaseSavepoint() on a released connection');
|
|
201
|
+
if (typeof this._intlcon.releaseSavepoint !== 'function')
|
|
202
|
+
throw new Error(this.client.driver + ' does not support releaseSavepoint method');
|
|
203
|
+
await this._intlcon.releaseSavepoint(savepoint);
|
|
204
|
+
this.emit('release-savepoint');
|
|
205
|
+
}
|
|
206
|
+
async rollbackSavepoint(savepoint) {
|
|
207
|
+
if (!this._intlcon)
|
|
208
|
+
throw new Error('Can not call rollbackSavepoint() on a released connection');
|
|
209
|
+
if (typeof this._intlcon.rollbackSavepoint !== 'function')
|
|
210
|
+
throw new Error(this.client.driver + ' does not support rollbackSavepoint method');
|
|
211
|
+
await this._intlcon.rollbackSavepoint(savepoint);
|
|
212
|
+
this.emit('rollback-savepoint');
|
|
213
|
+
}
|
|
214
|
+
async test() {
|
|
215
|
+
if (!this._intlcon)
|
|
216
|
+
throw new Error('Can not call test() on a released connection');
|
|
217
|
+
await this._intlcon.test();
|
|
218
|
+
}
|
|
219
|
+
_prepareQueryRequest(query, options = {}) {
|
|
220
|
+
if (!this._intlcon)
|
|
221
|
+
throw new Error('Session released');
|
|
222
|
+
const defaults = this.client.defaults;
|
|
223
|
+
const request = {
|
|
224
|
+
dialect: this.client.dialect,
|
|
225
|
+
sql: '',
|
|
226
|
+
autoCommit: this.inTransaction ? false :
|
|
227
|
+
coerceToBoolean(coalesce(options.autoCommit, this._options?.autoCommit, defaults.autoCommit), true),
|
|
228
|
+
cursor: coerceToBoolean(coalesce(options.cursor, defaults.cursor), false),
|
|
229
|
+
objectRows: coerceToBoolean(coalesce(options.objectRows, defaults.objectRows), true),
|
|
230
|
+
ignoreNulls: coerceToBoolean(coalesce(options.ignoreNulls, defaults.ignoreNulls), false),
|
|
231
|
+
fetchRows: coerceToInt(coalesce(options.fetchRows, defaults.fetchRows), 100),
|
|
232
|
+
fieldNaming: coalesce(options.namingStrategy, defaults.fieldNaming),
|
|
233
|
+
transform: coalesce(options.transform, defaults.transform),
|
|
234
|
+
showSql: coerceToBoolean(coalesce(options.showSql, defaults.showSql), false),
|
|
235
|
+
prettyPrint: coerceToBoolean(coalesce(options.prettyPrint, defaults.prettyPrint), false),
|
|
236
|
+
action: coerceToString(options.action),
|
|
237
|
+
fetchAsString: options.fetchAsString
|
|
238
|
+
};
|
|
239
|
+
request.ignoreNulls = request.ignoreNulls && request.objectRows;
|
|
240
|
+
if (query instanceof classes.Query) {
|
|
241
|
+
if (this._intlcon.onGenerateQuery)
|
|
242
|
+
this._intlcon.onGenerateQuery(request, query);
|
|
243
|
+
const q = query
|
|
244
|
+
.generate({
|
|
245
|
+
dialect: request.dialect,
|
|
246
|
+
dialectVersion: request.dialectVersion,
|
|
247
|
+
params: options.params,
|
|
248
|
+
strictParams: true,
|
|
249
|
+
prettyPrint: request.prettyPrint
|
|
250
|
+
});
|
|
251
|
+
request.sql = q.sql;
|
|
252
|
+
request.params = q.params;
|
|
253
|
+
request.paramOptions = q.paramOptions;
|
|
254
|
+
if (q.returningFields)
|
|
255
|
+
request.returningFields = q.returningFields;
|
|
256
|
+
if (query.listenerCount('execute'))
|
|
257
|
+
request.executeHooks = query.listeners('execute');
|
|
258
|
+
if (query.listenerCount('fetch'))
|
|
259
|
+
request.fetchHooks = query.listeners('fetch');
|
|
260
|
+
}
|
|
261
|
+
else if (typeof query === 'string') {
|
|
262
|
+
request.sql = query;
|
|
263
|
+
request.params = options.params;
|
|
264
|
+
}
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
if (!request.sql)
|
|
267
|
+
throw new Error('No sql given');
|
|
268
|
+
return request;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { PoolConfiguration } from 'lightning-pool';
|
|
2
2
|
import { Maybe } from 'ts-gems';
|
|
3
3
|
import { DataType, ParamOptions } from '@sqb/builder';
|
|
4
|
-
import type { Adapter } from './
|
|
5
|
-
import type { Cursor } from './
|
|
6
|
-
import type { FieldInfoMap } from './
|
|
7
|
-
import type { SqbConnection } from './
|
|
4
|
+
import type { Adapter } from './adapter';
|
|
5
|
+
import type { Cursor } from './cursor';
|
|
6
|
+
import type { FieldInfoMap } from './field-info-map';
|
|
7
|
+
import type { SqbConnection } from './sqb-connection';
|
|
8
8
|
export { DataType } from '@sqb/builder';
|
|
9
9
|
export declare type ExecuteHookFunction = (connection: SqbConnection, request: QueryRequest) => Promise<void>;
|
|
10
10
|
export declare type FetchFunction = (row: any, request: QueryRequest) => void;
|
|
@@ -144,21 +144,13 @@ export interface QueryExecuteOptions {
|
|
|
144
144
|
export interface QueryResult {
|
|
145
145
|
executeTime: number;
|
|
146
146
|
fields?: FieldInfoMap;
|
|
147
|
-
rows?:
|
|
147
|
+
rows?: any;
|
|
148
148
|
rowType?: RowType;
|
|
149
149
|
query?: QueryRequest;
|
|
150
150
|
returns?: any;
|
|
151
151
|
rowsAffected?: number;
|
|
152
152
|
cursor?: Cursor;
|
|
153
153
|
}
|
|
154
|
-
export interface ObjectQueryResult extends QueryResult {
|
|
155
|
-
rows?: Record<string, any>[];
|
|
156
|
-
rowType?: 'object';
|
|
157
|
-
}
|
|
158
|
-
export interface ArrayQueryResult extends QueryResult {
|
|
159
|
-
rows?: any[][];
|
|
160
|
-
rowType?: 'array';
|
|
161
|
-
}
|
|
162
154
|
export declare type FieldInfo = {
|
|
163
155
|
index: number;
|
|
164
156
|
name: string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { DataType } from '@sqb/builder';
|
package/esm/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
export { Type, Maybe, DeepPartial, DeepPickWritable, DeepBuildable } from 'ts-gems';
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './client/types.js';
|
|
5
|
+
export * from './client/adapter.js';
|
|
6
|
+
export * from './client/sqb-client.js';
|
|
7
|
+
export * from './client/sqb-connection.js';
|
|
8
|
+
export * from './client/cursor.js';
|
|
9
|
+
export { registerAdapter, unRegisterAdapter } from './client/extensions.js';
|
|
10
|
+
export * from './orm/orm.type.js';
|
|
11
|
+
export * from './orm/orm.const.js';
|
|
12
|
+
export * from './orm/base-entity.js';
|
|
13
|
+
export * from './orm/repository.class.js';
|
|
14
|
+
export * from './orm/model/entity-metadata.js';
|
|
15
|
+
export * from './orm/model/field-metadata.js';
|
|
16
|
+
export * from './orm/model/column-field-metadata.js';
|
|
17
|
+
export * from './orm/model/embedded-field-metadata.js';
|
|
18
|
+
export * from './orm/model/association-field-metadata.js';
|
|
19
|
+
export * from './orm/model/association.js';
|
|
20
|
+
export * from './orm/model/association-node.js';
|
|
21
|
+
export * from './orm/model/index-metadata.js';
|
|
22
|
+
export * from './orm/model/link-chain.js';
|
|
23
|
+
export * from './orm/decorators/column.decorator.js';
|
|
24
|
+
export * from './orm/decorators/embedded.decorator.js';
|
|
25
|
+
export * from './orm/decorators/entity.decorator.js';
|
|
26
|
+
export * from './orm/decorators/events.decorator.js';
|
|
27
|
+
export * from './orm/decorators/foreignkey.decorator.js';
|
|
28
|
+
export * from './orm/decorators/index.decorator.js';
|
|
29
|
+
export * from './orm/decorators/link.decorator.js';
|
|
30
|
+
export * from './orm/decorators/primarykey.decorator.js';
|
|
31
|
+
export * from './orm/decorators/transform.decorator.js';
|
|
32
|
+
export { isColumnField, isEmbeddedField, isAssociationField, isEntityClass } from './orm/util/orm.helper.js';
|
|
33
|
+
export * from './orm/backward.js';
|
package/esm/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
export * from './client/types.js';
|
|
4
|
+
export * from './client/adapter.js';
|
|
5
|
+
export * from './client/sqb-client.js';
|
|
6
|
+
export * from './client/sqb-connection.js';
|
|
7
|
+
export * from './client/cursor.js';
|
|
8
|
+
export { registerAdapter, unRegisterAdapter } from './client/extensions.js';
|
|
9
|
+
export * from './orm/orm.type.js';
|
|
10
|
+
export * from './orm/orm.const.js';
|
|
11
|
+
export * from './orm/base-entity.js';
|
|
12
|
+
export * from './orm/repository.class.js';
|
|
13
|
+
export * from './orm/model/entity-metadata.js';
|
|
14
|
+
export * from './orm/model/field-metadata.js';
|
|
15
|
+
export * from './orm/model/column-field-metadata.js';
|
|
16
|
+
export * from './orm/model/embedded-field-metadata.js';
|
|
17
|
+
export * from './orm/model/association-field-metadata.js';
|
|
18
|
+
export * from './orm/model/association.js';
|
|
19
|
+
export * from './orm/model/association-node.js';
|
|
20
|
+
export * from './orm/model/index-metadata.js';
|
|
21
|
+
export * from './orm/model/link-chain.js';
|
|
22
|
+
export * from './orm/decorators/column.decorator.js';
|
|
23
|
+
export * from './orm/decorators/embedded.decorator.js';
|
|
24
|
+
export * from './orm/decorators/entity.decorator.js';
|
|
25
|
+
export * from './orm/decorators/events.decorator.js';
|
|
26
|
+
export * from './orm/decorators/foreignkey.decorator.js';
|
|
27
|
+
export * from './orm/decorators/index.decorator.js';
|
|
28
|
+
export * from './orm/decorators/link.decorator.js';
|
|
29
|
+
export * from './orm/decorators/primarykey.decorator.js';
|
|
30
|
+
export * from './orm/decorators/transform.decorator.js';
|
|
31
|
+
export { isColumnField, isEmbeddedField, isAssociationField, isEntityClass } from './orm/util/orm.helper.js';
|
|
32
|
+
export * from './orm/backward.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PickWritable, Type } from 'ts-gems';
|
|
2
|
-
import { Entity } from './decorators/entity.decorator';
|
|
2
|
+
import { Entity } from './decorators/entity.decorator.js';
|
|
3
3
|
export declare function getInsertColumnNames<T, K extends keyof PickWritable<T>>(ctor: Type<T>): K[];
|
|
4
4
|
export declare function getUpdateColumnNames<T, K extends keyof PickWritable<T>>(ctor: Type<T>): K[];
|
|
5
5
|
export declare function getNonAssociationElementNames<T, K extends keyof PickWritable<T>>(ctor: Type<T>): K[];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Entity } from './decorators/entity.decorator.js';
|
|
2
|
+
export function getInsertColumnNames(ctor) {
|
|
3
|
+
return Entity.getInsertColumnNames(ctor);
|
|
4
|
+
}
|
|
5
|
+
export function getUpdateColumnNames(ctor) {
|
|
6
|
+
return Entity.getUpdateColumnNames(ctor);
|
|
7
|
+
}
|
|
8
|
+
export function getNonAssociationElementNames(ctor) {
|
|
9
|
+
return Entity.getNonAssociationFieldNames(ctor);
|
|
10
|
+
}
|
|
11
|
+
export function mixinEntities(derivedCtor, ...bases) {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
return Entity.mixin(derivedCtor, ...bases);
|
|
14
|
+
}
|
|
15
|
+
export const OmitEntity = Entity.Omit;
|
|
16
|
+
export const PickEntity = Entity.Pick;
|
|
17
|
+
export const UnionEntity = Entity.Union;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Entity } from './decorators/entity.decorator.js';
|
|
2
|
+
import { REPOSITORY_KEY } from './orm.const.js';
|
|
3
|
+
export class BaseEntity {
|
|
4
|
+
[REPOSITORY_KEY];
|
|
5
|
+
constructor(partial) {
|
|
6
|
+
const fields = Entity.getColumnFieldNames(Object.getPrototypeOf(this).constructor);
|
|
7
|
+
if (fields && partial) {
|
|
8
|
+
for (const k of fields)
|
|
9
|
+
if (partial[k] !== undefined)
|
|
10
|
+
this[k] = partial[k];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async destroy() {
|
|
14
|
+
const repo = this[REPOSITORY_KEY];
|
|
15
|
+
return !!(repo && repo.destroy(this));
|
|
16
|
+
}
|
|
17
|
+
async exists() {
|
|
18
|
+
const repo = this[REPOSITORY_KEY];
|
|
19
|
+
return !!(repo && repo.exists(this));
|
|
20
|
+
}
|
|
21
|
+
toJSON() {
|
|
22
|
+
// this method is a placeholder and will be overwritten by declareEntity() method
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JoinStatement, LogicalOperator } from '@sqb/builder';
|
|
2
|
-
import { AssociationNode } from '../model/association-node';
|
|
3
|
-
import { EntityMetadata } from '../model/entity-metadata';
|
|
2
|
+
import { AssociationNode } from '../model/association-node.js';
|
|
3
|
+
import { EntityMetadata } from '../model/entity-metadata.js';
|
|
4
4
|
export interface JoinInfo {
|
|
5
5
|
association: AssociationNode;
|
|
6
6
|
sourceEntity: EntityMetadata;
|