diff --git a/select-builder-pgsql.js b/select-builder-pgsql.js index 7108efd..d64465d 100644 --- a/select-builder-pgsql.js +++ b/select-builder-pgsql.js @@ -1,6 +1,6 @@ // Простенький "селект билдер" по мотивам MediaWiki-овского, успешно юзаю подобный в PHP уже лет 8 // (c) Виталий Филиппов, 2019-2021 -// Версия 2021-09-16 +// Версия 2021-11-24 // В PHP, правда, прикольнее - там в массиве можно смешивать строковые и численные ключи, // благодаря чему можно писать $where = [ 't1.a=t2.a', 't2.b' => [ 1, 2, 3 ] ] @@ -213,8 +213,15 @@ function where_in(key, values, result, bind, for_where) { throw new Error('IN syntax can only be used inside WHERE'); } - result.push(key+' = ?'); - bind.push(values[0]); + if (values[0] instanceof Text) + { + push_text(result, bind, new Text(key+' = '+values[0].sql, values[0].bind)); + } + else + { + result.push(key+' = ?'); + bind.push(values[0]); + } } else { @@ -236,6 +243,18 @@ function where_in(key, values, result, bind, for_where) } } +function push_text(where, bind, v) +{ + if (v instanceof Text) + { + where.push(v.sql); + for (let i = 0; i < v.bind.length; i++) + bind.push(v.bind[i]); + } + else + where.push(v); +} + // fields: one of: // - string: 'a=b AND c=d' // - array: [ 'a=b', [ 'a=? or b=?', 1, 2 ], [ 'a', [ 1, 2 ] ] ] @@ -254,10 +273,14 @@ function where_or_set(fields, for_where) for (let k in fields) { let v = fields[k]; - v = v instanceof Array ? v : [ v ]; if (/^\d+$/.exec(k)) { - if (v.length == 0 || typeof v[0] !== 'string') + if (!(v instanceof Array)) + { + push_text(where, bind, v); + continue; + } + else if (v.length == 0 || typeof v[0] !== 'string') { // invalid value continue; @@ -265,7 +288,7 @@ function where_or_set(fields, for_where) else if (v.length == 1) { // [ text ] or just text - where.push(v[0]); + push_text(where, bind, v[0]); } else if (v[0].indexOf('?') >= 0) { @@ -288,6 +311,10 @@ function where_or_set(fields, for_where) } else { + if (!(v instanceof Array)) + { + v = [ v ]; + } if (k.indexOf('?') >= 0 || v.length == 0) { // { expr: [ bind ] } @@ -701,7 +728,7 @@ class Connection extends ConnectionBase async begin() { - if (this.in_transaction) + while (this.in_transaction) { // Если уже кто-то активен - ждём его await new Promise((resolve, reject) => this.transaction_queue.push(resolve)); @@ -711,18 +738,39 @@ class Connection extends ConnectionBase return this.in_transaction; } + async txn(cb) + { + let r; + const txn = await this.begin(); + try + { + r = await cb(txn); + await txn.commit(); + } + catch (e) + { + await txn.rollback(); + throw e; + } + return r; + } + async query(sql, bind) { if (sql.length == 5 && sql.toLowerCase() == 'begin') { throw new Error('Do not use transactions in asynchronous code directly!'); } - if (this.in_transaction) + while (this.in_transaction) { // Если уже кто-то активен - ждём его await new Promise((resolve, reject) => this.transaction_queue.push(resolve)); } + if (!this.dbh) + await this.connect(); + this.in_transaction = true; const r = await this._query(sql, bind); + this.in_transaction = null; // Если есть ещё кто-то в очереди - пусть проходит this._next_txn(); return r; @@ -734,7 +782,7 @@ class Connection extends ConnectionBase { return; } - if (this.in_transaction) + while (this.in_transaction) { // Если уже кто-то активен - ждём его await new Promise((resolve, reject) => this.transaction_queue.push(resolve)); @@ -753,9 +801,6 @@ class Connection extends ConnectionBase async _query(sql, bind) { - const do_lock = !this.in_transaction; - if (!this.dbh) - await this.connect(); if (this.in_transaction && this.connection_lost) { this._next_txn(); @@ -770,8 +815,6 @@ class Connection extends ConnectionBase { start_time = Date.now(); } - if (do_lock) - this._in_transaction = true; const r = await this.dbh.query(sql); if (this.config.log_queries) { @@ -828,6 +871,11 @@ class Transaction extends ConnectionBase return this; } + async txn(cb) + { + return await cb(this); + } + async commit() { if (this.nested > 0) @@ -873,6 +921,7 @@ class Transaction extends ConnectionBase module.exports = { select_builder, where_builder, + where_or_set, quote, quote_into: _inline, select,