@@ -204,6 +204,81 @@ function cleanParamsForSpanner(
204204 return cleaned ;
205205}
206206
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+
207282// Helper function to provide better error messages
208283function enhanceSpannerError ( error : any , params ?: Record < string , any > ) : Error {
209284 const errorMessage = error . message || '' ;
@@ -395,10 +470,13 @@ export class SpannerAdapter implements DatabaseAdapter {
395470 ) : Promise < number | AffectedRows > {
396471 const db = this . ensureConnected ( ) ; // Relies on connect() having awaited this.ready
397472 try {
473+ // Merge provided hints with inferred hints
474+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
475+
398476 // 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 ) ;
402480
403481 // Spanner's runUpdate returns an array where the first element is the affected row count.
404482 // The result of runTransactionAsync is the result of its callback.
@@ -496,10 +574,13 @@ export class SpannerAdapter implements DatabaseAdapter {
496574 ) : Promise < TResult [ ] > {
497575 const db = this . ensureConnected ( ) ; // Relies on connect() having awaited this.ready
498576 try {
577+ // Merge provided hints with inferred hints
578+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
579+
499580 // 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 ) ;
503584
504585 const queryOptions : any = {
505586 sql,
@@ -576,10 +657,13 @@ export class SpannerAdapter implements DatabaseAdapter {
576657 ) : Promise < TResult [ ] > {
577658 const db = this . ensureConnected ( ) ;
578659 try {
660+ // Merge provided hints with inferred hints
661+ const mergedHints = mergeTypeHints ( spannerTypeHints , params ) ;
662+
579663 // 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 ) ;
583667
584668 // Use runTransactionAsync to ensure a read-write transaction
585669 return await db . runTransactionAsync (
@@ -656,10 +740,13 @@ export class SpannerAdapter implements DatabaseAdapter {
656740 ) ;
657741
658742 try {
743+ // Merge provided hints with inferred hints
744+ const mergedHints = mergeTypeHints ( cmdSpannerTypeHints , paramsCmd ) ;
745+
659746 // 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 ) ;
663750
664751 const updateOptions : any = {
665752 sql : sqlCmd ,
@@ -689,10 +776,13 @@ export class SpannerAdapter implements DatabaseAdapter {
689776 ) : Promise < TQuery [ ] > => {
690777 const txObjectQuery = spannerTx as any ;
691778 try {
779+ // Merge provided hints with inferred hints
780+ const mergedHints = mergeTypeHints ( querySpannerTypeHints , paramsQuery ) ;
781+
692782 // 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 ) ;
696786
697787 const queryOptions : any = {
698788 sql : sqlQuery ,
@@ -749,10 +839,13 @@ export class SpannerAdapter implements DatabaseAdapter {
749839 cmdSpannerTypeHints ?: Record < string , string >
750840 ) => {
751841 try {
842+ // Merge provided hints with inferred hints
843+ const mergedHints = mergeTypeHints ( cmdSpannerTypeHints , cmdParams ) ;
844+
752845 // 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 ) ;
756849
757850 const updateOptions : any = {
758851 sql : cmdSql ,
@@ -779,10 +872,13 @@ export class SpannerAdapter implements DatabaseAdapter {
779872 querySpannerTypeHints ?: Record < string , string >
780873 ) => {
781874 try {
875+ // Merge provided hints with inferred hints
876+ const mergedHints = mergeTypeHints ( querySpannerTypeHints , queryParams ) ;
877+
782878 // 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 ) ;
786882
787883 const queryOptions : any = {
788884 sql : querySql ,
0 commit comments