@@ -204,6 +204,81 @@ function cleanParamsForSpanner(
204
204
return cleaned ;
205
205
}
206
206
207
+ // Helper function to automatically infer Spanner types from JavaScript values
208
+ function inferSpannerTypeFromValue ( value : any ) : string {
209
+ if ( value === null || value === undefined ) {
210
+ // For null/undefined, we can't infer type, default to STRING
211
+ return "STRING" ;
212
+ }
213
+
214
+ if ( typeof value === 'string' ) {
215
+ return "STRING" ;
216
+ }
217
+
218
+ if ( typeof value === 'number' ) {
219
+ // Check if it's an integer or float
220
+ if ( Number . isInteger ( value ) ) {
221
+ return "INT64" ;
222
+ }
223
+ return "FLOAT64" ;
224
+ }
225
+
226
+ if ( typeof value === 'boolean' ) {
227
+ return "BOOL" ;
228
+ }
229
+
230
+ if ( value instanceof Date ) {
231
+ return "TIMESTAMP" ;
232
+ }
233
+
234
+ if ( Buffer . isBuffer ( value ) || value instanceof Uint8Array ) {
235
+ return "BYTES" ;
236
+ }
237
+
238
+ if ( typeof value === 'object' ) {
239
+ // For objects and arrays, use JSON type
240
+ return "JSON" ;
241
+ }
242
+
243
+ // Default fallback
244
+ return "STRING" ;
245
+ }
246
+
247
+ // Helper function to automatically generate type hints from parameters
248
+ function generateTypeHintsFromParams ( params ?: Record < string , any > ) : Record < string , string > | undefined {
249
+ if ( ! params ) return undefined ;
250
+
251
+ const typeHints : Record < string , string > = { } ;
252
+ for ( const key in params ) {
253
+ if ( Object . prototype . hasOwnProperty . call ( params , key ) ) {
254
+ typeHints [ key ] = inferSpannerTypeFromValue ( params [ key ] ) ;
255
+ }
256
+ }
257
+ return typeHints ;
258
+ }
259
+
260
+ // Helper function to merge provided hints with inferred hints
261
+ function mergeTypeHints (
262
+ providedHints ?: Record < string , string > ,
263
+ params ?: Record < string , any >
264
+ ) : Record < string , string > | undefined {
265
+ if ( ! params && ! providedHints ) return undefined ;
266
+
267
+ // Generate automatic hints from params
268
+ const inferredHints = generateTypeHintsFromParams ( params ) ;
269
+
270
+ if ( ! providedHints ) {
271
+ return inferredHints ;
272
+ }
273
+
274
+ if ( ! inferredHints ) {
275
+ return providedHints ;
276
+ }
277
+
278
+ // Merge, with provided hints taking precedence
279
+ return { ...inferredHints , ...providedHints } ;
280
+ }
281
+
207
282
// Helper function to provide better error messages
208
283
function enhanceSpannerError ( error : any , params ?: Record < string , any > ) : Error {
209
284
const errorMessage = error . message || '' ;
@@ -395,10 +470,13 @@ export class SpannerAdapter implements DatabaseAdapter {
395
470
) : Promise < number | AffectedRows > {
396
471
const db = this . ensureConnected ( ) ; // Relies on connect() having awaited this.ready
397
472
try {
473
+ // Merge provided hints with inferred hints
474
+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
475
+
398
476
// Clean params if they contain JSON
399
- const cleanedParams = cleanParamsForSpanner ( params , spannerTypeHints ) ;
400
- const paramTypes = transformDdlHintsToParamTypes ( spannerTypeHints ) as any ;
401
- const types = transformDdlHintsToTypes ( spannerTypeHints ) ;
477
+ const cleanedParams = cleanParamsForSpanner ( params , mergedHints ) ;
478
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
479
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
402
480
403
481
// Spanner's runUpdate returns an array where the first element is the affected row count.
404
482
// The result of runTransactionAsync is the result of its callback.
@@ -496,10 +574,13 @@ export class SpannerAdapter implements DatabaseAdapter {
496
574
) : Promise < TResult [ ] > {
497
575
const db = this . ensureConnected ( ) ; // Relies on connect() having awaited this.ready
498
576
try {
577
+ // Merge provided hints with inferred hints
578
+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
579
+
499
580
// Clean params if they contain JSON
500
- const cleanedParams = cleanParamsForSpanner ( params , spannerTypeHints ) ;
501
- const paramTypes = transformDdlHintsToParamTypes ( spannerTypeHints ) as any ;
502
- const types = transformDdlHintsToTypes ( spannerTypeHints ) ;
581
+ const cleanedParams = cleanParamsForSpanner ( params , mergedHints ) ;
582
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
583
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
503
584
504
585
const queryOptions : any = {
505
586
sql,
@@ -576,10 +657,13 @@ export class SpannerAdapter implements DatabaseAdapter {
576
657
) : Promise < TResult [ ] > {
577
658
const db = this . ensureConnected ( ) ;
578
659
try {
660
+ // Merge provided hints with inferred hints
661
+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
662
+
579
663
// Clean params if they contain JSON
580
- const cleanedParams = cleanParamsForSpanner ( params , spannerTypeHints ) ;
581
- const paramTypes = transformDdlHintsToParamTypes ( spannerTypeHints ) as any ;
582
- const types = transformDdlHintsToTypes ( spannerTypeHints ) ;
664
+ const cleanedParams = cleanParamsForSpanner ( params , mergedHints ) ;
665
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
666
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
583
667
584
668
// Use runTransactionAsync to ensure a read-write transaction
585
669
return await db . runTransactionAsync (
@@ -656,10 +740,13 @@ export class SpannerAdapter implements DatabaseAdapter {
656
740
) ;
657
741
658
742
try {
743
+ // Merge provided hints with inferred hints
744
+ const mergedHints = mergeTypeHints ( cmdSpannerTypeHints , paramsCmd ) ;
745
+
659
746
// Clean params if they contain JSON
660
- const cleanedParams = cleanParamsForSpanner ( paramsCmd , cmdSpannerTypeHints ) ;
661
- const paramTypes = transformDdlHintsToParamTypes ( cmdSpannerTypeHints ) as any ;
662
- const types = transformDdlHintsToTypes ( cmdSpannerTypeHints ) ;
747
+ const cleanedParams = cleanParamsForSpanner ( paramsCmd , mergedHints ) ;
748
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
749
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
663
750
664
751
const updateOptions : any = {
665
752
sql : sqlCmd ,
@@ -689,10 +776,13 @@ export class SpannerAdapter implements DatabaseAdapter {
689
776
) : Promise < TQuery [ ] > => {
690
777
const txObjectQuery = spannerTx as any ;
691
778
try {
779
+ // Merge provided hints with inferred hints
780
+ const mergedHints = mergeTypeHints ( querySpannerTypeHints , paramsQuery ) ;
781
+
692
782
// Clean params if they contain JSON
693
- const cleanedParams = cleanParamsForSpanner ( paramsQuery , querySpannerTypeHints ) ;
694
- const paramTypes = transformDdlHintsToParamTypes ( querySpannerTypeHints ) as any ;
695
- const types = transformDdlHintsToTypes ( querySpannerTypeHints ) ;
783
+ const cleanedParams = cleanParamsForSpanner ( paramsQuery , mergedHints ) ;
784
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
785
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
696
786
697
787
const queryOptions : any = {
698
788
sql : sqlQuery ,
@@ -749,10 +839,13 @@ export class SpannerAdapter implements DatabaseAdapter {
749
839
cmdSpannerTypeHints ?: Record < string , string >
750
840
) => {
751
841
try {
842
+ // Merge provided hints with inferred hints
843
+ const mergedHints = mergeTypeHints ( cmdSpannerTypeHints , cmdParams ) ;
844
+
752
845
// Clean params if they contain JSON
753
- const cleanedParams = cleanParamsForSpanner ( cmdParams , cmdSpannerTypeHints ) ;
754
- const paramTypes = transformDdlHintsToParamTypes ( cmdSpannerTypeHints ) as any ;
755
- const types = transformDdlHintsToTypes ( cmdSpannerTypeHints ) ;
846
+ const cleanedParams = cleanParamsForSpanner ( cmdParams , mergedHints ) ;
847
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
848
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
756
849
757
850
const updateOptions : any = {
758
851
sql : cmdSql ,
@@ -779,10 +872,13 @@ export class SpannerAdapter implements DatabaseAdapter {
779
872
querySpannerTypeHints ?: Record < string , string >
780
873
) => {
781
874
try {
875
+ // Merge provided hints with inferred hints
876
+ const mergedHints = mergeTypeHints ( querySpannerTypeHints , queryParams ) ;
877
+
782
878
// Clean params if they contain JSON
783
- const cleanedParams = cleanParamsForSpanner ( queryParams , querySpannerTypeHints ) ;
784
- const paramTypes = transformDdlHintsToParamTypes ( querySpannerTypeHints ) as any ;
785
- const types = transformDdlHintsToTypes ( querySpannerTypeHints ) ;
879
+ const cleanedParams = cleanParamsForSpanner ( queryParams , mergedHints ) ;
880
+ const paramTypes = transformDdlHintsToParamTypes ( mergedHints ) as any ;
881
+ const types = transformDdlHintsToTypes ( mergedHints ) ;
786
882
787
883
const queryOptions : any = {
788
884
sql : querySql ,
0 commit comments