Skip to content

Commit da2bdb7

Browse files
authored
Merge pull request #113 from Flux159/pr113
Updating typehints
2 parents 4d5e26b + 2d58419 commit da2bdb7

File tree

2 files changed

+326
-58
lines changed

2 files changed

+326
-58
lines changed

src/spanner/adapter.ts

Lines changed: 117 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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
208283
function 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

Comments
 (0)