@nattyjs/orm 0.0.1-beta.32 → 0.0.1-beta.33

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/dist/index.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const mssql = require('mssql');
4
+ const pg = require('pg');
4
5
  const common = require('@nattyjs/common');
5
6
  const core = require('@nattyjs/core');
6
7
 
@@ -17,6 +18,7 @@ function _interopNamespaceCompat(e) {
17
18
  }
18
19
 
19
20
  const mssql__namespace = /*#__PURE__*/_interopNamespaceCompat(mssql);
21
+ const pg__namespace = /*#__PURE__*/_interopNamespaceCompat(pg);
20
22
 
21
23
  var EntityState = /* @__PURE__ */ ((EntityState2) => {
22
24
  EntityState2[EntityState2["added"] = 0] = "added";
@@ -58,6 +60,12 @@ var QueryAction = /* @__PURE__ */ ((QueryAction2) => {
58
60
  return QueryAction2;
59
61
  })(QueryAction || {});
60
62
 
63
+ var DatabaseServerTechnology = /* @__PURE__ */ ((DatabaseServerTechnology2) => {
64
+ DatabaseServerTechnology2[DatabaseServerTechnology2["MSSQL"] = 0] = "MSSQL";
65
+ DatabaseServerTechnology2[DatabaseServerTechnology2["PGSQL"] = 1] = "PGSQL";
66
+ return DatabaseServerTechnology2;
67
+ })(DatabaseServerTechnology || {});
68
+
61
69
  function getComparisonOperator(operator) {
62
70
  let operatorText = "";
63
71
  switch (operator) {
@@ -87,23 +95,27 @@ function getLogicalOperator(operator) {
87
95
  function getDeleteQueryText(config) {
88
96
  const tableName = config.tableName;
89
97
  const params = new Array();
90
- const whereClause = getWhereClause$1(config.whereClause, params);
98
+ const whereClause = getWhereClause$1(config.whereClause, params, config.databaseServerTechnology);
91
99
  return {
92
100
  query: `delete from ${tableName} where ${whereClause}`,
93
101
  parameters: params
94
102
  };
95
103
  }
96
- function getWhereClause$1(whereClause, params) {
104
+ function getWhereClause$1(whereClause, params, dbTechnology) {
105
+ const isMsSql = dbTechnology == DatabaseServerTechnology.MSSQL;
106
+ let paramCharacter = isMsSql ? "@" : "$";
97
107
  let sqlQuery = "";
98
108
  const paramKeys = {};
99
109
  let increment = 1;
110
+ let index = 1;
100
111
  for (var i = 0; i < whereClause.length; i++) {
101
112
  const expression = whereClause[i];
102
113
  let paramKey = expression[0];
103
114
  if (paramKeys[paramKey])
104
115
  paramKey = `${paramKey}${increment}`;
105
116
  paramKeys[paramKey] = paramKey;
106
- sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} @${paramKey} `;
117
+ sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} ${paramCharacter}${isMsSql ? paramKey : index} `;
118
+ index++;
107
119
  params.push({
108
120
  name: paramKey,
109
121
  value: expression[2]
@@ -126,16 +138,28 @@ class Utils {
126
138
  }
127
139
 
128
140
  function getInsertQueryText(config) {
141
+ const isMsSql = DatabaseServerTechnology.MSSQL == config.databaseServerTechnology;
142
+ const isPgSql = DatabaseServerTechnology.PGSQL == config.databaseServerTechnology;
129
143
  const tableName = config.tableName;
130
144
  const queryInfo = getColumnNameAndParams$1(config);
131
145
  const columnNames = queryInfo.columnNames.join(",");
132
- const parameters = queryInfo.columnNames.map((name) => `@${name}`).join(",");
146
+ const parameters = queryInfo.columnNames.map((name, index) => {
147
+ if (isMsSql)
148
+ return `@${name}`;
149
+ else if (isPgSql)
150
+ return `$${index + 1}`;
151
+ }).join(",");
133
152
  const primaryKey = config.primaryKeys[0];
134
153
  let output = "";
135
- if (primaryKey)
136
- output = `OUTPUT INSERTED.${primaryKey}`;
154
+ let returningOutput = "";
155
+ if (primaryKey) {
156
+ if (DatabaseServerTechnology.MSSQL == config.databaseServerTechnology)
157
+ output = `OUTPUT INSERTED.${primaryKey}`;
158
+ else if (DatabaseServerTechnology.PGSQL == config.databaseServerTechnology)
159
+ returningOutput = `RETURNING ${primaryKey}`;
160
+ }
137
161
  return {
138
- query: `insert into ${tableName} (${columnNames}) ${output} values (${parameters})`,
162
+ query: `insert into ${tableName} (${columnNames}) ${output} values (${parameters}) ${returningOutput}`,
139
163
  parameters: queryInfo.params,
140
164
  relationProps: queryInfo.relationProps
141
165
  };
@@ -167,23 +191,27 @@ function getSelectQueryText(config) {
167
191
  const tableName = config.tableName;
168
192
  const columnNames = config.columns.length == 0 ? "*" : config.columns.join(",");
169
193
  const params = new Array();
170
- const whereClause = getWhereClause(config.whereClause, params);
194
+ const whereClause = getWhereClause(config.whereClause, params, config.databaseServerTechnology);
171
195
  return {
172
196
  query: `select ${columnNames} from ${tableName} ${whereClause ? `where ${whereClause}` : ""}`,
173
197
  parameters: params
174
198
  };
175
199
  }
176
- function getWhereClause(whereClause, params) {
200
+ function getWhereClause(whereClause, params, dbTechnology) {
201
+ const isMsSql = dbTechnology == DatabaseServerTechnology.MSSQL;
202
+ let paramCharacter = isMsSql ? "@" : "$";
177
203
  let sqlQuery = "";
178
204
  const paramKeys = {};
179
205
  let increment = 1;
206
+ let index = 1;
180
207
  for (var i = 0; i < whereClause.length; i++) {
181
208
  const expression = whereClause[i];
182
209
  let paramKey = expression[0];
183
210
  if (paramKeys[paramKey])
184
211
  paramKey = `${paramKey}${increment}`;
185
212
  paramKeys[paramKey] = paramKey;
186
- sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} @${paramKey} `;
213
+ sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} ${paramCharacter}${isMsSql ? paramKey : index} `;
214
+ index++;
187
215
  params.push({
188
216
  name: paramKey,
189
217
  value: expression[2]
@@ -206,16 +234,21 @@ function getUpdateQueryText(config) {
206
234
  };
207
235
  }
208
236
  function getColumnNameAndParams(config) {
237
+ const isMsSql = config.databaseServerTechnology == DatabaseServerTechnology.MSSQL;
209
238
  const sets = [];
210
239
  const whereClause = [];
211
240
  const params = new Array();
212
241
  if (config.entity) {
242
+ let index = 1;
243
+ let parameterCharacter = isMsSql ? "@" : "$";
213
244
  for (const [key, value] of Object.entries(config.entity)) {
245
+ const paramProp = isMsSql ? key : index;
214
246
  if (!(Utils.isObject(value) || Utils.isArray(value))) {
215
247
  if (config.primaryKeys.indexOf(key) === -1)
216
- sets.push(`${key}=@${key}`);
248
+ sets.push(`${key}=${parameterCharacter}${paramProp}`);
217
249
  else
218
- whereClause.push(`${key}=@${key}`);
250
+ whereClause.push(`${key}=${parameterCharacter}${paramProp}`);
251
+ index++;
219
252
  params.push({
220
253
  name: `${key}`,
221
254
  value
@@ -249,6 +282,274 @@ class DbConnection {
249
282
  constructor(config) {
250
283
  this.config = config;
251
284
  this.mssql = mssql__namespace;
285
+ this.pg = pg__namespace;
286
+ }
287
+ }
288
+
289
+ const connectionCacheContainer = new class {
290
+ constructor() {
291
+ this.connectionPoolState = {};
292
+ }
293
+ getCacheKey(config) {
294
+ return `${config.server}-${config.database}`;
295
+ }
296
+ async getConnectionPool(mssql, config) {
297
+ return await new Promise((resolve, error) => {
298
+ const cacheKey = this.getCacheKey(config);
299
+ if (this.connectionPoolState[cacheKey])
300
+ return resolve(this.connectionPoolState[cacheKey]);
301
+ const pool = new mssql.ConnectionPool(config);
302
+ this.connectionPoolState[cacheKey] = pool;
303
+ resolve(pool);
304
+ });
305
+ }
306
+ async getPgSqlConnectionPool(sql, config) {
307
+ return await new Promise((resolve, error) => {
308
+ const cacheKey = this.getCacheKey(config);
309
+ if (this.connectionPoolState[cacheKey])
310
+ return resolve(this.connectionPoolState[cacheKey]);
311
+ const pool = new sql.Pool(config);
312
+ this.connectionPoolState[cacheKey] = pool;
313
+ resolve(pool);
314
+ });
315
+ }
316
+ }();
317
+
318
+ class PgSqlDbTransaction {
319
+ constructor() {
320
+ this.transactionConnection = null;
321
+ this.isSelfTransaction = true;
322
+ this.dbContexts = null;
323
+ }
324
+ useTransaction(client) {
325
+ this.isSelfTransaction = false;
326
+ this.transactionConnection = client;
327
+ }
328
+ async begin(pool, isolationLevel, dbContexts) {
329
+ if (!this.transactionConnection) {
330
+ this.transactionConnection = await pool.connect();
331
+ this.isSelfTransaction = true;
332
+ const isoSql = this.convertToIsolationLevel(isolationLevel);
333
+ await this.transactionConnection.query(`BEGIN ${isoSql}`);
334
+ }
335
+ this.assignTransaction(dbContexts);
336
+ }
337
+ assignTransaction(dbContexts) {
338
+ if (dbContexts)
339
+ for (const dbContext of dbContexts) {
340
+ dbContext.connection.useTransaction(this.transactionConnection);
341
+ }
342
+ this.dbContexts = dbContexts;
343
+ }
344
+ async commit() {
345
+ if (this.transactionConnection && this.isSelfTransaction) {
346
+ try {
347
+ await this.transactionConnection.query("COMMIT");
348
+ } catch (err) {
349
+ throw err;
350
+ } finally {
351
+ this.transactionRelease();
352
+ this.transactionConnection.release();
353
+ this.transactionConnection = null;
354
+ }
355
+ }
356
+ }
357
+ async rollback() {
358
+ if (this.transactionConnection && this.isSelfTransaction) {
359
+ try {
360
+ await this.transactionConnection.query("ROLLBACK");
361
+ } catch (err) {
362
+ throw err;
363
+ } finally {
364
+ this.transactionRelease();
365
+ this.transactionConnection.release();
366
+ this.transactionConnection = null;
367
+ }
368
+ }
369
+ }
370
+ transactionRelease() {
371
+ if (this.dbContexts) {
372
+ for (const dbContext of this.dbContexts) {
373
+ dbContext.connection.releaseTransaction();
374
+ }
375
+ this.dbContexts = null;
376
+ }
377
+ }
378
+ releaseTransaction() {
379
+ this.transactionConnection = null;
380
+ this.isSelfTransaction = true;
381
+ }
382
+ convertToIsolationLevel(isolation) {
383
+ switch (isolation?.toUpperCase()) {
384
+ case "READ UNCOMMITTED":
385
+ return "ISOLATION LEVEL READ UNCOMMITTED";
386
+ case "REPEATABLE READ":
387
+ return "ISOLATION LEVEL REPEATABLE READ";
388
+ case "SERIALIZABLE":
389
+ return "ISOLATION LEVEL SERIALIZABLE";
390
+ case "READ COMMITTED":
391
+ default:
392
+ return "ISOLATION LEVEL READ COMMITTED";
393
+ }
394
+ }
395
+ }
396
+
397
+ class PgSqlConnection extends DbConnection {
398
+ constructor(config) {
399
+ super(config);
400
+ this.baseTransaction = new PgSqlDbTransaction();
401
+ }
402
+ get transaction() {
403
+ return this.baseTransaction;
404
+ }
405
+ useTransaction(connection) {
406
+ this.baseTransaction.useTransaction(connection);
407
+ }
408
+ useConnection(connection) {
409
+ this.connection = connection;
410
+ }
411
+ async executeQuery(query) {
412
+ try {
413
+ query.databaseServerTechnology = DatabaseServerTechnology.PGSQL;
414
+ const sqlQueryText = getSqlTextAndParams(query);
415
+ const result = await this.query(sqlQueryText);
416
+ let records = new Array();
417
+ const outputInfo = this.getOutput(result, query);
418
+ await this.runNestedObjectQueries(outputInfo, sqlQueryText.relationProps, query);
419
+ if (result["rows"]) {
420
+ records = result.rows;
421
+ }
422
+ return records;
423
+ } catch (ex) {
424
+ throw ex;
425
+ }
426
+ }
427
+ async runNestedObjectQueries(outputInfo, relationProps, config) {
428
+ if (outputInfo) {
429
+ switch (config.queryAction) {
430
+ case QueryAction.add:
431
+ for (const propName of relationProps.keys()) {
432
+ const entries = relationProps.get(propName);
433
+ const queryConfig = config.propsDbConfig.get(propName);
434
+ if (Array.isArray(entries) && queryConfig) {
435
+ for (const entity of entries) {
436
+ if (!entity[queryConfig.foreignKey])
437
+ entity[queryConfig.foreignKey] = outputInfo.value;
438
+ await this.runQuery([{ ...queryConfig, entity }], config.queryAction);
439
+ }
440
+ }
441
+ }
442
+ break;
443
+ }
444
+ }
445
+ }
446
+ async executeFunc(funcName, params) {
447
+ let records = new Array();
448
+ if (common.isObject(params)) {
449
+ const queryInfo = { parameters: [] };
450
+ let query = `select * from ${funcName}(`;
451
+ let index = 1;
452
+ for (const [key, value] of Object.entries(params)) {
453
+ query += index == 1 ? `$${index}` : `,$${index}`;
454
+ index++;
455
+ queryInfo.parameters.push({ name: key, value });
456
+ }
457
+ query += ")";
458
+ queryInfo.query = query;
459
+ const result = await this.query(queryInfo);
460
+ if (result["rows"]) {
461
+ records = result.rows;
462
+ }
463
+ return records;
464
+ }
465
+ return records;
466
+ }
467
+ async executeSp(spName, params) {
468
+ let records = new Array();
469
+ if (common.isObject(params)) {
470
+ const queryInfo = { parameters: [] };
471
+ let query = `CALL ${spName}(`;
472
+ let index = 1;
473
+ for (const [key, value] of Object.entries(params)) {
474
+ query += index == 1 ? `$${index}` : `,$${index}`;
475
+ index++;
476
+ queryInfo.parameters.push({ name: key, value });
477
+ }
478
+ query += ")";
479
+ queryInfo.query = query;
480
+ const result = await this.query(queryInfo);
481
+ if (result["rows"]) {
482
+ records = result.rows;
483
+ }
484
+ return records;
485
+ }
486
+ return records;
487
+ }
488
+ getOutput(result, config) {
489
+ switch (config.queryAction) {
490
+ case QueryAction.add:
491
+ const primaryKey = config.primaryKeys[0];
492
+ const output = result.rows[0][primaryKey];
493
+ if (output)
494
+ config.entity[primaryKey] = output;
495
+ return { key: primaryKey, value: output };
496
+ }
497
+ }
498
+ async addEntries(dbEntities) {
499
+ await this.runQuery(dbEntities, QueryAction.add);
500
+ }
501
+ async updateEntries(dbEntities) {
502
+ await this.runQuery(dbEntities, QueryAction.update);
503
+ }
504
+ async deleteEntries(dbEntities) {
505
+ await this.runQuery(dbEntities, QueryAction.delete);
506
+ }
507
+ async runQuery(dbEntities, queryAction) {
508
+ for (const dbEntity of dbEntities) {
509
+ const executeQuery = {
510
+ ...dbEntity,
511
+ queryAction
512
+ };
513
+ await this.executeQuery(executeQuery);
514
+ }
515
+ }
516
+ async query(queryInfo) {
517
+ const pool = await this.getConnectionPool();
518
+ const request = pool;
519
+ const values = queryInfo.parameters.map((t) => t.value);
520
+ const resolveQuery = (resolve, errorResolver) => (error, raw) => {
521
+ if (error)
522
+ errorResolver(error);
523
+ resolve(raw);
524
+ };
525
+ const catchFn = (ex) => {
526
+ throw ex;
527
+ };
528
+ if (queryInfo.query) {
529
+ const raw = await new Promise((resolve, error) => {
530
+ request.query(queryInfo.query, values, resolveQuery(resolve, error));
531
+ }).catch(catchFn);
532
+ return raw;
533
+ }
534
+ }
535
+ async beginTransaction(isolationLevel, dbContexts) {
536
+ const connection = await this.getConnectionPool();
537
+ await this.baseTransaction.begin(connection, isolationLevel, dbContexts);
538
+ }
539
+ async commitTransaction() {
540
+ await this.baseTransaction.commit();
541
+ }
542
+ async rollbackTransaction() {
543
+ await this.baseTransaction.rollback();
544
+ }
545
+ releaseTransaction() {
546
+ this.baseTransaction.releaseTransaction();
547
+ }
548
+ async getConnectionPool() {
549
+ return this.createPool();
550
+ }
551
+ async createPool() {
552
+ return await connectionCacheContainer.getPgSqlConnectionPool(this.pg, this.config);
252
553
  }
253
554
  }
254
555
 
@@ -344,32 +645,6 @@ class SqlDbTransaction {
344
645
  }
345
646
  }
346
647
 
347
- const connectionCacheContainer = new class {
348
- constructor() {
349
- this.connectionPoolState = {};
350
- }
351
- getCacheKey(config) {
352
- return `${config.server}-${config.database}`;
353
- }
354
- async getConnectionPool(mssql, config) {
355
- return await new Promise((resolve, error) => {
356
- const cacheKey = this.getCacheKey(config);
357
- if (this.connectionPoolState[cacheKey])
358
- return resolve(this.connectionPoolState[cacheKey]);
359
- const pool = new mssql.ConnectionPool(config);
360
- const errorHandler = (error2) => {
361
- };
362
- pool.on("error", errorHandler);
363
- const connection = pool.connect((err) => {
364
- if (err)
365
- return error(err);
366
- this.connectionPoolState[cacheKey] = connection;
367
- resolve(connection);
368
- });
369
- });
370
- }
371
- }();
372
-
373
648
  class SqlConnection extends DbConnection {
374
649
  constructor(config) {
375
650
  super(config);
@@ -386,6 +661,7 @@ class SqlConnection extends DbConnection {
386
661
  }
387
662
  async executeQuery(query) {
388
663
  try {
664
+ query.databaseServerTechnology = DatabaseServerTechnology.MSSQL;
389
665
  const sqlQueryText = getSqlTextAndParams(query);
390
666
  const result = await this.query(sqlQueryText);
391
667
  let records = new Array();
@@ -418,6 +694,27 @@ class SqlConnection extends DbConnection {
418
694
  }
419
695
  }
420
696
  }
697
+ async executeFunc(funcName, params) {
698
+ let records = new Array();
699
+ if (common.isObject(params)) {
700
+ const queryInfo = { parameters: [] };
701
+ let query = `select * from ${funcName}(`;
702
+ let index = 1;
703
+ for (const [key, value] of Object.entries(params)) {
704
+ query += index == 1 ? `@${key}` : `,@${key}`;
705
+ index++;
706
+ queryInfo.parameters.push({ name: key, value });
707
+ }
708
+ query += ")";
709
+ queryInfo.query = query;
710
+ const result = await this.query(queryInfo);
711
+ if (result["recordset"]) {
712
+ records = result.recordset;
713
+ }
714
+ return records;
715
+ }
716
+ return records;
717
+ }
421
718
  async executeSp(spName, params) {
422
719
  let records = new Array();
423
720
  if (common.isObject(params)) {
@@ -515,6 +812,9 @@ class DbConnectionContext {
515
812
  useSqlServer(options) {
516
813
  this.connection = new SqlConnection(options);
517
814
  }
815
+ usePgSqlServer(options) {
816
+ this.connection = new PgSqlConnection(options);
817
+ }
518
818
  }
519
819
 
520
820
  class DbSet {
@@ -621,6 +921,25 @@ class StoreProc {
621
921
  }
622
922
  }
623
923
 
924
+ class DbFunc {
925
+ constructor(funcName, type, queryConnection) {
926
+ this.funcName = funcName;
927
+ this.type = type;
928
+ this.queryConnection = queryConnection;
929
+ }
930
+ async execute(params) {
931
+ const items = await this.queryConnection.executeFunc(this.funcName, params);
932
+ return new common.List(items, this.type, this.properties);
933
+ }
934
+ get properties() {
935
+ const props = core.entityContainer.getProperties(this.type.name);
936
+ const jProps = {};
937
+ if (props)
938
+ props.forEach((property) => jProps[property.name.toLowerCase()] = property.name);
939
+ return jProps;
940
+ }
941
+ }
942
+
624
943
  class DbContext {
625
944
  get connection() {
626
945
  return this.dbConnectionInfo.connection;
@@ -648,6 +967,11 @@ class DbContext {
648
967
  for (const [key, value] of Object.entries(sps))
649
968
  this[key] = new StoreProc(value.spName, value.model(), this.queryConnection);
650
969
  }
970
+ onDbFuncRegistering(funcs) {
971
+ if (funcs)
972
+ for (const [key, value] of Object.entries(funcs))
973
+ this[key] = new DbFunc(value.funcName, value.model(), this.queryConnection);
974
+ }
651
975
  async saveChanges() {
652
976
  return new Promise(async (resolve, error) => {
653
977
  try {
@@ -669,5 +993,6 @@ class DbContext {
669
993
 
670
994
  exports.DbConnectionContext = DbConnectionContext;
671
995
  exports.DbContext = DbContext;
996
+ exports.DbFunc = DbFunc;
672
997
  exports.DbSet = DbSet;
673
998
  exports.StoreProc = StoreProc;
package/dist/index.d.ts CHANGED
@@ -46,6 +46,7 @@ declare class ChangeTracker {
46
46
  declare class DbConnectionContext {
47
47
  connection: any;
48
48
  useSqlServer(options: any): void;
49
+ usePgSqlServer(options: any): void;
49
50
  }
50
51
 
51
52
  declare abstract class DbContext implements IDbContext {
@@ -64,12 +65,23 @@ declare abstract class DbContext implements IDbContext {
64
65
  spName: string;
65
66
  };
66
67
  }): void;
68
+ protected onDbFuncRegistering(funcs?: {
69
+ [key: string]: {
70
+ model: () => ClassType<any>;
71
+ funcName: string;
72
+ };
73
+ }): void;
67
74
  protected abstract onConfiguring(connectionContext: DbConnectionContext): void;
68
75
  saveChanges(): Promise<unknown>;
69
76
  }
70
77
 
71
78
  type FilterExpression<T> = (t: T) => boolean;
72
79
 
80
+ declare enum DatabaseServerTechnology {
81
+ MSSQL = 0,
82
+ PGSQL = 1
83
+ }
84
+
73
85
  declare enum QueryAction {
74
86
  select = 0,
75
87
  add = 1,
@@ -81,6 +93,7 @@ interface ExecuteQueryConfig extends DbEntityInfo {
81
93
  columns?: string[];
82
94
  whereClause?: any;
83
95
  queryAction?: QueryAction;
96
+ databaseServerTechnology?: DatabaseServerTechnology;
84
97
  }
85
98
 
86
99
  interface DataQueryConnection extends IDbConnection {
@@ -88,6 +101,9 @@ interface DataQueryConnection extends IDbConnection {
88
101
  executeSp(spName: string, params: {
89
102
  [key: string]: any;
90
103
  }): any;
104
+ executeFunc(funcName: string, params: {
105
+ [key: string]: any;
106
+ }): any;
91
107
  }
92
108
 
93
109
  declare class DbSet<T> {
@@ -119,4 +135,13 @@ declare class StoreProc<SpName, Entity, SpParamterModel> {
119
135
  private get properties();
120
136
  }
121
137
 
122
- export { DbConnectionContext, DbContext, DbSet, StoreProc };
138
+ declare class DbFunc<FuncName, Entity, FuncParamterModel> {
139
+ private funcName;
140
+ private type;
141
+ private queryConnection;
142
+ constructor(funcName: string, type: ClassType<Entity>, queryConnection: DataQueryConnection);
143
+ execute(params: FuncParamterModel): Promise<List<Entity>>;
144
+ private get properties();
145
+ }
146
+
147
+ export { DbConnectionContext, DbContext, DbFunc, DbSet, StoreProc };
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as mssql from 'mssql';
2
+ import * as pg from 'pg';
2
3
  import { isObject, List } from '@nattyjs/common';
3
4
  import { entityContainer } from '@nattyjs/core';
4
5
 
@@ -42,6 +43,12 @@ var QueryAction = /* @__PURE__ */ ((QueryAction2) => {
42
43
  return QueryAction2;
43
44
  })(QueryAction || {});
44
45
 
46
+ var DatabaseServerTechnology = /* @__PURE__ */ ((DatabaseServerTechnology2) => {
47
+ DatabaseServerTechnology2[DatabaseServerTechnology2["MSSQL"] = 0] = "MSSQL";
48
+ DatabaseServerTechnology2[DatabaseServerTechnology2["PGSQL"] = 1] = "PGSQL";
49
+ return DatabaseServerTechnology2;
50
+ })(DatabaseServerTechnology || {});
51
+
45
52
  function getComparisonOperator(operator) {
46
53
  let operatorText = "";
47
54
  switch (operator) {
@@ -71,23 +78,27 @@ function getLogicalOperator(operator) {
71
78
  function getDeleteQueryText(config) {
72
79
  const tableName = config.tableName;
73
80
  const params = new Array();
74
- const whereClause = getWhereClause$1(config.whereClause, params);
81
+ const whereClause = getWhereClause$1(config.whereClause, params, config.databaseServerTechnology);
75
82
  return {
76
83
  query: `delete from ${tableName} where ${whereClause}`,
77
84
  parameters: params
78
85
  };
79
86
  }
80
- function getWhereClause$1(whereClause, params) {
87
+ function getWhereClause$1(whereClause, params, dbTechnology) {
88
+ const isMsSql = dbTechnology == DatabaseServerTechnology.MSSQL;
89
+ let paramCharacter = isMsSql ? "@" : "$";
81
90
  let sqlQuery = "";
82
91
  const paramKeys = {};
83
92
  let increment = 1;
93
+ let index = 1;
84
94
  for (var i = 0; i < whereClause.length; i++) {
85
95
  const expression = whereClause[i];
86
96
  let paramKey = expression[0];
87
97
  if (paramKeys[paramKey])
88
98
  paramKey = `${paramKey}${increment}`;
89
99
  paramKeys[paramKey] = paramKey;
90
- sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} @${paramKey} `;
100
+ sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} ${paramCharacter}${isMsSql ? paramKey : index} `;
101
+ index++;
91
102
  params.push({
92
103
  name: paramKey,
93
104
  value: expression[2]
@@ -110,16 +121,28 @@ class Utils {
110
121
  }
111
122
 
112
123
  function getInsertQueryText(config) {
124
+ const isMsSql = DatabaseServerTechnology.MSSQL == config.databaseServerTechnology;
125
+ const isPgSql = DatabaseServerTechnology.PGSQL == config.databaseServerTechnology;
113
126
  const tableName = config.tableName;
114
127
  const queryInfo = getColumnNameAndParams$1(config);
115
128
  const columnNames = queryInfo.columnNames.join(",");
116
- const parameters = queryInfo.columnNames.map((name) => `@${name}`).join(",");
129
+ const parameters = queryInfo.columnNames.map((name, index) => {
130
+ if (isMsSql)
131
+ return `@${name}`;
132
+ else if (isPgSql)
133
+ return `$${index + 1}`;
134
+ }).join(",");
117
135
  const primaryKey = config.primaryKeys[0];
118
136
  let output = "";
119
- if (primaryKey)
120
- output = `OUTPUT INSERTED.${primaryKey}`;
137
+ let returningOutput = "";
138
+ if (primaryKey) {
139
+ if (DatabaseServerTechnology.MSSQL == config.databaseServerTechnology)
140
+ output = `OUTPUT INSERTED.${primaryKey}`;
141
+ else if (DatabaseServerTechnology.PGSQL == config.databaseServerTechnology)
142
+ returningOutput = `RETURNING ${primaryKey}`;
143
+ }
121
144
  return {
122
- query: `insert into ${tableName} (${columnNames}) ${output} values (${parameters})`,
145
+ query: `insert into ${tableName} (${columnNames}) ${output} values (${parameters}) ${returningOutput}`,
123
146
  parameters: queryInfo.params,
124
147
  relationProps: queryInfo.relationProps
125
148
  };
@@ -151,23 +174,27 @@ function getSelectQueryText(config) {
151
174
  const tableName = config.tableName;
152
175
  const columnNames = config.columns.length == 0 ? "*" : config.columns.join(",");
153
176
  const params = new Array();
154
- const whereClause = getWhereClause(config.whereClause, params);
177
+ const whereClause = getWhereClause(config.whereClause, params, config.databaseServerTechnology);
155
178
  return {
156
179
  query: `select ${columnNames} from ${tableName} ${whereClause ? `where ${whereClause}` : ""}`,
157
180
  parameters: params
158
181
  };
159
182
  }
160
- function getWhereClause(whereClause, params) {
183
+ function getWhereClause(whereClause, params, dbTechnology) {
184
+ const isMsSql = dbTechnology == DatabaseServerTechnology.MSSQL;
185
+ let paramCharacter = isMsSql ? "@" : "$";
161
186
  let sqlQuery = "";
162
187
  const paramKeys = {};
163
188
  let increment = 1;
189
+ let index = 1;
164
190
  for (var i = 0; i < whereClause.length; i++) {
165
191
  const expression = whereClause[i];
166
192
  let paramKey = expression[0];
167
193
  if (paramKeys[paramKey])
168
194
  paramKey = `${paramKey}${increment}`;
169
195
  paramKeys[paramKey] = paramKey;
170
- sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} @${paramKey} `;
196
+ sqlQuery += `${expression[0]} ${getComparisonOperator(expression[1])} ${paramCharacter}${isMsSql ? paramKey : index} `;
197
+ index++;
171
198
  params.push({
172
199
  name: paramKey,
173
200
  value: expression[2]
@@ -190,16 +217,21 @@ function getUpdateQueryText(config) {
190
217
  };
191
218
  }
192
219
  function getColumnNameAndParams(config) {
220
+ const isMsSql = config.databaseServerTechnology == DatabaseServerTechnology.MSSQL;
193
221
  const sets = [];
194
222
  const whereClause = [];
195
223
  const params = new Array();
196
224
  if (config.entity) {
225
+ let index = 1;
226
+ let parameterCharacter = isMsSql ? "@" : "$";
197
227
  for (const [key, value] of Object.entries(config.entity)) {
228
+ const paramProp = isMsSql ? key : index;
198
229
  if (!(Utils.isObject(value) || Utils.isArray(value))) {
199
230
  if (config.primaryKeys.indexOf(key) === -1)
200
- sets.push(`${key}=@${key}`);
231
+ sets.push(`${key}=${parameterCharacter}${paramProp}`);
201
232
  else
202
- whereClause.push(`${key}=@${key}`);
233
+ whereClause.push(`${key}=${parameterCharacter}${paramProp}`);
234
+ index++;
203
235
  params.push({
204
236
  name: `${key}`,
205
237
  value
@@ -233,6 +265,274 @@ class DbConnection {
233
265
  constructor(config) {
234
266
  this.config = config;
235
267
  this.mssql = mssql;
268
+ this.pg = pg;
269
+ }
270
+ }
271
+
272
+ const connectionCacheContainer = new class {
273
+ constructor() {
274
+ this.connectionPoolState = {};
275
+ }
276
+ getCacheKey(config) {
277
+ return `${config.server}-${config.database}`;
278
+ }
279
+ async getConnectionPool(mssql, config) {
280
+ return await new Promise((resolve, error) => {
281
+ const cacheKey = this.getCacheKey(config);
282
+ if (this.connectionPoolState[cacheKey])
283
+ return resolve(this.connectionPoolState[cacheKey]);
284
+ const pool = new mssql.ConnectionPool(config);
285
+ this.connectionPoolState[cacheKey] = pool;
286
+ resolve(pool);
287
+ });
288
+ }
289
+ async getPgSqlConnectionPool(sql, config) {
290
+ return await new Promise((resolve, error) => {
291
+ const cacheKey = this.getCacheKey(config);
292
+ if (this.connectionPoolState[cacheKey])
293
+ return resolve(this.connectionPoolState[cacheKey]);
294
+ const pool = new sql.Pool(config);
295
+ this.connectionPoolState[cacheKey] = pool;
296
+ resolve(pool);
297
+ });
298
+ }
299
+ }();
300
+
301
+ class PgSqlDbTransaction {
302
+ constructor() {
303
+ this.transactionConnection = null;
304
+ this.isSelfTransaction = true;
305
+ this.dbContexts = null;
306
+ }
307
+ useTransaction(client) {
308
+ this.isSelfTransaction = false;
309
+ this.transactionConnection = client;
310
+ }
311
+ async begin(pool, isolationLevel, dbContexts) {
312
+ if (!this.transactionConnection) {
313
+ this.transactionConnection = await pool.connect();
314
+ this.isSelfTransaction = true;
315
+ const isoSql = this.convertToIsolationLevel(isolationLevel);
316
+ await this.transactionConnection.query(`BEGIN ${isoSql}`);
317
+ }
318
+ this.assignTransaction(dbContexts);
319
+ }
320
+ assignTransaction(dbContexts) {
321
+ if (dbContexts)
322
+ for (const dbContext of dbContexts) {
323
+ dbContext.connection.useTransaction(this.transactionConnection);
324
+ }
325
+ this.dbContexts = dbContexts;
326
+ }
327
+ async commit() {
328
+ if (this.transactionConnection && this.isSelfTransaction) {
329
+ try {
330
+ await this.transactionConnection.query("COMMIT");
331
+ } catch (err) {
332
+ throw err;
333
+ } finally {
334
+ this.transactionRelease();
335
+ this.transactionConnection.release();
336
+ this.transactionConnection = null;
337
+ }
338
+ }
339
+ }
340
+ async rollback() {
341
+ if (this.transactionConnection && this.isSelfTransaction) {
342
+ try {
343
+ await this.transactionConnection.query("ROLLBACK");
344
+ } catch (err) {
345
+ throw err;
346
+ } finally {
347
+ this.transactionRelease();
348
+ this.transactionConnection.release();
349
+ this.transactionConnection = null;
350
+ }
351
+ }
352
+ }
353
+ transactionRelease() {
354
+ if (this.dbContexts) {
355
+ for (const dbContext of this.dbContexts) {
356
+ dbContext.connection.releaseTransaction();
357
+ }
358
+ this.dbContexts = null;
359
+ }
360
+ }
361
+ releaseTransaction() {
362
+ this.transactionConnection = null;
363
+ this.isSelfTransaction = true;
364
+ }
365
+ convertToIsolationLevel(isolation) {
366
+ switch (isolation?.toUpperCase()) {
367
+ case "READ UNCOMMITTED":
368
+ return "ISOLATION LEVEL READ UNCOMMITTED";
369
+ case "REPEATABLE READ":
370
+ return "ISOLATION LEVEL REPEATABLE READ";
371
+ case "SERIALIZABLE":
372
+ return "ISOLATION LEVEL SERIALIZABLE";
373
+ case "READ COMMITTED":
374
+ default:
375
+ return "ISOLATION LEVEL READ COMMITTED";
376
+ }
377
+ }
378
+ }
379
+
380
+ class PgSqlConnection extends DbConnection {
381
+ constructor(config) {
382
+ super(config);
383
+ this.baseTransaction = new PgSqlDbTransaction();
384
+ }
385
+ get transaction() {
386
+ return this.baseTransaction;
387
+ }
388
+ useTransaction(connection) {
389
+ this.baseTransaction.useTransaction(connection);
390
+ }
391
+ useConnection(connection) {
392
+ this.connection = connection;
393
+ }
394
+ async executeQuery(query) {
395
+ try {
396
+ query.databaseServerTechnology = DatabaseServerTechnology.PGSQL;
397
+ const sqlQueryText = getSqlTextAndParams(query);
398
+ const result = await this.query(sqlQueryText);
399
+ let records = new Array();
400
+ const outputInfo = this.getOutput(result, query);
401
+ await this.runNestedObjectQueries(outputInfo, sqlQueryText.relationProps, query);
402
+ if (result["rows"]) {
403
+ records = result.rows;
404
+ }
405
+ return records;
406
+ } catch (ex) {
407
+ throw ex;
408
+ }
409
+ }
410
+ async runNestedObjectQueries(outputInfo, relationProps, config) {
411
+ if (outputInfo) {
412
+ switch (config.queryAction) {
413
+ case QueryAction.add:
414
+ for (const propName of relationProps.keys()) {
415
+ const entries = relationProps.get(propName);
416
+ const queryConfig = config.propsDbConfig.get(propName);
417
+ if (Array.isArray(entries) && queryConfig) {
418
+ for (const entity of entries) {
419
+ if (!entity[queryConfig.foreignKey])
420
+ entity[queryConfig.foreignKey] = outputInfo.value;
421
+ await this.runQuery([{ ...queryConfig, entity }], config.queryAction);
422
+ }
423
+ }
424
+ }
425
+ break;
426
+ }
427
+ }
428
+ }
429
+ async executeFunc(funcName, params) {
430
+ let records = new Array();
431
+ if (isObject(params)) {
432
+ const queryInfo = { parameters: [] };
433
+ let query = `select * from ${funcName}(`;
434
+ let index = 1;
435
+ for (const [key, value] of Object.entries(params)) {
436
+ query += index == 1 ? `$${index}` : `,$${index}`;
437
+ index++;
438
+ queryInfo.parameters.push({ name: key, value });
439
+ }
440
+ query += ")";
441
+ queryInfo.query = query;
442
+ const result = await this.query(queryInfo);
443
+ if (result["rows"]) {
444
+ records = result.rows;
445
+ }
446
+ return records;
447
+ }
448
+ return records;
449
+ }
450
+ async executeSp(spName, params) {
451
+ let records = new Array();
452
+ if (isObject(params)) {
453
+ const queryInfo = { parameters: [] };
454
+ let query = `CALL ${spName}(`;
455
+ let index = 1;
456
+ for (const [key, value] of Object.entries(params)) {
457
+ query += index == 1 ? `$${index}` : `,$${index}`;
458
+ index++;
459
+ queryInfo.parameters.push({ name: key, value });
460
+ }
461
+ query += ")";
462
+ queryInfo.query = query;
463
+ const result = await this.query(queryInfo);
464
+ if (result["rows"]) {
465
+ records = result.rows;
466
+ }
467
+ return records;
468
+ }
469
+ return records;
470
+ }
471
+ getOutput(result, config) {
472
+ switch (config.queryAction) {
473
+ case QueryAction.add:
474
+ const primaryKey = config.primaryKeys[0];
475
+ const output = result.rows[0][primaryKey];
476
+ if (output)
477
+ config.entity[primaryKey] = output;
478
+ return { key: primaryKey, value: output };
479
+ }
480
+ }
481
+ async addEntries(dbEntities) {
482
+ await this.runQuery(dbEntities, QueryAction.add);
483
+ }
484
+ async updateEntries(dbEntities) {
485
+ await this.runQuery(dbEntities, QueryAction.update);
486
+ }
487
+ async deleteEntries(dbEntities) {
488
+ await this.runQuery(dbEntities, QueryAction.delete);
489
+ }
490
+ async runQuery(dbEntities, queryAction) {
491
+ for (const dbEntity of dbEntities) {
492
+ const executeQuery = {
493
+ ...dbEntity,
494
+ queryAction
495
+ };
496
+ await this.executeQuery(executeQuery);
497
+ }
498
+ }
499
+ async query(queryInfo) {
500
+ const pool = await this.getConnectionPool();
501
+ const request = pool;
502
+ const values = queryInfo.parameters.map((t) => t.value);
503
+ const resolveQuery = (resolve, errorResolver) => (error, raw) => {
504
+ if (error)
505
+ errorResolver(error);
506
+ resolve(raw);
507
+ };
508
+ const catchFn = (ex) => {
509
+ throw ex;
510
+ };
511
+ if (queryInfo.query) {
512
+ const raw = await new Promise((resolve, error) => {
513
+ request.query(queryInfo.query, values, resolveQuery(resolve, error));
514
+ }).catch(catchFn);
515
+ return raw;
516
+ }
517
+ }
518
+ async beginTransaction(isolationLevel, dbContexts) {
519
+ const connection = await this.getConnectionPool();
520
+ await this.baseTransaction.begin(connection, isolationLevel, dbContexts);
521
+ }
522
+ async commitTransaction() {
523
+ await this.baseTransaction.commit();
524
+ }
525
+ async rollbackTransaction() {
526
+ await this.baseTransaction.rollback();
527
+ }
528
+ releaseTransaction() {
529
+ this.baseTransaction.releaseTransaction();
530
+ }
531
+ async getConnectionPool() {
532
+ return this.createPool();
533
+ }
534
+ async createPool() {
535
+ return await connectionCacheContainer.getPgSqlConnectionPool(this.pg, this.config);
236
536
  }
237
537
  }
238
538
 
@@ -328,32 +628,6 @@ class SqlDbTransaction {
328
628
  }
329
629
  }
330
630
 
331
- const connectionCacheContainer = new class {
332
- constructor() {
333
- this.connectionPoolState = {};
334
- }
335
- getCacheKey(config) {
336
- return `${config.server}-${config.database}`;
337
- }
338
- async getConnectionPool(mssql, config) {
339
- return await new Promise((resolve, error) => {
340
- const cacheKey = this.getCacheKey(config);
341
- if (this.connectionPoolState[cacheKey])
342
- return resolve(this.connectionPoolState[cacheKey]);
343
- const pool = new mssql.ConnectionPool(config);
344
- const errorHandler = (error2) => {
345
- };
346
- pool.on("error", errorHandler);
347
- const connection = pool.connect((err) => {
348
- if (err)
349
- return error(err);
350
- this.connectionPoolState[cacheKey] = connection;
351
- resolve(connection);
352
- });
353
- });
354
- }
355
- }();
356
-
357
631
  class SqlConnection extends DbConnection {
358
632
  constructor(config) {
359
633
  super(config);
@@ -370,6 +644,7 @@ class SqlConnection extends DbConnection {
370
644
  }
371
645
  async executeQuery(query) {
372
646
  try {
647
+ query.databaseServerTechnology = DatabaseServerTechnology.MSSQL;
373
648
  const sqlQueryText = getSqlTextAndParams(query);
374
649
  const result = await this.query(sqlQueryText);
375
650
  let records = new Array();
@@ -402,6 +677,27 @@ class SqlConnection extends DbConnection {
402
677
  }
403
678
  }
404
679
  }
680
+ async executeFunc(funcName, params) {
681
+ let records = new Array();
682
+ if (isObject(params)) {
683
+ const queryInfo = { parameters: [] };
684
+ let query = `select * from ${funcName}(`;
685
+ let index = 1;
686
+ for (const [key, value] of Object.entries(params)) {
687
+ query += index == 1 ? `@${key}` : `,@${key}`;
688
+ index++;
689
+ queryInfo.parameters.push({ name: key, value });
690
+ }
691
+ query += ")";
692
+ queryInfo.query = query;
693
+ const result = await this.query(queryInfo);
694
+ if (result["recordset"]) {
695
+ records = result.recordset;
696
+ }
697
+ return records;
698
+ }
699
+ return records;
700
+ }
405
701
  async executeSp(spName, params) {
406
702
  let records = new Array();
407
703
  if (isObject(params)) {
@@ -499,6 +795,9 @@ class DbConnectionContext {
499
795
  useSqlServer(options) {
500
796
  this.connection = new SqlConnection(options);
501
797
  }
798
+ usePgSqlServer(options) {
799
+ this.connection = new PgSqlConnection(options);
800
+ }
502
801
  }
503
802
 
504
803
  class DbSet {
@@ -605,6 +904,25 @@ class StoreProc {
605
904
  }
606
905
  }
607
906
 
907
+ class DbFunc {
908
+ constructor(funcName, type, queryConnection) {
909
+ this.funcName = funcName;
910
+ this.type = type;
911
+ this.queryConnection = queryConnection;
912
+ }
913
+ async execute(params) {
914
+ const items = await this.queryConnection.executeFunc(this.funcName, params);
915
+ return new List(items, this.type, this.properties);
916
+ }
917
+ get properties() {
918
+ const props = entityContainer.getProperties(this.type.name);
919
+ const jProps = {};
920
+ if (props)
921
+ props.forEach((property) => jProps[property.name.toLowerCase()] = property.name);
922
+ return jProps;
923
+ }
924
+ }
925
+
608
926
  class DbContext {
609
927
  get connection() {
610
928
  return this.dbConnectionInfo.connection;
@@ -632,6 +950,11 @@ class DbContext {
632
950
  for (const [key, value] of Object.entries(sps))
633
951
  this[key] = new StoreProc(value.spName, value.model(), this.queryConnection);
634
952
  }
953
+ onDbFuncRegistering(funcs) {
954
+ if (funcs)
955
+ for (const [key, value] of Object.entries(funcs))
956
+ this[key] = new DbFunc(value.funcName, value.model(), this.queryConnection);
957
+ }
635
958
  async saveChanges() {
636
959
  return new Promise(async (resolve, error) => {
637
960
  try {
@@ -651,4 +974,4 @@ class DbContext {
651
974
  }
652
975
  }
653
976
 
654
- export { DbConnectionContext, DbContext, DbSet, StoreProc };
977
+ export { DbConnectionContext, DbContext, DbFunc, DbSet, StoreProc };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nattyjs/orm",
3
- "version": "0.0.1-beta.32",
3
+ "version": "0.0.1-beta.33",
4
4
  "description": "",
5
5
  "module": "./dist/index.mjs",
6
6
  "main": "./dist/index.cjs",
@@ -17,10 +17,11 @@
17
17
  "unbuild": "1.2.1"
18
18
  },
19
19
  "dependencies": {
20
+ "pg": "8.16.0",
20
21
  "mssql": "^9.1.1",
21
- "@nattyjs/core": "0.0.1-beta.32",
22
- "@nattyjs/common": "0.0.1-beta.32",
23
- "@nattyjs/entity": "0.0.1-beta.32",
24
- "@nattyjs/types": "0.0.1-beta.32"
22
+ "@nattyjs/core": "0.0.1-beta.33",
23
+ "@nattyjs/common": "0.0.1-beta.33",
24
+ "@nattyjs/entity": "0.0.1-beta.33",
25
+ "@nattyjs/types": "0.0.1-beta.33"
25
26
  }
26
27
  }