@@ -9,9 +9,10 @@ import {
99 CrateDBBaseResponse ,
1010 CrateDBResponse ,
1111 CrateDBBulkResponse ,
12- CrateDBBulkRecord ,
1312 CrateDBRecord ,
13+ CrateDBErrorResponse ,
1414} from './interfaces' ;
15+ import { CrateDBError , DeserializationError , RequestError } from './utils/Error.js' ;
1516
1617// Configuration options with CrateDB-specific environment variables
1718const defaultConfig : CrateDBConfig = {
@@ -105,43 +106,60 @@ export class CrateDBClient {
105106 }
106107 }
107108
108- async execute ( stmt : string , args : unknown [ ] = [ ] ) : Promise < CrateDBResponse > {
109- return await this . _execute ( stmt , args ) ;
110- }
109+ async execute ( stmt : string , args ?: unknown [ ] ) : Promise < CrateDBResponse > {
110+ const startRequestTime = Date . now ( ) ;
111+ const payload = args ? { stmt, args } : { stmt } ;
112+ let body : string ;
113+ try {
114+ body = Serializer . serialize ( payload ) ;
115+ } catch ( serializationError : unknown ) {
116+ const msg = serializationError instanceof Error ? serializationError . message : String ( serializationError ) ;
117+ throw new RequestError ( `Serialization failed: ${ msg } ` ) ;
118+ }
111119
112- async executeMany ( stmt : string , bulk_args : unknown [ ] [ ] ) : Promise < CrateDBBulkResponse > {
113- const res : CrateDBBulkResponse = await this . _execute ( stmt , null , bulk_args ) ;
114- const results : Array < CrateDBBulkRecord > = res . results || [ ] ;
115- const bulk_errors = results . map ( ( result , i ) => ( result . rowcount === - 2 ? i : null ) ) . filter ( ( i ) => i !== null ) ;
120+ const options = { ...this . httpOptions , body } ;
116121
117- if ( bulk_errors . length > 0 ) {
118- res . bulk_errors = bulk_errors ;
122+ try {
123+ const response = await this . _makeRequest ( options ) ;
124+ return this . _addDurations ( startRequestTime , response ) as CrateDBResponse ;
125+ } catch ( error : unknown ) {
126+ if ( error instanceof CrateDBError || error instanceof DeserializationError ) {
127+ throw error ;
128+ } else if ( error instanceof Error ) {
129+ throw new RequestError ( `CrateDB request failed: ${ error . message } ` , { cause : error } ) ;
130+ }
131+ throw new RequestError ( 'CrateDB request failed with an unknown error' ) ;
119132 }
120- return res ;
121133 }
122134
123- private async _execute (
124- stmt : string ,
125- args : unknown [ ] | null = null ,
126- bulk_args : unknown [ ] [ ] | null = null
127- ) : Promise < CrateDBBaseResponse > {
135+ async executeMany ( stmt : string , bulk_args : unknown [ ] [ ] ) : Promise < CrateDBBulkResponse > {
128136 const startRequestTime = Date . now ( ) ;
129- const body = Serializer . serialize ( args ? { stmt, args } : { stmt, bulk_args } ) ;
137+ let body : string ;
138+ try {
139+ body = Serializer . serialize ( { stmt, bulk_args } ) ;
140+ } catch ( serializationError : unknown ) {
141+ const msg = serializationError instanceof Error ? serializationError . message : String ( serializationError ) ;
142+ throw new RequestError ( `Serialization failed: ${ msg } ` ) ;
143+ }
144+
130145 const options = { ...this . httpOptions , body } ;
131- const response = await this . _makeRequest ( options ) ;
132- const totalRequestTime = Date . now ( ) - startRequestTime ;
133- if ( typeof response . duration === 'number' ) {
134- response . durations = {
135- cratedb : response . duration ,
136- request : totalRequestTime - response . duration ,
137- } ;
138- } else {
139- response . durations = {
140- cratedb : 0 ,
141- request : totalRequestTime ,
142- } ;
146+
147+ try {
148+ const response = await this . _makeRequest ( options ) ;
149+ const res = this . _addDurations ( startRequestTime , response ) as CrateDBBulkResponse ;
150+ // Mark bulk errors for each result where rowcount is -2
151+ res . bulk_errors = ( res . results || [ ] )
152+ . map ( ( result , i ) => ( result . rowcount === - 2 ? i : null ) )
153+ . filter ( ( i ) => i !== null ) ;
154+ return res ;
155+ } catch ( error : unknown ) {
156+ if ( error instanceof CrateDBError || error instanceof DeserializationError ) {
157+ throw error ;
158+ } else if ( error instanceof Error ) {
159+ throw new RequestError ( `CrateDB bulk request failed: ${ error . message } ` , { cause : error } ) ;
160+ }
161+ throw new RequestError ( 'CrateDB bulk request failed with an unknown error' ) ;
143162 }
144- return response ;
145163 }
146164
147165 // Convenience methods for common SQL operations
@@ -182,7 +200,7 @@ export class CrateDBClient {
182200 const args = Object . values ( obj ) ;
183201
184202 // Execute the query
185- return await this . execute ( query , args ) ;
203+ return this . execute ( query , args ) ;
186204 }
187205
188206 async insertMany (
@@ -229,22 +247,22 @@ export class CrateDBClient {
229247 const { keys, values, args } = this . _prepareOptions ( options ) ;
230248 const setClause = keys . map ( ( key , i ) => `${ key } =${ values [ i ] } ` ) . join ( ', ' ) ;
231249 const query = `UPDATE ${ tableName } SET ${ setClause } WHERE ${ whereClause } ` ;
232- return await this . execute ( query , args ) ;
250+ return this . execute ( query , args ) ;
233251 }
234252
235253 async delete ( tableName : string , whereClause : string ) : Promise < CrateDBResponse > {
236254 const query = `DELETE FROM ${ tableName } WHERE ${ whereClause } ` ;
237- return await this . execute ( query ) ;
255+ return this . execute ( query ) ;
238256 }
239257
240258 async drop ( tableName : string ) : Promise < CrateDBResponse > {
241259 const query = `DROP TABLE IF EXISTS ${ tableName } ` ;
242- return await this . execute ( query ) ;
260+ return this . execute ( query ) ;
243261 }
244262
245263 async refresh ( tableName : string ) : Promise < CrateDBResponse > {
246264 const query = `REFRESH TABLE ${ tableName } ` ;
247- return await this . execute ( query ) ;
265+ return this . execute ( query ) ;
248266 }
249267
250268 async createTable ( schema : Record < string , Record < string , string > > ) : Promise < CrateDBResponse > {
@@ -253,7 +271,7 @@ export class CrateDBClient {
253271 . map ( ( [ col , type ] ) => `"${ col } " ${ type } ` )
254272 . join ( ', ' ) ;
255273 const query = `CREATE TABLE ${ tableName } (${ columns } )` ;
256- return await this . execute ( query ) ;
274+ return this . execute ( query ) ;
257275 }
258276
259277 private _prepareOptions ( options : Record < string , unknown > ) : {
@@ -267,6 +285,22 @@ export class CrateDBClient {
267285 return { keys, values, args } ;
268286 }
269287
288+ private _addDurations ( startRequestTime : number , response : CrateDBBaseResponse ) : CrateDBBaseResponse {
289+ const totalRequestTime = Date . now ( ) - startRequestTime ;
290+ if ( typeof response . duration === 'number' ) {
291+ response . durations = {
292+ cratedb : response . duration ,
293+ request : totalRequestTime - response . duration ,
294+ } ;
295+ } else {
296+ response . durations = {
297+ cratedb : 0 ,
298+ request : totalRequestTime ,
299+ } ;
300+ }
301+ return response ;
302+ }
303+
270304 async _makeRequest ( options : http . RequestOptions & { body ?: string } ) : Promise < CrateDBBaseResponse > {
271305 return new Promise ( ( resolve , reject ) => {
272306 const requestBodySize = options . body ? Buffer . byteLength ( options . body ) : 0 ;
@@ -276,18 +310,19 @@ export class CrateDBClient {
276310 response . on ( 'end' , ( ) => {
277311 const rawResponse = Buffer . concat ( data ) ; // Raw response data as a buffer
278312 const responseBodySize = rawResponse . length ;
313+
279314 try {
280315 const parsedResponse = Serializer . deserialize ( rawResponse . toString ( ) , this . cfg . deserialization ) ;
281- resolve ( {
282- ...parsedResponse ,
283- sizes : { response : responseBodySize , request : requestBodySize } ,
284- } ) ;
285- } catch ( parseErr : unknown ) {
286- if ( response . statusCode === 401 ) {
287- reject ( new Error ( 'Authentication error: Invalid credentials or insufficient permissions.' ) ) ;
288- } else if ( response . statusCode === 503 ) {
289- reject ( new Error ( 'Service unavailable: server is not available (503).' ) ) ;
316+ if ( response . statusCode === 200 ) {
317+ resolve ( {
318+ ...parsedResponse ,
319+ sizes : { response : responseBodySize , request : requestBodySize } ,
320+ } ) ;
321+ } else {
322+ reject ( CrateDBError . fromResponse ( parsedResponse as CrateDBErrorResponse , response . statusCode ) ) ;
290323 }
324+ } catch ( parseErr : unknown ) {
325+ // Handle parsing errors
291326 if ( parseErr instanceof Error ) {
292327 reject (
293328 new Error ( `Failed to parse response: ${ parseErr . message } . Raw response: ${ rawResponse . toString ( ) } ` )
@@ -302,6 +337,7 @@ export class CrateDBClient {
302337 req . end ( options . body || null ) ;
303338 } ) ;
304339 }
340+
305341 public getConfig ( ) : Readonly < CrateDBConfig > {
306342 return this . cfg ;
307343 }
0 commit comments