@m2k-5f/pgtx 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 +134 -0
- package/dist/clauses/array.clause.d.ts +10 -0
- package/dist/clauses/array.clause.d.ts.map +1 -0
- package/dist/clauses/array.clause.js +34 -0
- package/dist/clauses/base.clause.d.ts +5 -0
- package/dist/clauses/base.clause.d.ts.map +1 -0
- package/dist/clauses/base.clause.js +6 -0
- package/dist/clauses/fragment.clause.d.ts +10 -0
- package/dist/clauses/fragment.clause.d.ts.map +1 -0
- package/dist/clauses/fragment.clause.js +20 -0
- package/dist/clauses/iden.caluse.d.ts +9 -0
- package/dist/clauses/iden.caluse.d.ts.map +1 -0
- package/dist/clauses/iden.caluse.js +20 -0
- package/dist/clauses/static.clause.d.ts +9 -0
- package/dist/clauses/static.clause.d.ts.map +1 -0
- package/dist/clauses/static.clause.js +18 -0
- package/dist/clauses/update.clause.d.ts +10 -0
- package/dist/clauses/update.clause.d.ts.map +1 -0
- package/dist/clauses/update.clause.js +26 -0
- package/dist/clauses/values.clause.d.ts +9 -0
- package/dist/clauses/values.clause.d.ts.map +1 -0
- package/dist/clauses/values.clause.js +27 -0
- package/dist/connection.d.ts +50 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +101 -0
- package/dist/index.d.ts +92 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/pool.d.ts +59 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +112 -0
- package/dist/query.cacher.d.ts +6 -0
- package/dist/query.cacher.d.ts.map +1 -0
- package/dist/query.cacher.js +23 -0
- package/dist/transaction.d.ts +40 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +71 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +27 -0
- package/package.json +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Pgtx 🚀
|
|
2
|
+
|
|
3
|
+
A lightweight, **high-performance** SQL query builder for `node-postgres` (pg).
|
|
4
|
+
Experience ORM-like convenience (auto-inserts, updates, recursive fragments) with the transparency and speed of raw SQL.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 🔥 Why Pgtx?
|
|
9
|
+
|
|
10
|
+
* **Zero-Cost Abstraction**: Only ~2% overhead compared to raw `pg.query`.
|
|
11
|
+
* **Structural Caching**: Uses `WeakMap` to cache SQL templates. Static parts are parsed only once.
|
|
12
|
+
* **Explicit Prepared Statements**: Create and reuse prepared statements with type safety
|
|
13
|
+
* **True Recursion**: Nest `sql.fragment` anywhere. Argument numbering ($1, $2) is managed automatically across all nesting levels.
|
|
14
|
+
* **No Magic**: You write SQL, `Pgtx` handles the tedious parts (placeholders, identifiers, bulk inserts).
|
|
15
|
+
* **ACID Transactions**: Reliable transaction management with automatic rollback on errors.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 🚀 Quick Start
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { sql, Pool } from 'pgtx';
|
|
23
|
+
|
|
24
|
+
const pool = new Pool({ /* pg.PoolConfig */ })
|
|
25
|
+
|
|
26
|
+
// Type-safe query with automatic placeholder ($1)
|
|
27
|
+
const [user] = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ⚡ Performance Benchmark
|
|
31
|
+
|
|
32
|
+
The following results were measured during sequential execution of 10,000 complex `UPSERT` queries.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
| Tool | RPS | Avg. Query Time | Performance Overhead |
|
|
36
|
+
| :--- | :---: | :---: | :---: |
|
|
37
|
+
| **Native `pg.query`** | **~194** | **5.15 ms** | **0% (Baseline)** |
|
|
38
|
+
| **Pgtx** | **~190** | **5.27 ms** | **~2.1%** |
|
|
39
|
+
| Typical Node.js ORM | **~58** | 12.5+ ms | > 150% |
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
## 📖 Feature Guide
|
|
43
|
+
|
|
44
|
+
### 1. Recursive Fragments (sql.fragment)
|
|
45
|
+
Combine multiple SQL pieces. Perfect for dynamic filters or subqueries.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const filter = sql.fragment`status = ${'active'} AND age > ${21}`
|
|
49
|
+
const roleSub = sql.fragment`(SELECT id FROM roles WHERE name = ${'admin'})`
|
|
50
|
+
|
|
51
|
+
await pool.query`
|
|
52
|
+
INSERT INTO users (name, role_id)
|
|
53
|
+
VALUES (${'Ivan'}, (${roleSub}))
|
|
54
|
+
WHERE ${filter}
|
|
55
|
+
`
|
|
56
|
+
// SQL: INSERT INTO users ... VALUES ($1, (SELECT id FROM roles WHERE name = $2)) WHERE status = $3 AND age > $4
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 2. Transactions
|
|
60
|
+
Automatic BEGIN, COMMIT, and ROLLBACK. Use savepoint for nested logic.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
await pool.begin(async (tx) => {
|
|
64
|
+
await tx.query`UPDATE accounts SET balance = balance - 100 WHERE id = 1`;
|
|
65
|
+
|
|
66
|
+
// Nested transaction (Savepoint)
|
|
67
|
+
await tx.savepoint('inventory', async (stx) => {
|
|
68
|
+
await stx.query`UPDATE stock SET count = count - 1 WHERE item_id = ${42}`;
|
|
69
|
+
if (outOfStock) throw new Error(); // Only 'inventory' rolls back
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
// Main transaction commits or rolls back based on callback success
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 3. Bulk Inserts (sql.insert)
|
|
76
|
+
Automatically extracts columns from the first object. Supports single objects and arrays.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const users = [
|
|
80
|
+
{ name: 'Alice', email: 'alice@test.com' },
|
|
81
|
+
{ name: 'Bob', email: 'bob@test.com' }
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
await pool.query`INSERT INTO users ${sql.insert(users)}`
|
|
85
|
+
// SQL: INSERT INTO users (name, email) VALUES ($1, $2), ($3, $4)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## 4. Prepared Statements
|
|
89
|
+
Pre-parse SQL on the database server for maximum performance in hot loops.
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const stmt = await pool.prepare<User>("get_user_by_email", 'SELECT * FROM users WHERE email = ?')
|
|
93
|
+
// `Pgtx` automatically maps standard `?` placeholders to native `$1, $2` indexes.
|
|
94
|
+
|
|
95
|
+
const users = await stmt.execute('test@example.com')
|
|
96
|
+
// Statements created via pool.prepare are lazily initialized on each connection upon first use,
|
|
97
|
+
// gradually "warming up" the entire pool for peak performance.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 5. Smart Lists (sql.array)
|
|
101
|
+
The ultimate tool for dynamic lists. Works for IN clauses, column lists, or joined conditions.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
// 1. Classic IN clause
|
|
105
|
+
const ids = [10, 20]
|
|
106
|
+
await pool.query`SELECT * FROM users WHERE id IN (${sql.array(ids)})`
|
|
107
|
+
// SQL: SELECT * FROM users WHERE id IN ($1, $2)
|
|
108
|
+
|
|
109
|
+
// 2. Dynamic column list
|
|
110
|
+
const cols = [sql.ident('id'), sql.ident('name')]
|
|
111
|
+
await pool.query`SELECT ${sql.array(cols)} FROM users`
|
|
112
|
+
// SQL: SELECT "id", "name" FROM users
|
|
113
|
+
|
|
114
|
+
// 3. Dynamic WHERE conditions
|
|
115
|
+
const conds = [sql.fragment`active = true`, sql.fragment`age > ${18}`]
|
|
116
|
+
await pool.query`SELECT * FROM users WHERE ${sql.array(conds, ' AND ')}`
|
|
117
|
+
// SQL: SELECT * FROM users WHERE active = true AND age > $1
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## 6. Dynamic Updates (sql.update)
|
|
121
|
+
Easily generate SET clauses from plain JavaScript objects.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const data = { status: 'pro', last_login: new Date() }
|
|
125
|
+
|
|
126
|
+
await pool.query`UPDATE users SET ${sql.update(data)} WHERE id = ${1}`
|
|
127
|
+
// SQL: UPDATE users SET status = $1, last_login = $2 WHERE id = $3
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
## 🛡️ Security
|
|
132
|
+
* **SQL Injection**: Automatically uses native placeholders ($1, $2) for all values.
|
|
133
|
+
* **Identifiers**: `sql.ident` safely escapes table and column names using double quotes.
|
|
134
|
+
* **Connection Leaks**: `pool.query` uses try...finally internally to ensure connections are always returned to the pool.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Clause } from "../clauses/base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class ArrayClause extends Clause {
|
|
4
|
+
private readonly array;
|
|
5
|
+
private readonly separator;
|
|
6
|
+
constructor(array: any[], separator?: string);
|
|
7
|
+
map(argCounter: number): CompiledSqlQuery;
|
|
8
|
+
}
|
|
9
|
+
export declare function arrayClause(array: any[], separator?: string): ArrayClause;
|
|
10
|
+
//# sourceMappingURL=array.clause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/array.clause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,WAAY,SAAQ,MAAM;IAE/B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBADT,KAAK,EAAE,GAAG,EAAE,EACZ,SAAS,GAAE,MAAa;IAGpC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAmBrD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,SAAS,GAAE,MAAa,GAAG,WAAW,CAE/E"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArrayClause = void 0;
|
|
4
|
+
exports.arrayClause = arrayClause;
|
|
5
|
+
const base_clause_1 = require("../clauses/base.clause");
|
|
6
|
+
class ArrayClause extends base_clause_1.Clause {
|
|
7
|
+
constructor(array, separator = ", ") {
|
|
8
|
+
super();
|
|
9
|
+
this.array = array;
|
|
10
|
+
this.separator = separator;
|
|
11
|
+
}
|
|
12
|
+
map(argCounter) {
|
|
13
|
+
if (this.array.length === 0)
|
|
14
|
+
return { text: 'NULL', args: [], argCounter };
|
|
15
|
+
const args = [];
|
|
16
|
+
const text = `${this.array.map(value => {
|
|
17
|
+
if (value instanceof base_clause_1.Clause) {
|
|
18
|
+
const result = value.map(argCounter);
|
|
19
|
+
args.push(...result.args);
|
|
20
|
+
argCounter = result.argCounter;
|
|
21
|
+
return result.text;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
args.push(value);
|
|
25
|
+
return `$${argCounter++}`;
|
|
26
|
+
}
|
|
27
|
+
}).join(this.separator)}`;
|
|
28
|
+
return { text, args, argCounter };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.ArrayClause = ArrayClause;
|
|
32
|
+
function arrayClause(array, separator = ", ") {
|
|
33
|
+
return new ArrayClause(array, separator);
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/base.clause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,8BAAsB,MAAM;IACxB,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CACrD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Clause } from "./base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class FragmentClause extends Clause {
|
|
4
|
+
readonly strings: TemplateStringsArray;
|
|
5
|
+
readonly values: any[];
|
|
6
|
+
constructor(strings: TemplateStringsArray, values: any[]);
|
|
7
|
+
map(currentArgCounter: number): CompiledSqlQuery;
|
|
8
|
+
}
|
|
9
|
+
export declare function fragmentClause(strings: TemplateStringsArray, ...values: any[]): FragmentClause;
|
|
10
|
+
//# sourceMappingURL=fragment.clause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragment.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/fragment.clause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAI,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAsB,MAAM,UAAU,CAAC;AAEhE,qBAAa,cAAe,SAAQ,MAAM;IAElC,QAAQ,CAAC,OAAO,EAAE,oBAAoB;IACtC,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;gBADb,OAAO,EAAE,oBAAoB,EAC7B,MAAM,EAAE,GAAG,EAAE;IAGjB,GAAG,CAAC,iBAAiB,EAAE,MAAM,GAAG,gBAAgB;CAG5D;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,kBAE7E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FragmentClause = void 0;
|
|
4
|
+
exports.fragmentClause = fragmentClause;
|
|
5
|
+
const base_clause_1 = require("./base.clause");
|
|
6
|
+
const utils_1 = require("../utils");
|
|
7
|
+
class FragmentClause extends base_clause_1.Clause {
|
|
8
|
+
constructor(strings, values) {
|
|
9
|
+
super();
|
|
10
|
+
this.strings = strings;
|
|
11
|
+
this.values = values;
|
|
12
|
+
}
|
|
13
|
+
map(currentArgCounter) {
|
|
14
|
+
return (0, utils_1.compileSqlTemplate)(this.strings, this.values, currentArgCounter);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.FragmentClause = FragmentClause;
|
|
18
|
+
function fragmentClause(strings, ...values) {
|
|
19
|
+
return new FragmentClause(strings, values);
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Clause } from "./base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class IdentifierClause<T extends string> extends Clause {
|
|
4
|
+
readonly value: T;
|
|
5
|
+
constructor(value: T);
|
|
6
|
+
map(argCounter: number): CompiledSqlQuery;
|
|
7
|
+
}
|
|
8
|
+
export declare function identClause<T extends string>(identificator: T): IdentifierClause<T>;
|
|
9
|
+
//# sourceMappingURL=iden.caluse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"iden.caluse.d.ts","sourceRoot":"","sources":["../../src/clauses/iden.caluse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,MAAM;IAEtD,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAGZ,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAMrD;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,aAAa,EAAE,CAAC,uBAE7D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IdentifierClause = void 0;
|
|
4
|
+
exports.identClause = identClause;
|
|
5
|
+
const base_clause_1 = require("./base.clause");
|
|
6
|
+
class IdentifierClause extends base_clause_1.Clause {
|
|
7
|
+
constructor(value) {
|
|
8
|
+
super();
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
map(argCounter) {
|
|
12
|
+
const text = `"${this.value}"`;
|
|
13
|
+
const args = [];
|
|
14
|
+
return { text, args, argCounter };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.IdentifierClause = IdentifierClause;
|
|
18
|
+
function identClause(identificator) {
|
|
19
|
+
return new IdentifierClause(identificator);
|
|
20
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Clause } from "./base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class StaticClause<T extends string> extends Clause {
|
|
4
|
+
readonly value: T;
|
|
5
|
+
constructor(value: T);
|
|
6
|
+
map(argCounter: number): CompiledSqlQuery;
|
|
7
|
+
}
|
|
8
|
+
export declare function staticClause<T extends string>(value: T): StaticClause<T>;
|
|
9
|
+
//# sourceMappingURL=static.clause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/static.clause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAC,MAAM,eAAe,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,MAAM;IAElD,QAAQ,CAAC,KAAK,EAAE,CAAC;gBAAR,KAAK,EAAE,CAAC;IAKZ,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAGrD;AAGD,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAExE"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaticClause = void 0;
|
|
4
|
+
exports.staticClause = staticClause;
|
|
5
|
+
const base_clause_1 = require("./base.clause");
|
|
6
|
+
class StaticClause extends base_clause_1.Clause {
|
|
7
|
+
constructor(value) {
|
|
8
|
+
super();
|
|
9
|
+
this.value = value;
|
|
10
|
+
}
|
|
11
|
+
map(argCounter) {
|
|
12
|
+
return { text: this.value, args: [], argCounter };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.StaticClause = StaticClause;
|
|
16
|
+
function staticClause(value) {
|
|
17
|
+
return new StaticClause(value);
|
|
18
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Clause } from "./base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class UpdateClause<T extends Record<string, any>> extends Clause {
|
|
4
|
+
readonly updateMap: T;
|
|
5
|
+
readonly columns?: (keyof T)[] | undefined;
|
|
6
|
+
constructor(updateMap: T, columns?: (keyof T)[] | undefined);
|
|
7
|
+
map(argCounter: number): CompiledSqlQuery;
|
|
8
|
+
}
|
|
9
|
+
export declare function updateClause<T extends Record<string, any>>(object: T, ...updateColumns: (keyof T)[]): UpdateClause<T>;
|
|
10
|
+
//# sourceMappingURL=update.clause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/update.clause.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAE,SAAQ,MAAM;IAE/D,QAAQ,CAAC,SAAS,EAAE,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE;gBADrB,SAAS,EAAE,CAAC,EACZ,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,YAAA;IAGzB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAerD;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,YAAY,CAAC,CAAC,CAAC,CAErH"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UpdateClause = void 0;
|
|
4
|
+
exports.updateClause = updateClause;
|
|
5
|
+
const base_clause_1 = require("./base.clause");
|
|
6
|
+
class UpdateClause extends base_clause_1.Clause {
|
|
7
|
+
constructor(updateMap, columns) {
|
|
8
|
+
super();
|
|
9
|
+
this.updateMap = updateMap;
|
|
10
|
+
this.columns = columns;
|
|
11
|
+
}
|
|
12
|
+
map(argCounter) {
|
|
13
|
+
const columns = this.columns || Object.keys(this.updateMap);
|
|
14
|
+
const args = [];
|
|
15
|
+
const text = columns
|
|
16
|
+
.map((key) => {
|
|
17
|
+
args.push(this.updateMap[key]);
|
|
18
|
+
return `${key.toString()} = $${argCounter++}`;
|
|
19
|
+
}).join(', ');
|
|
20
|
+
return { text, args, argCounter };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.UpdateClause = UpdateClause;
|
|
24
|
+
function updateClause(object, ...updateColumns) {
|
|
25
|
+
return new UpdateClause(object, updateColumns.length > 0 ? updateColumns : undefined);
|
|
26
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Clause } from "./base.clause";
|
|
2
|
+
import { CompiledSqlQuery } from "../utils";
|
|
3
|
+
export declare class InsertClause extends Clause {
|
|
4
|
+
readonly inserts: Record<string, any>[];
|
|
5
|
+
constructor(inserts: Record<string, any>[]);
|
|
6
|
+
map(argCounter: number): CompiledSqlQuery;
|
|
7
|
+
}
|
|
8
|
+
export declare function valueClause<T extends Record<string, any>>(...objects: [T, ...NoInfer<T>[]]): InsertClause;
|
|
9
|
+
//# sourceMappingURL=values.clause.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.clause.d.ts","sourceRoot":"","sources":["../../src/clauses/values.clause.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,qBAAa,YAAa,SAAQ,MAAM;IAEhC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;gBAA9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE;IAGlC,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAgBrD;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,gBAE1F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InsertClause = void 0;
|
|
4
|
+
exports.valueClause = valueClause;
|
|
5
|
+
const base_clause_1 = require("./base.clause");
|
|
6
|
+
class InsertClause extends base_clause_1.Clause {
|
|
7
|
+
constructor(inserts) {
|
|
8
|
+
super();
|
|
9
|
+
this.inserts = inserts;
|
|
10
|
+
}
|
|
11
|
+
map(argCounter) {
|
|
12
|
+
const columns = Object.keys(this.inserts[0]);
|
|
13
|
+
let text = `(${columns.join(', ')}) VALUES `;
|
|
14
|
+
let args = [];
|
|
15
|
+
text += `${this.inserts.map(values => {
|
|
16
|
+
return `(${Object.values(values).map(value => {
|
|
17
|
+
args.push(value);
|
|
18
|
+
return `$${argCounter++}`;
|
|
19
|
+
}).join(", ")})`;
|
|
20
|
+
}).join(", ")}`;
|
|
21
|
+
return { text, args, argCounter };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.InsertClause = InsertClause;
|
|
25
|
+
function valueClause(...objects) {
|
|
26
|
+
return new InsertClause(objects);
|
|
27
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { PoolClient, QueryResultRow } from "pg";
|
|
2
|
+
import { PreparedStatement } from "./types";
|
|
3
|
+
import { Transaction } from "./transaction";
|
|
4
|
+
/**
|
|
5
|
+
* Represents a single dedicated connection to the database.
|
|
6
|
+
* Always remember to call `.release()` when finished.
|
|
7
|
+
*/
|
|
8
|
+
export declare class Connection {
|
|
9
|
+
private readonly client;
|
|
10
|
+
private isReleased;
|
|
11
|
+
constructor(client: PoolClient);
|
|
12
|
+
/**
|
|
13
|
+
* Checks if the connection is still open and not returned to the pool.
|
|
14
|
+
*/
|
|
15
|
+
get isActive(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a prepared statement on this specific connection.
|
|
18
|
+
* Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const stmt = await conn.prepare('get_user', 'SELECT * FROM users WHERE id = ?');
|
|
22
|
+
* const rows = await stmt.execute(1);
|
|
23
|
+
*/
|
|
24
|
+
prepare<TResult extends QueryResultRow = any, TParams extends any[] = any[]>(name: string, sqlTemplate: string): Promise<PreparedStatement<TResult, TParams>>;
|
|
25
|
+
/**
|
|
26
|
+
* Releases the connection back to the pool.
|
|
27
|
+
* The connection cannot be used after this call.
|
|
28
|
+
*/
|
|
29
|
+
release(): void;
|
|
30
|
+
private checkActive;
|
|
31
|
+
/**
|
|
32
|
+
* Executes a tagged SQL query using structural caching.
|
|
33
|
+
* Supports recursive fragments and clauses.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* const users = await conn.query`SELECT * FROM users WHERE id = ${1}`;
|
|
37
|
+
*/
|
|
38
|
+
query<T extends QueryResultRow = any>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Starts a managed transaction on this connection.
|
|
41
|
+
* Handles automatic COMMIT on success or ROLLBACK on error.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* await conn.begin(async (tx) => {
|
|
45
|
+
* await tx.query`INSERT INTO logs ...`;
|
|
46
|
+
* });
|
|
47
|
+
*/
|
|
48
|
+
begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../src/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,IAAI,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAK3C;;;GAGG;AACH,qBAAa,UAAU;IAIf,OAAO,CAAC,QAAQ,CAAC,MAAM;IAH3B,OAAO,CAAC,UAAU,CAAiB;gBAGd,MAAM,EAAE,UAAU;IAGvC;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED;;;;;;;OAOG;IACU,OAAO,CAAC,OAAO,SAAS,cAAc,GAAG,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EACpF,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAoB/C;;;OAGG;IACI,OAAO,IAAI,IAAI;IAMtB,OAAO,CAAC,WAAW;IAMnB;;;;;;OAMG;IACU,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAUjH;;;;;;;;OAQG;IACU,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAmB/E"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Connection = void 0;
|
|
4
|
+
const transaction_1 = require("./transaction");
|
|
5
|
+
const query_cacher_1 = require("./query.cacher");
|
|
6
|
+
const cacher = new query_cacher_1.QueryCacher();
|
|
7
|
+
/**
|
|
8
|
+
* Represents a single dedicated connection to the database.
|
|
9
|
+
* Always remember to call `.release()` when finished.
|
|
10
|
+
*/
|
|
11
|
+
class Connection {
|
|
12
|
+
constructor(client) {
|
|
13
|
+
this.client = client;
|
|
14
|
+
this.isReleased = false;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Checks if the connection is still open and not returned to the pool.
|
|
18
|
+
*/
|
|
19
|
+
get isActive() {
|
|
20
|
+
return !this.isReleased;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates a prepared statement on this specific connection.
|
|
24
|
+
* Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* const stmt = await conn.prepare('get_user', 'SELECT * FROM users WHERE id = ?');
|
|
28
|
+
* const rows = await stmt.execute(1);
|
|
29
|
+
*/
|
|
30
|
+
async prepare(name, sqlTemplate) {
|
|
31
|
+
let index = 1;
|
|
32
|
+
const text = sqlTemplate.replace(/\?/g, () => `$${index++}`);
|
|
33
|
+
return {
|
|
34
|
+
text: text,
|
|
35
|
+
name: name,
|
|
36
|
+
execute: async (...args) => {
|
|
37
|
+
this.checkActive();
|
|
38
|
+
const result = await this.client.query({
|
|
39
|
+
name,
|
|
40
|
+
text,
|
|
41
|
+
values: args
|
|
42
|
+
});
|
|
43
|
+
return result.rows;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Releases the connection back to the pool.
|
|
49
|
+
* The connection cannot be used after this call.
|
|
50
|
+
*/
|
|
51
|
+
release() {
|
|
52
|
+
if (this.isReleased)
|
|
53
|
+
return;
|
|
54
|
+
this.isReleased = true;
|
|
55
|
+
this.client.release();
|
|
56
|
+
}
|
|
57
|
+
checkActive() {
|
|
58
|
+
if (this.isReleased) {
|
|
59
|
+
throw new Error("Connection has been released");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Executes a tagged SQL query using structural caching.
|
|
64
|
+
* Supports recursive fragments and clauses.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const users = await conn.query`SELECT * FROM users WHERE id = ${1}`;
|
|
68
|
+
*/
|
|
69
|
+
async query(strings, ...values) {
|
|
70
|
+
this.checkActive();
|
|
71
|
+
const { text, args } = cacher.cachedBuild(strings, values, 1);
|
|
72
|
+
const result = await this.client.query(text, args);
|
|
73
|
+
return result.rows;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Starts a managed transaction on this connection.
|
|
77
|
+
* Handles automatic COMMIT on success or ROLLBACK on error.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* await conn.begin(async (tx) => {
|
|
81
|
+
* await tx.query`INSERT INTO logs ...`;
|
|
82
|
+
* });
|
|
83
|
+
*/
|
|
84
|
+
async begin(callback) {
|
|
85
|
+
this.checkActive();
|
|
86
|
+
const tx = new transaction_1.Transaction(this);
|
|
87
|
+
try {
|
|
88
|
+
await tx.query `BEGIN`;
|
|
89
|
+
const result = await callback(tx);
|
|
90
|
+
if (tx.isActive)
|
|
91
|
+
await tx.commit();
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
if (tx.isActive)
|
|
96
|
+
await tx.rollback();
|
|
97
|
+
throw err;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.Connection = Connection;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { arrayClause } from "./clauses/array.clause";
|
|
2
|
+
import { fragmentClause } from "./clauses/fragment.clause";
|
|
3
|
+
import { identClause } from "./clauses/iden.caluse";
|
|
4
|
+
import { Pool as PgtxPool } from "./pool";
|
|
5
|
+
import { staticClause } from "./clauses/static.clause";
|
|
6
|
+
import { updateClause } from "./clauses/update.clause";
|
|
7
|
+
import { valueClause } from "./clauses/values.clause";
|
|
8
|
+
/**
|
|
9
|
+
* Core SQL tagging utility for Pgtx.
|
|
10
|
+
* Provides type-safe helpers for building dynamic queries with recursive support.
|
|
11
|
+
*/
|
|
12
|
+
export declare const sql: {
|
|
13
|
+
/**
|
|
14
|
+
* Creates a VALUES clause for INSERT queries.
|
|
15
|
+
* Supports single objects and arrays of objects.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* sql.insert({ name: 'Ivan', age: 25 })
|
|
19
|
+
* // Result: (name, age) VALUES ($1, $2)
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* sql.insert([{ id: 1 }, { id: 2 }])
|
|
23
|
+
* // Result: (id) VALUES ($1), ($2)
|
|
24
|
+
*/
|
|
25
|
+
insert: typeof valueClause;
|
|
26
|
+
/**
|
|
27
|
+
* Generates a SET clause for UPDATE queries from a JavaScript object.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* sql.update({ status: 'active', updated_at: new Date() })
|
|
31
|
+
* // Result: status = $1, updated_at = $2
|
|
32
|
+
*/
|
|
33
|
+
update: typeof updateClause;
|
|
34
|
+
/**
|
|
35
|
+
* Safely escapes SQL identifiers (table or column names) using double quotes.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* sql.ident('users')
|
|
39
|
+
* // Result: "users"
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* sql.ident('table.column')
|
|
43
|
+
* // Result: "table.column"
|
|
44
|
+
*/
|
|
45
|
+
ident: typeof identClause;
|
|
46
|
+
/**
|
|
47
|
+
* Injects raw, unescaped SQL strings.
|
|
48
|
+
* ⚠️ Use with caution to prevent SQL injection!
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* sql.literal('DESC')
|
|
52
|
+
* // Result: DESC
|
|
53
|
+
*/
|
|
54
|
+
literal: typeof staticClause;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a reusable, recursive SQL fragment.
|
|
57
|
+
* Fragments can be nested within each other; argument numbering is handled automatically.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const filter = sql.fragment`age > ${18}`;
|
|
61
|
+
* sql`SELECT * FROM users WHERE ${filter} AND status = ${'active'}`
|
|
62
|
+
* // Result: SELECT * FROM users WHERE age > $1 AND status = $2
|
|
63
|
+
*/
|
|
64
|
+
fragment: typeof fragmentClause;
|
|
65
|
+
/**
|
|
66
|
+
* Formats an array for dynamic lists (IN clauses, column lists, or joined conditions).
|
|
67
|
+
* Supports recursive Clauses (fragments, idents) within the array.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // Case A: IN clause (manual brackets)
|
|
71
|
+
* sql`WHERE id IN (${sql.array([1, 2])})`
|
|
72
|
+
* // Result: WHERE id IN ($1, $2)
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Case B: Dynamic WHERE conditions
|
|
76
|
+
* const conds = [sql.fragment`a = 1`, sql.fragment`b = ${2}`];
|
|
77
|
+
* sql`WHERE ${sql.array(conds, ' AND ')}`
|
|
78
|
+
* // Result: WHERE a = 1 AND b = $1
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Case C: Column list
|
|
82
|
+
* sql`SELECT ${sql.array([sql.ident('id'), sql.ident('name')])}`
|
|
83
|
+
* // Result: SELECT "id", "name"
|
|
84
|
+
*/
|
|
85
|
+
array: typeof arrayClause;
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* Main Pgtx Connection Pool.
|
|
89
|
+
* Manages connections, transactions (including SAVEPOINTs), and prepared statements.
|
|
90
|
+
*/
|
|
91
|
+
export declare const Pool: typeof PgtxPool;
|
|
92
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,GAAG;IACZ;;;;;;;;;;;OAWG;;IAGH;;;;;;OAMG;;IAGH;;;;;;;;;;OAUG;;IAGH;;;;;;;OAOG;;IAGH;;;;;;;;OAQG;;IAGH;;;;;;;;;;;;;;;;;;;OAmBG;;CAEN,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,IAAI,iBAAW,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Pool = exports.sql = void 0;
|
|
4
|
+
const array_clause_1 = require("./clauses/array.clause");
|
|
5
|
+
const fragment_clause_1 = require("./clauses/fragment.clause");
|
|
6
|
+
const iden_caluse_1 = require("./clauses/iden.caluse");
|
|
7
|
+
const pool_1 = require("./pool");
|
|
8
|
+
const static_clause_1 = require("./clauses/static.clause");
|
|
9
|
+
const update_clause_1 = require("./clauses/update.clause");
|
|
10
|
+
const values_clause_1 = require("./clauses/values.clause");
|
|
11
|
+
/**
|
|
12
|
+
* Core SQL tagging utility for Pgtx.
|
|
13
|
+
* Provides type-safe helpers for building dynamic queries with recursive support.
|
|
14
|
+
*/
|
|
15
|
+
exports.sql = {
|
|
16
|
+
/**
|
|
17
|
+
* Creates a VALUES clause for INSERT queries.
|
|
18
|
+
* Supports single objects and arrays of objects.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* sql.insert({ name: 'Ivan', age: 25 })
|
|
22
|
+
* // Result: (name, age) VALUES ($1, $2)
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* sql.insert([{ id: 1 }, { id: 2 }])
|
|
26
|
+
* // Result: (id) VALUES ($1), ($2)
|
|
27
|
+
*/
|
|
28
|
+
insert: values_clause_1.valueClause,
|
|
29
|
+
/**
|
|
30
|
+
* Generates a SET clause for UPDATE queries from a JavaScript object.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* sql.update({ status: 'active', updated_at: new Date() })
|
|
34
|
+
* // Result: status = $1, updated_at = $2
|
|
35
|
+
*/
|
|
36
|
+
update: update_clause_1.updateClause,
|
|
37
|
+
/**
|
|
38
|
+
* Safely escapes SQL identifiers (table or column names) using double quotes.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* sql.ident('users')
|
|
42
|
+
* // Result: "users"
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* sql.ident('table.column')
|
|
46
|
+
* // Result: "table.column"
|
|
47
|
+
*/
|
|
48
|
+
ident: iden_caluse_1.identClause,
|
|
49
|
+
/**
|
|
50
|
+
* Injects raw, unescaped SQL strings.
|
|
51
|
+
* ⚠️ Use with caution to prevent SQL injection!
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* sql.literal('DESC')
|
|
55
|
+
* // Result: DESC
|
|
56
|
+
*/
|
|
57
|
+
literal: static_clause_1.staticClause,
|
|
58
|
+
/**
|
|
59
|
+
* Creates a reusable, recursive SQL fragment.
|
|
60
|
+
* Fragments can be nested within each other; argument numbering is handled automatically.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const filter = sql.fragment`age > ${18}`;
|
|
64
|
+
* sql`SELECT * FROM users WHERE ${filter} AND status = ${'active'}`
|
|
65
|
+
* // Result: SELECT * FROM users WHERE age > $1 AND status = $2
|
|
66
|
+
*/
|
|
67
|
+
fragment: fragment_clause_1.fragmentClause,
|
|
68
|
+
/**
|
|
69
|
+
* Formats an array for dynamic lists (IN clauses, column lists, or joined conditions).
|
|
70
|
+
* Supports recursive Clauses (fragments, idents) within the array.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Case A: IN clause (manual brackets)
|
|
74
|
+
* sql`WHERE id IN (${sql.array([1, 2])})`
|
|
75
|
+
* // Result: WHERE id IN ($1, $2)
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Case B: Dynamic WHERE conditions
|
|
79
|
+
* const conds = [sql.fragment`a = 1`, sql.fragment`b = ${2}`];
|
|
80
|
+
* sql`WHERE ${sql.array(conds, ' AND ')}`
|
|
81
|
+
* // Result: WHERE a = 1 AND b = $1
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* // Case C: Column list
|
|
85
|
+
* sql`SELECT ${sql.array([sql.ident('id'), sql.ident('name')])}`
|
|
86
|
+
* // Result: SELECT "id", "name"
|
|
87
|
+
*/
|
|
88
|
+
array: array_clause_1.arrayClause,
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Main Pgtx Connection Pool.
|
|
92
|
+
* Manages connections, transactions (including SAVEPOINTs), and prepared statements.
|
|
93
|
+
*/
|
|
94
|
+
exports.Pool = pool_1.Pool;
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { QueryResultRow } from "pg";
|
|
2
|
+
import { PoolConfig, PreparedStatement } from "./types";
|
|
3
|
+
import { Connection } from "./connection";
|
|
4
|
+
import { Transaction } from "./transaction";
|
|
5
|
+
/**
|
|
6
|
+
* The main entry point for Pgtx.
|
|
7
|
+
* Manages a connection pool and provides high-level API for queries and transactions.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Pool {
|
|
10
|
+
private pool;
|
|
11
|
+
constructor(config: PoolConfig);
|
|
12
|
+
/**
|
|
13
|
+
* Executes a one-off query.
|
|
14
|
+
* Automatically acquires and releases a connection from the pool.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`;
|
|
18
|
+
*/
|
|
19
|
+
query<T extends QueryResultRow>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a reusable prepared statement.
|
|
22
|
+
* When executed via `stmt.execute()`, it automatically manages its own connection.
|
|
23
|
+
* Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* const stmt = await pool.prepare<User, [string]>('get_user', 'SELECT * FROM users WHERE email = ?');
|
|
27
|
+
* const users = await stmt.execute('test@example.com');
|
|
28
|
+
*/
|
|
29
|
+
prepare<TResult extends QueryResultRow = any, TParams extends any[] = any[]>(name: string, sqlTemplate: string): Promise<PreparedStatement<TResult, TParams>>;
|
|
30
|
+
/**
|
|
31
|
+
* Acquires a dedicated connection from the pool.
|
|
32
|
+
* **Note:** You must call `connection.release()` manually when finished.
|
|
33
|
+
*/
|
|
34
|
+
acquire(): Promise<Connection>;
|
|
35
|
+
/**
|
|
36
|
+
* Starts a managed transaction.
|
|
37
|
+
* Automatically acquires a connection and handles BEGIN/COMMIT/ROLLBACK.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const result = await pool.begin(async (tx) => {
|
|
41
|
+
* await tx.query`INSERT INTO accounts ...`;
|
|
42
|
+
* return "success";
|
|
43
|
+
* });
|
|
44
|
+
*/
|
|
45
|
+
begin<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Returns current pool utilization statistics.
|
|
48
|
+
*/
|
|
49
|
+
get stats(): {
|
|
50
|
+
total: number;
|
|
51
|
+
idle: number;
|
|
52
|
+
waiting: number;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Shuts down the pool and closes all active connections.
|
|
56
|
+
*/
|
|
57
|
+
close(): Promise<void>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,cAAc,EAAC,MAAM,IAAI,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAE3C;;;GAGG;AACH,qBAAa,IAAI;IACb,OAAO,CAAC,IAAI,CAAQ;gBAGhB,MAAM,EAAE,UAAU;IAKtB;;;;;;OAMG;IACU,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAc5F;;;;;;;;OAQG;IACU,OAAO,CAAC,OAAO,SAAS,cAAc,GAAG,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,EACpF,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GACpB,OAAO,CAAC,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAyB/C;;;OAGG;IACU,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC;IAK3C;;;;;;;;;OASG;IACU,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAc5E;;OAEG;IACH,IAAW,KAAK;;;;MAMf;IAED;;OAEG;IACI,KAAK;CAGf"}
|
package/dist/pool.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Pool = void 0;
|
|
4
|
+
const pg_1 = require("pg");
|
|
5
|
+
const connection_1 = require("./connection");
|
|
6
|
+
/**
|
|
7
|
+
* The main entry point for Pgtx.
|
|
8
|
+
* Manages a connection pool and provides high-level API for queries and transactions.
|
|
9
|
+
*/
|
|
10
|
+
class Pool {
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.pool = new pg_1.Pool(config);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Executes a one-off query.
|
|
16
|
+
* Automatically acquires and releases a connection from the pool.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const users = await pool.query<User>`SELECT * FROM users WHERE id = ${1}`;
|
|
20
|
+
*/
|
|
21
|
+
async query(strings, ...values) {
|
|
22
|
+
const conn = await this.acquire();
|
|
23
|
+
try {
|
|
24
|
+
return await conn.query(strings, ...values);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
conn.release();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a reusable prepared statement.
|
|
35
|
+
* When executed via `stmt.execute()`, it automatically manages its own connection.
|
|
36
|
+
* Maps '?' placeholders to native PostgreSQL '$1, $2' indexes.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const stmt = await pool.prepare<User, [string]>('get_user', 'SELECT * FROM users WHERE email = ?');
|
|
40
|
+
* const users = await stmt.execute('test@example.com');
|
|
41
|
+
*/
|
|
42
|
+
async prepare(name, sqlTemplate) {
|
|
43
|
+
let index = 1;
|
|
44
|
+
const text = sqlTemplate.replace(/\?/g, () => `$${index++}`);
|
|
45
|
+
return {
|
|
46
|
+
text,
|
|
47
|
+
name,
|
|
48
|
+
execute: async (...args) => {
|
|
49
|
+
const conn = await this.acquire();
|
|
50
|
+
conn['checkActive']();
|
|
51
|
+
try {
|
|
52
|
+
const result = await conn['client'].query({
|
|
53
|
+
name,
|
|
54
|
+
text,
|
|
55
|
+
values: args
|
|
56
|
+
});
|
|
57
|
+
return result.rows;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
conn.release();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Acquires a dedicated connection from the pool.
|
|
67
|
+
* **Note:** You must call `connection.release()` manually when finished.
|
|
68
|
+
*/
|
|
69
|
+
async acquire() {
|
|
70
|
+
const client = await this.pool.connect();
|
|
71
|
+
return new connection_1.Connection(client);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Starts a managed transaction.
|
|
75
|
+
* Automatically acquires a connection and handles BEGIN/COMMIT/ROLLBACK.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const result = await pool.begin(async (tx) => {
|
|
79
|
+
* await tx.query`INSERT INTO accounts ...`;
|
|
80
|
+
* return "success";
|
|
81
|
+
* });
|
|
82
|
+
*/
|
|
83
|
+
async begin(callback) {
|
|
84
|
+
const conn = await this.acquire();
|
|
85
|
+
try {
|
|
86
|
+
return await conn.begin(callback);
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
conn.release();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Returns current pool utilization statistics.
|
|
97
|
+
*/
|
|
98
|
+
get stats() {
|
|
99
|
+
return {
|
|
100
|
+
total: this.pool.totalCount,
|
|
101
|
+
idle: this.pool.idleCount,
|
|
102
|
+
waiting: this.pool.waitingCount
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Shuts down the pool and closes all active connections.
|
|
107
|
+
*/
|
|
108
|
+
close() {
|
|
109
|
+
return this.pool.end();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.Pool = Pool;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.cacher.d.ts","sourceRoot":"","sources":["../src/query.cacher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAsB,MAAM,SAAS,CAAC;AAG/D,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyE;IAExF,WAAW,CAAC,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB;CAezG"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueryCacher = void 0;
|
|
4
|
+
const base_clause_1 = require("./clauses/base.clause");
|
|
5
|
+
const utils_1 = require("./utils");
|
|
6
|
+
class QueryCacher {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.cache = new WeakMap();
|
|
9
|
+
}
|
|
10
|
+
cachedBuild(strings, values, argCounter) {
|
|
11
|
+
const cached = this.cache.get(strings);
|
|
12
|
+
if (cached?.isStatic) {
|
|
13
|
+
return { text: cached.text, args: values, argCounter };
|
|
14
|
+
}
|
|
15
|
+
const result = (0, utils_1.compileSqlTemplate)(strings, values, 1);
|
|
16
|
+
if (!cached) {
|
|
17
|
+
const isStatic = !values.some(value => value instanceof base_clause_1.Clause);
|
|
18
|
+
this.cache.set(strings, { text: result.text, isStatic });
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.QueryCacher = QueryCacher;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { QueryResultRow } from "pg";
|
|
2
|
+
import { Connection } from "./connection";
|
|
3
|
+
/**
|
|
4
|
+
* Represents an active SQL transaction.
|
|
5
|
+
* All queries are executed on a single dedicated connection.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Transaction {
|
|
8
|
+
readonly conn: Connection;
|
|
9
|
+
private isFinished;
|
|
10
|
+
constructor(conn: Connection);
|
|
11
|
+
/**
|
|
12
|
+
* Returns true if the transaction is still open (not committed or rolled back).
|
|
13
|
+
*/
|
|
14
|
+
get isActive(): boolean;
|
|
15
|
+
private checkActive;
|
|
16
|
+
/**
|
|
17
|
+
* Commits the current transaction.
|
|
18
|
+
*/
|
|
19
|
+
commit(): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Rolls back the current transaction.
|
|
22
|
+
*/
|
|
23
|
+
rollback(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Executes a query within the current transaction.
|
|
26
|
+
*/
|
|
27
|
+
query<T extends QueryResultRow = any>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
30
|
+
* If the callback throws, only the actions within this savepoint are rolled back.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* await tx.savepoint('my_point', async (stx) => {
|
|
34
|
+
* await stx.query`INSERT ...`;
|
|
35
|
+
* if (error) throw new Error(); // Only this insert rolls back
|
|
36
|
+
* });
|
|
37
|
+
*/
|
|
38
|
+
savepoint(name: string, callback: (tx: Transaction) => Promise<void>): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAIzC;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC;;OAEG;IACU,KAAK,CAAC,CAAC,SAAS,cAAc,GAAG,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAKjH;;;;;;;;;OASG;IACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAcpG"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Transaction = void 0;
|
|
4
|
+
const iden_caluse_1 = require("./clauses/iden.caluse");
|
|
5
|
+
/**
|
|
6
|
+
* Represents an active SQL transaction.
|
|
7
|
+
* All queries are executed on a single dedicated connection.
|
|
8
|
+
*/
|
|
9
|
+
class Transaction {
|
|
10
|
+
constructor(conn) {
|
|
11
|
+
this.conn = conn;
|
|
12
|
+
this.isFinished = false;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns true if the transaction is still open (not committed or rolled back).
|
|
16
|
+
*/
|
|
17
|
+
get isActive() {
|
|
18
|
+
return !this.isFinished;
|
|
19
|
+
}
|
|
20
|
+
checkActive() {
|
|
21
|
+
if (this.isFinished) {
|
|
22
|
+
throw new Error("Transaction is finished");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Commits the current transaction.
|
|
27
|
+
*/
|
|
28
|
+
async commit() {
|
|
29
|
+
this.checkActive();
|
|
30
|
+
await this.conn.query `COMMIT`;
|
|
31
|
+
this.isFinished = true;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Rolls back the current transaction.
|
|
35
|
+
*/
|
|
36
|
+
async rollback() {
|
|
37
|
+
this.checkActive();
|
|
38
|
+
await this.conn.query `ROLLBACK`;
|
|
39
|
+
this.isFinished = true;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Executes a query within the current transaction.
|
|
43
|
+
*/
|
|
44
|
+
async query(strings, ...values) {
|
|
45
|
+
this.checkActive();
|
|
46
|
+
return await this.conn.query(strings, ...values);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
50
|
+
* If the callback throws, only the actions within this savepoint are rolled back.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* await tx.savepoint('my_point', async (stx) => {
|
|
54
|
+
* await stx.query`INSERT ...`;
|
|
55
|
+
* if (error) throw new Error(); // Only this insert rolls back
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
async savepoint(name, callback) {
|
|
59
|
+
this.checkActive();
|
|
60
|
+
await this.conn.query `SAVEPOINT ${(0, iden_caluse_1.identClause)(name)}`;
|
|
61
|
+
try {
|
|
62
|
+
await callback(this);
|
|
63
|
+
await this.conn.query `RELEASE SAVEPOINT ${(0, iden_caluse_1.identClause)(name)}`;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
await this.conn.query `ROLLBACK TO SAVEPOINT ${(0, iden_caluse_1.identClause)(name)}`;
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.Transaction = Transaction;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { PoolConfig as PgPoolConfig } from "pg";
|
|
2
|
+
export type PoolConfig = PgPoolConfig;
|
|
3
|
+
export type PreparedStatement<TResult extends any, Tparams extends any[]> = {
|
|
4
|
+
text: string;
|
|
5
|
+
name: string;
|
|
6
|
+
execute: (...args: Tparams) => Promise<TResult[]>;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,YAAY,EAAE,MAAM,IAAI,CAAA;AAE/C,MAAM,MAAM,UAAU,GAAG,YAAY,CAAA;AAErC,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,IAAI;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CACpD,CAAA"}
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,oBAAoB,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAyBrH"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileSqlTemplate = compileSqlTemplate;
|
|
4
|
+
const base_clause_1 = require("./clauses/base.clause");
|
|
5
|
+
function compileSqlTemplate(strings, values, argCounter) {
|
|
6
|
+
const templateLength = strings.length;
|
|
7
|
+
let text = '';
|
|
8
|
+
let args = [];
|
|
9
|
+
strings.forEach((template, index) => {
|
|
10
|
+
text += template;
|
|
11
|
+
if (index === templateLength - 1)
|
|
12
|
+
return;
|
|
13
|
+
const value = values[index];
|
|
14
|
+
if (value instanceof base_clause_1.Clause) {
|
|
15
|
+
const result = value.map(argCounter);
|
|
16
|
+
argCounter = result.argCounter;
|
|
17
|
+
text += result.text;
|
|
18
|
+
args.push(...result.args);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
args.push(value);
|
|
22
|
+
text += `$${argCounter}`;
|
|
23
|
+
argCounter++;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return { text, args, argCounter };
|
|
27
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@m2k-5f/pgtx",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Lightweight, high-performance SQL toolkit for node-postgres",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["sql", "postgres", "pg", "query-builder", "typescript", "transactions", "prepared-statements"],
|
|
16
|
+
"author": "M2K-5F",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"pg": "^8.11.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/pg": "^8.11.0",
|
|
23
|
+
"typescript": "^5.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|