pg-query-sdk 1.0.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 +553 -0
- package/dist/cjs/builders/ConditionBuilder.d.ts +11 -0
- package/dist/cjs/builders/ConditionBuilder.js +43 -0
- package/dist/cjs/builders/QueryBuilder.d.ts +31 -0
- package/dist/cjs/builders/QueryBuilder.js +88 -0
- package/dist/cjs/core/Database.d.ts +20 -0
- package/dist/cjs/core/Database.js +39 -0
- package/dist/cjs/core/ParamContext.d.ts +8 -0
- package/dist/cjs/core/ParamContext.js +16 -0
- package/dist/cjs/core/QueryExecutor.d.ts +14 -0
- package/dist/cjs/core/QueryExecutor.js +39 -0
- package/dist/cjs/core/TransactionManager.d.ts +6 -0
- package/dist/cjs/core/TransactionManager.js +24 -0
- package/dist/cjs/core/UnitOfWork.d.ts +10 -0
- package/dist/cjs/core/UnitOfWork.js +27 -0
- package/dist/cjs/dialects/Dialect.d.ts +4 -0
- package/dist/cjs/dialects/Dialect.js +2 -0
- package/dist/cjs/dialects/MysqlDialect.d.ts +5 -0
- package/dist/cjs/dialects/MysqlDialect.js +11 -0
- package/dist/cjs/dialects/PostgresDialect.d.ts +5 -0
- package/dist/cjs/dialects/PostgresDialect.js +11 -0
- package/dist/cjs/index.d.ts +7 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/orm/EntityManager.d.ts +0 -0
- package/dist/cjs/orm/EntityManager.js +1 -0
- package/dist/cjs/orm/Repository.d.ts +13 -0
- package/dist/cjs/orm/Repository.js +30 -0
- package/dist/cjs/query/ConditionBuilder.d.ts +11 -0
- package/dist/cjs/query/ConditionBuilder.js +67 -0
- package/dist/cjs/query/QueryBuilder.d.ts +43 -0
- package/dist/cjs/query/QueryBuilder.js +152 -0
- package/dist/esm/builders/ConditionBuilder.d.ts +11 -0
- package/dist/esm/builders/ConditionBuilder.js +40 -0
- package/dist/esm/builders/QueryBuilder.d.ts +31 -0
- package/dist/esm/builders/QueryBuilder.js +82 -0
- package/dist/esm/core/Database.d.ts +20 -0
- package/dist/esm/core/Database.js +33 -0
- package/dist/esm/core/ParamContext.d.ts +8 -0
- package/dist/esm/core/ParamContext.js +13 -0
- package/dist/esm/core/QueryExecutor.d.ts +14 -0
- package/dist/esm/core/QueryExecutor.js +36 -0
- package/dist/esm/core/TransactionManager.d.ts +6 -0
- package/dist/esm/core/TransactionManager.js +21 -0
- package/dist/esm/core/UnitOfWork.d.ts +10 -0
- package/dist/esm/core/UnitOfWork.js +24 -0
- package/dist/esm/dialects/Dialect.d.ts +4 -0
- package/dist/esm/dialects/Dialect.js +1 -0
- package/dist/esm/dialects/MysqlDialect.d.ts +5 -0
- package/dist/esm/dialects/MysqlDialect.js +8 -0
- package/dist/esm/dialects/PostgresDialect.d.ts +5 -0
- package/dist/esm/dialects/PostgresDialect.js +8 -0
- package/dist/esm/index.d.ts +7 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/orm/EntityManager.d.ts +0 -0
- package/dist/esm/orm/EntityManager.js +1 -0
- package/dist/esm/orm/Repository.d.ts +13 -0
- package/dist/esm/orm/Repository.js +27 -0
- package/dist/esm/query/ConditionBuilder.d.ts +11 -0
- package/dist/esm/query/ConditionBuilder.js +64 -0
- package/dist/esm/query/QueryBuilder.d.ts +43 -0
- package/dist/esm/query/QueryBuilder.js +146 -0
- package/package.json +45 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ParamContext_1 = __importDefault(require("../core/ParamContext"));
|
|
7
|
+
const ConditionBuilder_1 = __importDefault(require("./ConditionBuilder"));
|
|
8
|
+
class QueryBuilder {
|
|
9
|
+
constructor(table, executor, dialect, cacheTTL) {
|
|
10
|
+
this.executor = executor;
|
|
11
|
+
this.dialect = dialect;
|
|
12
|
+
this.cacheTTL = cacheTTL;
|
|
13
|
+
this.fields = [];
|
|
14
|
+
this.joins = [];
|
|
15
|
+
this.groupByFields = [];
|
|
16
|
+
this.orderByFields = [];
|
|
17
|
+
this.ctes = [];
|
|
18
|
+
this.fromClause = table;
|
|
19
|
+
this.ctx = new ParamContext_1.default(this.dialect);
|
|
20
|
+
this.condition = new ConditionBuilder_1.default(this.ctx);
|
|
21
|
+
this.havingCondition = new ConditionBuilder_1.default(this.ctx);
|
|
22
|
+
}
|
|
23
|
+
select(fields) {
|
|
24
|
+
this.fields = fields.map(String);
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
addJoin(type, table, localKey, foreignKey) {
|
|
28
|
+
this.joins.push(`${type} JOIN ${table} ON ${localKey} = ${foreignKey}`);
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
join(table, localKey, foreignKey) {
|
|
32
|
+
return this.addJoin('INNER', table, localKey, foreignKey);
|
|
33
|
+
}
|
|
34
|
+
leftJoin(table, localKey, foreignKey) {
|
|
35
|
+
return this.addJoin('LEFT', table, localKey, foreignKey);
|
|
36
|
+
}
|
|
37
|
+
rightJoin(table, localKey, foreignKey) {
|
|
38
|
+
return this.addJoin('RIGHT', table, localKey, foreignKey);
|
|
39
|
+
}
|
|
40
|
+
where(obj) {
|
|
41
|
+
this.condition.where(obj);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
whereRaw(expression) {
|
|
45
|
+
this.condition.raw(expression);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
andGroup(cb) {
|
|
49
|
+
this.condition.andGroup(cb);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
orGroup(cb) {
|
|
53
|
+
this.condition.orGroup(cb);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
groupBy(fields) {
|
|
57
|
+
if (Array.isArray(fields)) {
|
|
58
|
+
this.groupByFields.push(...fields);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.groupByFields.push(fields);
|
|
62
|
+
}
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
having(obj) {
|
|
66
|
+
this.havingCondition.where(obj);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
havingRaw(expr) {
|
|
70
|
+
this.havingCondition.raw(expr);
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
orderBy(column, direction = 'ASC') {
|
|
74
|
+
this.orderByFields.push(`${column} ${direction}`);
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
limit(value) {
|
|
78
|
+
this.limitCount = value;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
offset(value) {
|
|
82
|
+
this.offsetCount = value;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
with(name, subQuery, recursive = false) {
|
|
86
|
+
this.ctes.push({ name, query: subQuery, recursive });
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
fromSubquery(sub, alias) {
|
|
90
|
+
const { query, params } = sub.build();
|
|
91
|
+
params.forEach(p => this.ctx.add(p));
|
|
92
|
+
this.fromClause = `(${query}) AS ${alias}`;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
clone() {
|
|
96
|
+
const qb = new QueryBuilder(this.fromClause, this.executor, this.dialect, this.cacheTTL);
|
|
97
|
+
qb.fields = [...this.fields];
|
|
98
|
+
qb.joins = [...this.joins];
|
|
99
|
+
qb.groupByFields = [...this.groupByFields];
|
|
100
|
+
qb.orderByFields = [...this.orderByFields];
|
|
101
|
+
qb.limitCount = this.limitCount;
|
|
102
|
+
qb.offsetCount = this.offsetCount;
|
|
103
|
+
qb.ctes = [...this.ctes];
|
|
104
|
+
return qb;
|
|
105
|
+
}
|
|
106
|
+
build() {
|
|
107
|
+
let query = '';
|
|
108
|
+
if (this.ctes.length) {
|
|
109
|
+
const recursive = this.ctes.some(c => c.recursive);
|
|
110
|
+
query += `WITH ${recursive ? 'RECURSIVE ' : ''}`;
|
|
111
|
+
const parts = this.ctes.map(cte => {
|
|
112
|
+
const { query: q, params } = cte.query.build();
|
|
113
|
+
params.forEach(p => this.ctx.add(p));
|
|
114
|
+
return `${cte.name} AS (${q})`;
|
|
115
|
+
});
|
|
116
|
+
query += parts.join(', ') + ' ';
|
|
117
|
+
}
|
|
118
|
+
const select = this.fields.length ? this.fields.join(', ') : '*';
|
|
119
|
+
query += `SELECT ${select} FROM ${this.fromClause}`;
|
|
120
|
+
if (this.joins.length) {
|
|
121
|
+
query += ' ' + this.joins.join(' ');
|
|
122
|
+
}
|
|
123
|
+
const where = this.condition.build();
|
|
124
|
+
if (where)
|
|
125
|
+
query += ' ' + where;
|
|
126
|
+
if (this.groupByFields.length) {
|
|
127
|
+
query += ` GROUP BY ${this.groupByFields.join(', ')}`;
|
|
128
|
+
}
|
|
129
|
+
const having = this.havingCondition.build('HAVING');
|
|
130
|
+
if (having)
|
|
131
|
+
query += ' ' + having;
|
|
132
|
+
if (this.orderByFields.length) {
|
|
133
|
+
query += ` ORDER BY ${this.orderByFields.join(', ')}`;
|
|
134
|
+
}
|
|
135
|
+
if (this.limitCount) {
|
|
136
|
+
query += ` LIMIT ${this.limitCount}`;
|
|
137
|
+
}
|
|
138
|
+
if (this.offsetCount) {
|
|
139
|
+
query += ` OFFSET ${this.offsetCount}`;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
query,
|
|
143
|
+
params: this.ctx.getParams()
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async execute() {
|
|
147
|
+
const { query, params } = this.build();
|
|
148
|
+
const result = await this.executor.execute(query, params, this.cacheTTL);
|
|
149
|
+
return result.rows;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.default = QueryBuilder;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ParamContext from "../core/ParamContext";
|
|
2
|
+
export default class ConditionBuilder {
|
|
3
|
+
private ctx;
|
|
4
|
+
private conditions;
|
|
5
|
+
constructor(ctx: ParamContext);
|
|
6
|
+
where(obj: Record<string, any>): this;
|
|
7
|
+
raw(expression: string): this;
|
|
8
|
+
andGroup(callback: (qb: ConditionBuilder) => void): this;
|
|
9
|
+
orGroup(callback: (qb: ConditionBuilder) => void): this;
|
|
10
|
+
build(prefix?: string): string;
|
|
11
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export default class ConditionBuilder {
|
|
2
|
+
constructor(ctx) {
|
|
3
|
+
this.ctx = ctx;
|
|
4
|
+
this.conditions = [];
|
|
5
|
+
}
|
|
6
|
+
where(obj) {
|
|
7
|
+
Object.entries(obj).forEach(([key, value]) => {
|
|
8
|
+
const placeholder = this.ctx.add(value);
|
|
9
|
+
this.conditions.push(`${key} = ${placeholder}`);
|
|
10
|
+
});
|
|
11
|
+
return this;
|
|
12
|
+
}
|
|
13
|
+
raw(expression) {
|
|
14
|
+
this.conditions.push(expression);
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
andGroup(callback) {
|
|
18
|
+
const nested = new ConditionBuilder(this.ctx);
|
|
19
|
+
callback(nested);
|
|
20
|
+
const built = nested.build();
|
|
21
|
+
if (built) {
|
|
22
|
+
this.conditions.push(`(${built.replace(/^WHERE /, '')})`);
|
|
23
|
+
}
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
orGroup(callback) {
|
|
27
|
+
const nested = new ConditionBuilder(this.ctx);
|
|
28
|
+
callback(nested);
|
|
29
|
+
const built = nested.build();
|
|
30
|
+
if (built) {
|
|
31
|
+
this.conditions.push(`OR (${built.replace(/^WHERE /, '')})`);
|
|
32
|
+
}
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
build(prefix = 'WHERE') {
|
|
36
|
+
if (!this.conditions.length)
|
|
37
|
+
return '';
|
|
38
|
+
return `${prefix} ${this.conditions.join(' AND ')}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import QueryExecutor from '../core/QueryExecutor';
|
|
2
|
+
import { Dialect } from "../dialects/Dialect";
|
|
3
|
+
export default class QueryBuilder<T = any> {
|
|
4
|
+
private executor;
|
|
5
|
+
private fields;
|
|
6
|
+
private joins;
|
|
7
|
+
private groupByFields;
|
|
8
|
+
private orderByFields;
|
|
9
|
+
private limitCount?;
|
|
10
|
+
private offsetCount?;
|
|
11
|
+
private ctes;
|
|
12
|
+
private fromClause;
|
|
13
|
+
private condition;
|
|
14
|
+
private havingCondition;
|
|
15
|
+
private ctx;
|
|
16
|
+
constructor(table: string, executor: QueryExecutor, dialect: Dialect);
|
|
17
|
+
select(fields: string[]): this;
|
|
18
|
+
private addJoin;
|
|
19
|
+
join(table: string, localKey: string, foreignKey: string): this;
|
|
20
|
+
leftJoin(table: string, localKey: string, foreignKey: string): this;
|
|
21
|
+
rightJoin(table: string, localKey: string, foreignKey: string): this;
|
|
22
|
+
fromSubquery(sub: QueryBuilder, alias: string): this;
|
|
23
|
+
where(obj: Record<string, any>): this;
|
|
24
|
+
whereSub(column: string, operator: 'IN' | 'NOT IN', sub: QueryBuilder): this;
|
|
25
|
+
limit(limit: number): this;
|
|
26
|
+
build(): {
|
|
27
|
+
query: string;
|
|
28
|
+
params: any[];
|
|
29
|
+
};
|
|
30
|
+
execute(): Promise<any[]>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import ParamContext from '../core/ParamContext';
|
|
2
|
+
import ConditionBuilder from './ConditionBuilder';
|
|
3
|
+
export default class QueryBuilder {
|
|
4
|
+
constructor(table, executor, dialect) {
|
|
5
|
+
this.executor = executor;
|
|
6
|
+
this.fields = [];
|
|
7
|
+
this.joins = [];
|
|
8
|
+
this.groupByFields = [];
|
|
9
|
+
this.orderByFields = [];
|
|
10
|
+
this.ctes = [];
|
|
11
|
+
this.fromClause = table;
|
|
12
|
+
this.ctx = new ParamContext(dialect);
|
|
13
|
+
this.condition = new ConditionBuilder(this.ctx);
|
|
14
|
+
this.havingCondition = new ConditionBuilder(this.ctx);
|
|
15
|
+
}
|
|
16
|
+
select(fields) {
|
|
17
|
+
this.fields = fields;
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
addJoin(type, table, localKey, foreignKey) {
|
|
21
|
+
this.joins.push(`${type} JOIN ${table} ON ${localKey} = ${foreignKey}`);
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
join(table, localKey, foreignKey) {
|
|
25
|
+
return this.addJoin('INNER', table, localKey, foreignKey);
|
|
26
|
+
}
|
|
27
|
+
leftJoin(table, localKey, foreignKey) {
|
|
28
|
+
return this.addJoin('LEFT', table, localKey, foreignKey);
|
|
29
|
+
}
|
|
30
|
+
rightJoin(table, localKey, foreignKey) {
|
|
31
|
+
return this.addJoin('RIGHT', table, localKey, foreignKey);
|
|
32
|
+
}
|
|
33
|
+
fromSubquery(sub, alias) {
|
|
34
|
+
const { query, params } = sub.build();
|
|
35
|
+
params.forEach(p => this.ctx.add(p));
|
|
36
|
+
this.fromClause = `(${query}) AS ${alias}`;
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
where(obj) {
|
|
40
|
+
this.condition.where(obj);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
whereSub(column, operator, sub) {
|
|
44
|
+
const { query, params } = sub.build();
|
|
45
|
+
params.forEach(p => this.ctx.add(p));
|
|
46
|
+
this.condition.raw(`${column} ${operator} (${query})`);
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
limit(limit) {
|
|
50
|
+
this.limitCount = limit;
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
build() {
|
|
54
|
+
const select = this.fields.length
|
|
55
|
+
? this.fields.join(', ')
|
|
56
|
+
: '*';
|
|
57
|
+
let query = `SELECT ${select}
|
|
58
|
+
FROM ${this.fromClause}`;
|
|
59
|
+
if (this.joins.length) {
|
|
60
|
+
query += ' ' + this.joins.join(' ');
|
|
61
|
+
}
|
|
62
|
+
const whereClause = this.condition.build();
|
|
63
|
+
if (whereClause)
|
|
64
|
+
query += ' ' + whereClause;
|
|
65
|
+
if (this.limitCount) {
|
|
66
|
+
query += ` LIMIT ${this.limitCount}`;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
query,
|
|
70
|
+
params: this.ctx.getParams()
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async execute() {
|
|
74
|
+
if (!this.executor) {
|
|
75
|
+
throw new Error('No QueryExecutor provided');
|
|
76
|
+
}
|
|
77
|
+
const { query, params } = this.build();
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
const result = await this.executor.execute(query, params);
|
|
80
|
+
return result.rows;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Dialect } from '../dialects/Dialect';
|
|
2
|
+
import QueryExecutor from './QueryExecutor';
|
|
3
|
+
import QueryBuilder from '../query/QueryBuilder';
|
|
4
|
+
interface DatabaseOptions {
|
|
5
|
+
connectionString: string;
|
|
6
|
+
dialect?: Dialect;
|
|
7
|
+
defaultCacheTTL?: number;
|
|
8
|
+
}
|
|
9
|
+
export default class Database {
|
|
10
|
+
private executor;
|
|
11
|
+
private dialect;
|
|
12
|
+
private transactionManager;
|
|
13
|
+
private defaultCacheTTL?;
|
|
14
|
+
constructor(options: DatabaseOptions);
|
|
15
|
+
table<T = any>(name: string): QueryBuilder<T>;
|
|
16
|
+
transaction<T>(callback: (trxDb: Database) => Promise<T>): Promise<T>;
|
|
17
|
+
setExecutor(executor: QueryExecutor): void;
|
|
18
|
+
repository<R>(RepoClass: new (executor: QueryExecutor, dialect: Dialect) => R): R;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import PostgresDialect from '../dialects/PostgresDialect';
|
|
2
|
+
import QueryExecutor from './QueryExecutor';
|
|
3
|
+
import QueryBuilder from '../query/QueryBuilder';
|
|
4
|
+
import TransactionManager from './TransactionManager';
|
|
5
|
+
export default class Database {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.dialect = options.dialect ?? new PostgresDialect();
|
|
8
|
+
this.executor = new QueryExecutor(options);
|
|
9
|
+
this.transactionManager = new TransactionManager(this.executor.getPool());
|
|
10
|
+
this.defaultCacheTTL = options.defaultCacheTTL;
|
|
11
|
+
}
|
|
12
|
+
table(name) {
|
|
13
|
+
return new QueryBuilder(name, this.executor, this.dialect, this.defaultCacheTTL);
|
|
14
|
+
}
|
|
15
|
+
async transaction(callback) {
|
|
16
|
+
return this.transactionManager.transaction(async (trxClient) => {
|
|
17
|
+
const trxExecutor = new QueryExecutor(undefined, trxClient);
|
|
18
|
+
const trxDb = new Database({
|
|
19
|
+
connectionString: '',
|
|
20
|
+
dialect: this.dialect,
|
|
21
|
+
defaultCacheTTL: this.defaultCacheTTL
|
|
22
|
+
});
|
|
23
|
+
trxDb.setExecutor(trxExecutor);
|
|
24
|
+
return callback(trxDb);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
setExecutor(executor) {
|
|
28
|
+
this.executor = executor;
|
|
29
|
+
}
|
|
30
|
+
repository(RepoClass) {
|
|
31
|
+
return new RepoClass(this.executor, this.dialect);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default class ParamContext {
|
|
2
|
+
constructor(dialect) {
|
|
3
|
+
this.dialect = dialect;
|
|
4
|
+
this.params = [];
|
|
5
|
+
}
|
|
6
|
+
add(value) {
|
|
7
|
+
this.params.push(value);
|
|
8
|
+
return this.dialect.placeholder(this.params.length);
|
|
9
|
+
}
|
|
10
|
+
getParams() {
|
|
11
|
+
return this.params;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Pool, PoolClient, QueryResult } from 'pg';
|
|
2
|
+
interface ExecutorOptions {
|
|
3
|
+
connectionString: string;
|
|
4
|
+
}
|
|
5
|
+
export default class QueryExecutor {
|
|
6
|
+
private pool?;
|
|
7
|
+
private client?;
|
|
8
|
+
constructor(options?: ExecutorOptions, client?: PoolClient);
|
|
9
|
+
execute(query: string, params: any[] | undefined, cacheTTL: number | undefined): Promise<QueryResult>;
|
|
10
|
+
getPool(): Pool | undefined;
|
|
11
|
+
getClient(): PoolClient | undefined;
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
export default class QueryExecutor {
|
|
3
|
+
constructor(options, client) {
|
|
4
|
+
if (client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (options?.connectionString) {
|
|
9
|
+
this.pool = new Pool({
|
|
10
|
+
connectionString: options.connectionString
|
|
11
|
+
});
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
throw new Error('Invalid QueryExecutor initialization');
|
|
15
|
+
}
|
|
16
|
+
async execute(query, params = [], cacheTTL) {
|
|
17
|
+
if (this.client) {
|
|
18
|
+
return this.client.query(query, params);
|
|
19
|
+
}
|
|
20
|
+
if (this.pool) {
|
|
21
|
+
return this.pool.query(query, params);
|
|
22
|
+
}
|
|
23
|
+
throw new Error('Executor not initialized');
|
|
24
|
+
}
|
|
25
|
+
getPool() {
|
|
26
|
+
return this.pool;
|
|
27
|
+
}
|
|
28
|
+
getClient() {
|
|
29
|
+
return this.client;
|
|
30
|
+
}
|
|
31
|
+
async close() {
|
|
32
|
+
if (this.pool) {
|
|
33
|
+
await this.pool.end();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default class TransactionManager {
|
|
2
|
+
constructor(pool) {
|
|
3
|
+
this.pool = pool;
|
|
4
|
+
}
|
|
5
|
+
async transaction(callback) {
|
|
6
|
+
const client = await this.pool.connect();
|
|
7
|
+
try {
|
|
8
|
+
await client.query('BEGIN');
|
|
9
|
+
const result = await callback(client);
|
|
10
|
+
await client.query('COMMIT');
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
await client.query('ROLLBACK');
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
client.release();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Repository from "../orm/Repository";
|
|
2
|
+
export default class UnitOfWork {
|
|
3
|
+
private newEntities;
|
|
4
|
+
private dirtyEntities;
|
|
5
|
+
private removedEntities;
|
|
6
|
+
registerNew(entity: any): void;
|
|
7
|
+
registerDirty(entity: any): void;
|
|
8
|
+
registerRemoved(entity: any): void;
|
|
9
|
+
commit(repository: Repository<any>): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export default class UnitOfWork {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.newEntities = [];
|
|
4
|
+
this.dirtyEntities = [];
|
|
5
|
+
this.removedEntities = [];
|
|
6
|
+
}
|
|
7
|
+
registerNew(entity) {
|
|
8
|
+
this.newEntities.push(entity);
|
|
9
|
+
}
|
|
10
|
+
registerDirty(entity) {
|
|
11
|
+
this.dirtyEntities.push(entity);
|
|
12
|
+
}
|
|
13
|
+
registerRemoved(entity) {
|
|
14
|
+
this.removedEntities.push(entity);
|
|
15
|
+
}
|
|
16
|
+
async commit(repository) {
|
|
17
|
+
for (const e of this.newEntities)
|
|
18
|
+
await repository.insert(e);
|
|
19
|
+
for (const e of this.dirtyEntities)
|
|
20
|
+
await repository.update(e);
|
|
21
|
+
for (const e of this.removedEntities)
|
|
22
|
+
await repository.delete(e);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as QueryExecutor } from './core/QueryExecutor';
|
|
2
|
+
export { default as QueryBuilder } from './builders/QueryBuilder';
|
|
3
|
+
export { default as ConditionBuilder } from './builders/ConditionBuilder';
|
|
4
|
+
export { default as Database } from './core/Database';
|
|
5
|
+
export { default as TransactionManager } from './core/TransactionManager';
|
|
6
|
+
export { default as PostgresDialect } from './dialects/PostgresDialect';
|
|
7
|
+
export { default as Repository } from './orm/Repository';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as QueryExecutor } from './core/QueryExecutor';
|
|
2
|
+
export { default as QueryBuilder } from './builders/QueryBuilder';
|
|
3
|
+
export { default as ConditionBuilder } from './builders/ConditionBuilder';
|
|
4
|
+
export { default as Database } from './core/Database';
|
|
5
|
+
export { default as TransactionManager } from './core/TransactionManager';
|
|
6
|
+
export { default as PostgresDialect } from './dialects/PostgresDialect';
|
|
7
|
+
export { default as Repository } from './orm/Repository';
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { QueryBuilder, QueryExecutor } from "../index";
|
|
2
|
+
import { Dialect } from "../dialects/Dialect";
|
|
3
|
+
export default abstract class Repository<T> {
|
|
4
|
+
protected table: string;
|
|
5
|
+
protected executor: QueryExecutor;
|
|
6
|
+
protected dialect: Dialect;
|
|
7
|
+
constructor(table: string, executor: QueryExecutor, dialect: Dialect);
|
|
8
|
+
qb(): QueryBuilder<T>;
|
|
9
|
+
findById(id: number): Promise<T | null>;
|
|
10
|
+
insert(data: Partial<T>): Promise<void>;
|
|
11
|
+
update(data: Partial<T>): Promise<void>;
|
|
12
|
+
delete(data: Partial<T>): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { QueryBuilder } from "../index";
|
|
2
|
+
export default class Repository {
|
|
3
|
+
constructor(table, executor, dialect) {
|
|
4
|
+
this.table = table;
|
|
5
|
+
this.executor = executor;
|
|
6
|
+
this.dialect = dialect;
|
|
7
|
+
}
|
|
8
|
+
qb() {
|
|
9
|
+
return new QueryBuilder(this.table, this.executor, this.dialect);
|
|
10
|
+
}
|
|
11
|
+
async findById(id) {
|
|
12
|
+
const rows = await this.qb()
|
|
13
|
+
.where({ id })
|
|
14
|
+
.limit(1)
|
|
15
|
+
.execute();
|
|
16
|
+
return rows[0] ?? null;
|
|
17
|
+
}
|
|
18
|
+
async insert(data) {
|
|
19
|
+
// implementação insert segura
|
|
20
|
+
}
|
|
21
|
+
async update(data) {
|
|
22
|
+
// implementação update segura
|
|
23
|
+
}
|
|
24
|
+
async delete(data) {
|
|
25
|
+
// soft delete opcional
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import ParamContext from '../core/ParamContext';
|
|
2
|
+
export default class ConditionBuilder {
|
|
3
|
+
private ctx;
|
|
4
|
+
private parts;
|
|
5
|
+
constructor(ctx: ParamContext);
|
|
6
|
+
where(obj: Record<string, any>): this;
|
|
7
|
+
raw(expression: string): this;
|
|
8
|
+
andGroup(cb: (qb: ConditionBuilder) => void): this;
|
|
9
|
+
orGroup(cb: (qb: ConditionBuilder) => void): this;
|
|
10
|
+
build(prefix?: string): string;
|
|
11
|
+
}
|