diff --git a/packages/pg-meta/src/sql/studio/get-users-count.ts b/packages/pg-meta/src/sql/studio/get-users-count.ts index e3bc46ea5a3..9a012de315a 100644 --- a/packages/pg-meta/src/sql/studio/get-users-count.ts +++ b/packages/pg-meta/src/sql/studio/get-users-count.ts @@ -27,31 +27,34 @@ export const getUsersCountSQL = ({ const optimizedSearchMode = column && hasValidKeywords if (optimizedSearchMode) { - const formattedKeywords = keywords.replaceAll("'", "''") - if (column === 'email') { - const range = stringRange(formattedKeywords) + const range = stringRange(keywords) + const lowerBound = literal(range[0]) + const upperBound = range[1] ? literal(range[1]) : null conditions.push( - `lower(email) >= '${range[0]}'${range[1] ? ` and lower(email) < '${range[1]}'` : ''} and instance_id = '00000000-0000-0000-0000-000000000000'::uuid` + `lower(email) >= ${lowerBound}${upperBound ? ` and lower(email) < ${upperBound}` : ''} and instance_id = '00000000-0000-0000-0000-000000000000'::uuid` ) } else if (column === 'phone') { - const range = stringRange(formattedKeywords) - conditions.push(`phone >= '${range[0]}'${range[1] ? ` and phone < '${range[1]}'` : ''}`) + const range = stringRange(keywords) + const lowerBound = literal(range[0]) + const upperBound = range[1] ? literal(range[1]) : null + conditions.push(`phone >= ${lowerBound}${upperBound ? ` and phone < ${upperBound}` : ''}`) } else if (column === 'id') { - const isMatchingUUIDValue = prefixToUUID(formattedKeywords, false) === formattedKeywords - conditions.push( - isMatchingUUIDValue - ? `id = '${formattedKeywords}'` - : `id >= '${prefixToUUID(formattedKeywords, false)}' and id < '${prefixToUUID(formattedKeywords, true)}'` - ) + const lowerUUID = prefixToUUID(keywords, false) + const isMatchingUUIDValue = lowerUUID === keywords + if (isMatchingUUIDValue) { + conditions.push(`id = ${literal(keywords)}`) + } else { + const upperUUID = prefixToUUID(keywords, true) + conditions.push(`id >= ${literal(lowerUUID)} and id < ${literal(upperUUID)}`) + } } } else { // Unified search mode - apply all filters if (hasValidKeywords) { - // [Joshen] Escape single quotes properly - const formattedKeywords = keywords.replaceAll("'", "''") + const escapedFilterKeywords = literal(`%${keywords}%`) conditions.push( - `id::text ilike '%${formattedKeywords}%' or email ilike '%${formattedKeywords}%' or phone ilike '%${formattedKeywords}%'` + `id::text ilike ${escapedFilterKeywords} or email ilike ${escapedFilterKeywords} or phone ilike ${escapedFilterKeywords}` ) } @@ -67,13 +70,12 @@ export const getUsersCountSQL = ({ // [Joshen] This is arguarbly not fully optimized, but at the same time not commonly used // JFYI in case we do eventually run into performance issues here when filtering for SAML provider if (providers.includes('saml 2.0')) { + const mappedProviders = providers.map((p) => (p === 'saml 2.0' ? 'sso' : p)) conditions.push( - `(select jsonb_agg(case when value ~ '^sso' then 'sso' else value end) from jsonb_array_elements_text((raw_app_meta_data ->> 'providers')::jsonb)) ?| array[${literal(providers.map((p) => (p === 'saml 2.0' ? 'sso' : p)))}]`.trim() + `(select jsonb_agg(case when value ~ '^sso' then 'sso' else value end) from jsonb_array_elements_text((raw_app_meta_data ->> 'providers')::jsonb)) ?| array[${literal(mappedProviders)}]`.trim() ) } else { - conditions.push( - `(raw_app_meta_data->>'providers')::jsonb ?| array[${providers.map((p) => `'${p}'`).join(', ')}]` - ) + conditions.push(`(raw_app_meta_data->>'providers')::jsonb ?| array[${literal(providers)}]`) } } } @@ -87,7 +89,7 @@ export const getUsersCountSQL = ({ const selectBaseSql = `${baseQuerySelect}${whereClause}` const countBaseSql = `${baseQueryCount}${whereClause}` - const escapedSelectSql = selectBaseSql.replaceAll("'", "''") + const escapedSelectSql = literal(selectBaseSql) const sql = ` ${COUNT_ESTIMATE_SQL} @@ -95,8 +97,8 @@ ${COUNT_ESTIMATE_SQL} with approximation as (${USERS_COUNT_ESTIMATE_SQL}) select case - when estimate = -1 then (select pg_temp.count_estimate('${escapedSelectSql}'))::int - when estimate > ${THRESHOLD_COUNT} then ${conditions.length > 0 ? `(select pg_temp.count_estimate('${escapedSelectSql}'))::int` : 'estimate::int'} + when estimate = -1 then (select pg_temp.count_estimate(${escapedSelectSql}))::int + when estimate > ${THRESHOLD_COUNT} then ${conditions.length > 0 ? `(select pg_temp.count_estimate(${escapedSelectSql}))::int` : 'estimate::int'} else (${countBaseSql}) end as count, estimate = -1 or estimate > ${THRESHOLD_COUNT} as is_estimate