@@ -341,4 +341,74 @@ export const emailDataToString = (
341341 searchParams . size > 0 && `?${ searchParams . toString ( ) . replace ( / \+ / g, ' ' ) } ` ,
342342 ] . filter ( Boolean ) . join ( '' )
343343
344+ }
345+
346+
347+ /**
348+ * Represents a value that can be used as a parameter in string operations.
349+ *
350+ */
351+ type ParameterizedValue = string | boolean | number | bigint
352+
353+
354+ /**
355+ * Represents a parameterized string with its corresponding values.
356+ *
357+ * @property {string } 0 - The template string
358+ * @property {ParameterizedValue[] } 1 - Array of values to be substituted into the template string
359+ */
360+ type Parameterized = [ string , ParameterizedValue [ ] ]
361+
362+
363+ /**
364+ * Creates a parameterized query string with placeholder values.
365+ *
366+ * @param strings - The template string parts from a template literal.
367+ * @param values - One or more parameter values or arrays of values to be substituted into the template.
368+ * @returns A tuple containing the normalized query string with `?` placeholders and an array of parameter values.
369+ *
370+ * @example
371+ * ```ts
372+ * const [ query, params ] = parameterized`
373+ * SELECT * FROM users WHERE id = ${ 1 } AND status IN ( ${ [ 'active', 'pending' ] } )
374+ * ` )
375+ *
376+ * // query: "SELECT * FROM users WHERE id = ? AND status IN ( ?, ? )"
377+ * // params: [ 1, 'active', 'pending' ]
378+ * ```
379+ *
380+ * @remarks
381+ * - Whitespace is normalized (multiple spaces reduced to single space, trimmed).
382+ * - Undefined values are skipped.
383+ * - Array values are expanded into comma-separated placeholders.
384+ * - Single values are replaced with a single `?` placeholder.
385+ */
386+ export const parameterized = ( strings : TemplateStringsArray , ...values : ( ParameterizedValue | ParameterizedValue [ ] ) [ ] ) : Parameterized => {
387+
388+ const params : ParameterizedValue [ ] = [ ]
389+ let text = ''
390+
391+ strings . forEach ( ( string , index ) => {
392+ text += string
393+
394+ if ( index >= values . length ) return
395+
396+ const value = values [ index ]
397+
398+ if ( typeof value === 'undefined' ) return
399+
400+ if ( Array . isArray ( value ) ) {
401+
402+ const placeholders = value . map ( ( ) => '?' ) . join ( ', ' )
403+ text += placeholders
404+ params . push ( ...value )
405+ return
406+ }
407+
408+ text += '?'
409+ params . push ( value )
410+
411+ } )
412+
413+ return [ text . replace ( / \s + / g, ' ' ) . trim ( ) , params ]
344414}
0 commit comments