node-firebird 2.6.0 → 2.7.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.
@@ -226,10 +226,10 @@ class XdrWriter {
226
226
  }
227
227
  addInt64(value) {
228
228
  this.ensure(8);
229
- // Note: precision is limited to Number.MAX_SAFE_INTEGER (±2^53-1).
230
- // Values outside this range lose precision, which matches the previous
231
- // Long.fromNumber() behaviour.
232
- this.buffer.writeBigInt64BE(BigInt(Math.trunc(value)), this.pos);
229
+ // Note: for numbers, precision is limited to Number.MAX_SAFE_INTEGER
230
+ // (±2^53-1); values outside this range lose precision, which matches
231
+ // the previous Long.fromNumber() behaviour. BigInts keep full precision.
232
+ this.buffer.writeBigInt64BE(typeof value === 'bigint' ? value : BigInt(Math.trunc(value)), this.pos);
233
233
  this.pos += 8;
234
234
  }
235
235
  addInt128(value) {
@@ -306,6 +306,11 @@ class XdrWriter {
306
306
  this.buffer.writeDoubleBE(value, this.pos);
307
307
  this.pos += 8;
308
308
  }
309
+ addFloat(value) {
310
+ this.ensure(4);
311
+ this.buffer.writeFloatBE(value, this.pos);
312
+ this.pos += 4;
313
+ }
309
314
  addQuad(quad) {
310
315
  this.ensure(8);
311
316
  var b = this.buffer;
@@ -21,7 +21,13 @@ declare class Statement {
21
21
  fetch(transaction: any, count: number | string, callback: (err: any, result?: any) => void): void;
22
22
  fetchScroll(transaction: any, direction: string | number, offset?: any, count?: any, callback?: any): void;
23
23
  fetchAll(transaction: any, callback: (err: any, result?: any) => void): void;
24
+ /**
25
+ * Execute this statement once per row via the Firebird 4 batch API
26
+ * (protocol 16+). `rows` is an array of parameter arrays.
27
+ */
28
+ executeBatch(transaction: any, rows: any[][], callback?: any, options?: any): void;
24
29
  executeAsync(transaction: any, params?: any, options?: any): Promise<any>;
30
+ executeBatchAsync(transaction: any, rows: any[][], options?: any): Promise<any>;
25
31
  fetchAsync(transaction: any, count: number | string): Promise<any>;
26
32
  fetchScrollAsync(transaction: any, direction: string | number, offset?: any, count?: any): Promise<any>;
27
33
  fetchAllAsync(transaction: any): Promise<any>;
@@ -49,11 +49,22 @@ class Statement {
49
49
  fetchAll(transaction, callback) {
50
50
  this.connection.fetchAll(this, transaction, callback);
51
51
  }
52
+ /**
53
+ * Execute this statement once per row via the Firebird 4 batch API
54
+ * (protocol 16+). `rows` is an array of parameter arrays.
55
+ */
56
+ executeBatch(transaction, rows, callback, options) {
57
+ this.connection.executeBatch(transaction, this, rows, callback, options);
58
+ }
52
59
  /* Promise / async-await API — wrappers over the callback methods above. */
53
60
  executeAsync(transaction, params, options) {
54
61
  var self = this;
55
62
  return (0, callback_1.fromCallback)(function (cb) { self.execute(transaction, params, cb, options); });
56
63
  }
64
+ executeBatchAsync(transaction, rows, options) {
65
+ var self = this;
66
+ return (0, callback_1.fromCallback)(function (cb) { self.executeBatch(transaction, rows, cb, options); });
67
+ }
57
68
  fetchAsync(transaction, count) {
58
69
  var self = this;
59
70
  return (0, callback_1.fromCallback)(function (cb) { self.fetch(transaction, count, cb); });
@@ -8,6 +8,17 @@ declare class Transaction {
8
8
  execute(query: string, params?: any, callback?: any, options?: any): void;
9
9
  sequentially(query: string, params?: any, on?: any, callback?: any, options?: any): this;
10
10
  query(query: string, params?: any, callback?: any, options?: any): void;
11
+ /**
12
+ * Execute `query` once per row in `rows` using the Firebird 4 batch API
13
+ * (protocol 16+, single network flush). The callback receives a
14
+ * completion object: { recordCount, updateCounts, errors:
15
+ * [{recordNumber, error}], errorRecordNumbers, success }. Per-record
16
+ * failures do NOT roll anything back here — inspect the completion and
17
+ * commit or roll back yourself (or use db.executeBatch for
18
+ * all-or-nothing semantics).
19
+ */
20
+ executeBatch(query: string, rows: any[][], callback?: any, options?: any): void;
21
+ executeBatchAsync(query: string, rows: any[][], options?: any): Promise<any>;
11
22
  commit(callback?: (err?: any) => void): void;
12
23
  rollback(callback?: (err?: any) => void): void;
13
24
  commitRetaining(callback?: (err?: any) => void): void;
@@ -200,6 +200,33 @@ class Transaction {
200
200
  };
201
201
  this.execute(query, params, callback, options);
202
202
  }
203
+ /**
204
+ * Execute `query` once per row in `rows` using the Firebird 4 batch API
205
+ * (protocol 16+, single network flush). The callback receives a
206
+ * completion object: { recordCount, updateCounts, errors:
207
+ * [{recordNumber, error}], errorRecordNumbers, success }. Per-record
208
+ * failures do NOT roll anything back here — inspect the completion and
209
+ * commit or roll back yourself (or use db.executeBatch for
210
+ * all-or-nothing semantics).
211
+ */
212
+ executeBatch(query, rows, callback, options) {
213
+ var self = this;
214
+ this.newStatement(query, function (err, statement) {
215
+ if (err) {
216
+ (0, callback_1.doError)(err, callback);
217
+ return;
218
+ }
219
+ statement.executeBatch(self, rows, function (err, result) {
220
+ statement.release();
221
+ if (callback)
222
+ callback(err, result);
223
+ }, options);
224
+ });
225
+ }
226
+ executeBatchAsync(query, rows, options) {
227
+ var self = this;
228
+ return (0, callback_1.fromCallback)(function (cb) { self.executeBatch(query, rows, cb, options); });
229
+ }
203
230
  commit(callback) {
204
231
  this.connection.commit(this, callback);
205
232
  }
@@ -155,6 +155,15 @@ export declare class SQLParamBuffer {
155
155
  encode(data: XdrWriter): void;
156
156
  calcBlr(blr: BlrWriter): void;
157
157
  }
158
+ /**
159
+ * Split a JS Date into the Firebird wire representation used by
160
+ * TIMESTAMP/DATE/TIME columns: `date` is the modified-Julian day number and
161
+ * `time` the count of 100-microsecond units since midnight (local time).
162
+ */
163
+ export declare function encodeDateTimeParts(value: Date): {
164
+ date: number;
165
+ time: number;
166
+ };
158
167
  export declare class SQLParamQuad {
159
168
  value: any;
160
169
  constructor(value: any);
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SQLParamBool = exports.SQLParamDate = exports.SQLParamQuad = exports.SQLParamBuffer = exports.SQLParamString = exports.SQLParamDouble = exports.SQLParamDecFloat34 = exports.SQLParamDecFloat16 = exports.SQLParamInt128 = exports.SQLParamInt64 = exports.SQLParamInt = exports.SQLVarBoolean = exports.SQLVarTimeStampTzEx = exports.SQLVarTimeStampTz = exports.SQLVarTimeTzEx = exports.SQLVarTimeTz = exports.SQLVarTimeStamp = exports.SQLVarTime = exports.SQLVarDate = exports.SQLVarDouble = exports.SQLVarFloat = exports.SQLVarDecFloat34 = exports.SQLVarDecFloat16 = exports.SQLVarInt128 = exports.SQLVarInt64 = exports.SQLVarShort = exports.SQLVarInt = exports.SQLVarArray = exports.SQLVarBlob = exports.SQLVarQuad = exports.SQLVarString = exports.SQLVarNull = exports.SQLVarText = exports.SQLVarBase = void 0;
7
+ exports.encodeDateTimeParts = encodeDateTimeParts;
7
8
  const const_1 = __importDefault(require("./const"));
8
9
  /***************************************
9
10
  *
@@ -593,6 +594,24 @@ class SQLParamBuffer {
593
594
  }
594
595
  exports.SQLParamBuffer = SQLParamBuffer;
595
596
  //------------------------------------------------------
597
+ /**
598
+ * Split a JS Date into the Firebird wire representation used by
599
+ * TIMESTAMP/DATE/TIME columns: `date` is the modified-Julian day number and
600
+ * `time` the count of 100-microsecond units since midnight (local time).
601
+ */
602
+ function encodeDateTimeParts(value) {
603
+ var ms = value.getTime() - value.getTimezoneOffset() * MsPerMinute;
604
+ var time = ms % TimeCoeff;
605
+ var date = (ms - time) / TimeCoeff + DateOffset;
606
+ time *= 10;
607
+ // check overflow (dates before the epoch)
608
+ if (time < 0) {
609
+ date--;
610
+ time = TimeCoeff * 10 + time;
611
+ }
612
+ return { date: date, time: time };
613
+ }
614
+ //------------------------------------------------------
596
615
  class SQLParamQuad {
597
616
  constructor(value) {
598
617
  this.value = value;
@@ -621,17 +640,9 @@ class SQLParamDate {
621
640
  }
622
641
  encode(data) {
623
642
  if (this.value != null) {
624
- var value = this.value.getTime() - this.value.getTimezoneOffset() * MsPerMinute;
625
- var time = value % TimeCoeff;
626
- var date = (value - time) / TimeCoeff + DateOffset;
627
- time *= 10;
628
- // check overflow
629
- if (time < 0) {
630
- date--;
631
- time = TimeCoeff * 10 + time;
632
- }
633
- data.addInt(date);
634
- data.addUInt(time);
643
+ var parts = encodeDateTimeParts(this.value);
644
+ data.addInt(parts.date);
645
+ data.addUInt(parts.time);
635
646
  }
636
647
  else {
637
648
  data.addInt(0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-firebird",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Pure JavaScript and Asynchronous Firebird client for Node.js.",
5
5
  "keywords": [
6
6
  "firebird",
package/src/types.ts CHANGED
@@ -75,6 +75,31 @@ export type TransactionOptions = {
75
75
  waitTimeout?: number;
76
76
  };
77
77
 
78
+ /** Result of an executeBatch call (Firebird 4 batch API, protocol 16+). */
79
+ export interface BatchResult {
80
+ /** Total number of records processed by the server. */
81
+ recordCount: number;
82
+ /** Per-record update counts (in record order). */
83
+ updateCounts: number[];
84
+ /** Per-record failures with full status vectors (capped by `detailedErrors`). */
85
+ errors: Array<{ recordNumber: number; error: Error }>;
86
+ /** Record numbers of ALL failed records (detailed + status-less). */
87
+ errorRecordNumbers: number[];
88
+ /** True when every record executed without error. */
89
+ success: boolean;
90
+ }
91
+
92
+ export type BatchOptions = {
93
+ /** Continue past per-record errors and report them all (default true). */
94
+ multiError?: boolean;
95
+ /** Server-side batch buffer limit in bytes (BATCH_TAG_BUFFER_BYTES_SIZE). */
96
+ bufferSize?: number;
97
+ /** Max number of detailed per-record status vectors returned (server default 64). */
98
+ detailedErrors?: number;
99
+ /** Rows per op_batch_msg packet (default 500). */
100
+ chunkSize?: number;
101
+ };
102
+
78
103
  export type QueryOptions = {
79
104
  timeout?: number;
80
105
  scrollable?: boolean;
@@ -95,6 +120,8 @@ export interface Database {
95
120
  newStatement(query: string, callback: (err: Error | null, statement: Statement) => void): Database;
96
121
  query(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): Database;
97
122
  execute(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): Database;
123
+ /** Bulk-execute in its own transaction, all-or-nothing (Firebird 4.0+). */
124
+ executeBatch(query: string, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): Database;
98
125
  sequentially(query: string, params: any[], rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
99
126
  drop(callback: SimpleCallback): void;
100
127
  escape(value: any): string;
@@ -108,6 +135,7 @@ export interface Database {
108
135
  // Result metadata is only available through the callback API.
109
136
  queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
110
137
  executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
138
+ executeBatchAsync(query: string, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
111
139
  sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
112
140
  sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
113
141
  transactionAsync(options?: TransactionOptions | Isolation): Promise<Transaction>;
@@ -132,6 +160,8 @@ export interface Transaction {
132
160
  newStatement(query: string, callback: (err: Error | null, statement: Statement) => void): void;
133
161
  query(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): void;
134
162
  execute(query: string, params: any[], callback: QueryCallback, options?: QueryOptions): void;
163
+ /** Bulk-execute within this transaction; per-record failures do not roll back (Firebird 4.0+). */
164
+ executeBatch(query: string, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): void;
135
165
  sequentially(query: string, params: any[], rowCallback: SequentialCallback, callback: SimpleCallback, options?: QueryOptions | boolean): Database;
136
166
  commit(callback?: SimpleCallback): void;
137
167
  commitRetaining(callback?: SimpleCallback): void;
@@ -141,6 +171,7 @@ export interface Transaction {
141
171
  // Promise / async-await API
142
172
  queryAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
143
173
  executeAsync<T = any>(query: string, params?: any[], options?: QueryOptions): Promise<T[]>;
174
+ executeBatchAsync(query: string, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
144
175
  sequentiallyAsync(query: string, params: any[] | undefined, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
145
176
  sequentiallyAsync(query: string, rowCallback: SequentialCallback, options?: QueryOptions | boolean): Promise<void>;
146
177
  newStatementAsync(query: string): Promise<Statement>;
@@ -159,8 +190,12 @@ export interface Statement {
159
190
  fetchScroll(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset: number, count: number, callback: QueryCallback): void;
160
191
  fetchAll(transaction: Transaction, callback: QueryCallback): void;
161
192
 
193
+ /** Execute this prepared statement once per row (Firebird 4.0+ batch API). */
194
+ executeBatch(transaction: Transaction, rows: any[][], callback?: (err: any, result: BatchResult) => void, options?: BatchOptions): void;
195
+
162
196
  // Promise / async-await API
163
197
  executeAsync(transaction: Transaction, params?: any[], options?: QueryOptions): Promise<any>;
198
+ executeBatchAsync(transaction: Transaction, rows: any[][], options?: BatchOptions): Promise<BatchResult>;
164
199
  fetchAsync(transaction: Transaction, count: number | 'all'): Promise<any>;
165
200
  fetchScrollAsync(transaction: Transaction, direction: 'NEXT' | 'PRIOR' | 'FIRST' | 'LAST' | 'ABSOLUTE' | 'RELATIVE' | number, offset?: number, count?: number): Promise<any>;
166
201
  fetchAllAsync(transaction: Transaction): Promise<any>;