refactor(pg-meta): expand safeSql usage (#44674)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Standardized SQL construction across the pg-meta package to use
parameter-safe SQL fragments instead of raw string assembly, improving
safety for dynamic values (filters, limits, offsets, identifiers) and
unifying how exported SQL constants and query helpers are produced. No
functional query behavior changes expected.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Charis authored and GitHub committed 2026-04-09 14:32:02 -04:00
1 parent 054e44f7e6
commit 5d013cb2f6
25 files changed
+310 -260

No files matched your search

+14 -16
View File
@@ -2,7 +2,7 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { ident, literal } from './pg-format'
import { ident, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { COLUMNS_SQL } from './sql/columns'
const pgColumnZod = z.object({
@@ -46,10 +46,10 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgColumnArrayZod
} {
let sql = `
let sql = safeSql`
with
columns as (${COLUMNS_SQL})
select
@@ -67,16 +67,16 @@ where
)
if (filter) {
sql += ` and schema ${filter}`
sql = safeSql`${sql} and schema ${filter}`
}
if (tableId !== undefined) {
sql += ` and table_id = ${literal(tableId)} `
sql = safeSql`${sql} and table_id = ${literal(tableId)} `
}
if (limit) {
sql = `${sql} limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql = `${sql} offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -86,20 +86,20 @@ where
type ColumnIdentifier = Pick<PGColumn, 'id'> | Pick<PGColumn, 'name' | 'schema' | 'table'>
function getIdentifierWhereClause(identifier: ColumnIdentifier) {
function getIdentifierWhereClause(identifier: ColumnIdentifier): SafeSqlFragment {
if ('id' in identifier && identifier.id) {
return `${ident('id')} = ${literal(identifier.id)}`
return safeSql`${ident('id')} = ${literal(identifier.id)}`
} else if ('name' in identifier && identifier.name && identifier.schema && identifier.table) {
return `schema = ${literal(identifier.schema)} AND ${ident('table')} = ${literal(identifier.table)} AND name = ${literal(identifier.name)}`
return safeSql`schema = ${literal(identifier.schema)} AND ${ident('table')} = ${literal(identifier.table)} AND name = ${literal(identifier.name)}`
}
throw new Error('Must provide either id or schema, name and table')
}
function retrieve(identifier: ColumnIdentifier): {
sql: string
sql: SafeSqlFragment
zod: typeof pgColumnOptionalZod
} {
const sql = `WITH columns AS (${COLUMNS_SQL}) SELECT * FROM columns WHERE ${getIdentifierWhereClause(identifier)};`
const sql = safeSql`WITH columns AS (${COLUMNS_SQL}) SELECT * FROM columns WHERE ${getIdentifierWhereClause(identifier)};`
return {
sql,
zod: pgColumnOptionalZod,
@@ -393,10 +393,8 @@ COMMIT;`
function remove(
column: Pick<PGColumn, 'name' | 'schema' | 'table'>,
{ cascade = false } = {}
): { sql: string } {
const sql = `ALTER TABLE ${ident(column.schema)}.${ident(column.table)} DROP COLUMN ${ident(
column.name
)} ${cascade ? 'CASCADE' : 'RESTRICT'};`
): { sql: SafeSqlFragment } {
const sql = safeSql`ALTER TABLE ${ident(column.schema)}.${ident(column.table)} DROP COLUMN ${ident(column.name)} ${cascade ? safeSql`CASCADE` : safeSql`RESTRICT`};`
return { sql }
}
+4 -3
View File
@@ -1,5 +1,6 @@
import { z } from 'zod'
import { literal, safeSql, type SafeSqlFragment } from './pg-format'
import { CONFIG_SQL } from './sql/config'
const pgConfigZod = z.object({
@@ -33,15 +34,15 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgConfigArrayZod
} {
let sql = CONFIG_SQL
if (limit) {
sql += ` LIMIT ${limit}`
sql = safeSql`${sql} LIMIT ${literal(limit)}`
}
if (offset) {
sql += ` OFFSET ${offset}`
sql = safeSql`${sql} OFFSET ${literal(offset)}`
}
return {
sql,
+26 -19
View File
@@ -1,6 +1,6 @@
import { z } from 'zod'
import { ident, literal } from './pg-format'
import { ident, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { EXTENSIONS_SQL } from './sql/extensions'
const pgExtensionZod = z.object({
@@ -23,15 +23,15 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgExtensionArrayZod
} {
let sql = EXTENSIONS_SQL
if (limit) {
sql = `${sql} LIMIT ${limit}`
sql = safeSql`${sql} LIMIT ${literal(limit)}`
}
if (offset) {
sql = `${sql} OFFSET ${offset}`
sql = safeSql`${sql} OFFSET ${literal(offset)}`
}
return {
sql,
@@ -40,10 +40,10 @@ function list({
}
function retrieve({ name }: { name: string }): {
sql: string
sql: SafeSqlFragment
zod: typeof pgExtensionOptionalZod
} {
const sql = `${EXTENSIONS_SQL} WHERE name = ${literal(name)};`
const sql = safeSql`${EXTENSIONS_SQL} WHERE name = ${literal(name)};`
return {
sql,
zod: pgExtensionOptionalZod,
@@ -58,13 +58,13 @@ type ExtensionCreateParams = {
}
function create({ name, schema, version, cascade = false }: ExtensionCreateParams): {
sql: string
sql: SafeSqlFragment
} {
const sql = `
const sql = safeSql`
CREATE EXTENSION ${ident(name)}
${schema === undefined ? '' : `SCHEMA ${ident(schema)}`}
${version === undefined ? '' : `VERSION ${literal(version)}`}
${cascade ? 'CASCADE' : ''};`
${schema === undefined ? safeSql`` : safeSql`SCHEMA ${ident(schema)}`}
${version === undefined ? safeSql`` : safeSql`VERSION ${literal(version)}`}
${cascade ? safeSql`CASCADE` : safeSql``};`
return { sql }
}
@@ -77,17 +77,19 @@ type ExtensionUpdateParams = {
function update(
name: string,
{ update = false, version, schema }: ExtensionUpdateParams
): { sql: string } {
let updateSql = ''
): { sql: SafeSqlFragment } {
let updateSql = safeSql``
if (update) {
updateSql = `ALTER EXTENSION ${ident(name)} UPDATE ${
version === undefined ? '' : `TO ${literal(version)}`
updateSql = safeSql`ALTER EXTENSION ${ident(name)} UPDATE ${
version === undefined ? safeSql`` : safeSql`TO ${literal(version)}`
};`
}
const schemaSql =
schema === undefined ? '' : `ALTER EXTENSION ${ident(name)} SET SCHEMA ${ident(schema)};`
schema === undefined
? safeSql``
: safeSql`ALTER EXTENSION ${ident(name)} SET SCHEMA ${ident(schema)};`
const sql = `BEGIN; ${updateSql} ${schemaSql} COMMIT;`
const sql = safeSql`BEGIN; ${updateSql} ${schemaSql} COMMIT;`
return { sql }
}
@@ -95,8 +97,13 @@ type ExtensionRemoveParams = {
cascade?: boolean
}
function remove(name: string, { cascade = false }: ExtensionRemoveParams = {}): { sql: string } {
const sql = `DROP EXTENSION ${ident(name)} ${cascade ? 'CASCADE' : 'RESTRICT'};`
function remove(
name: string,
{ cascade = false }: ExtensionRemoveParams = {}
): {
sql: SafeSqlFragment
} {
const sql = safeSql`DROP EXTENSION ${ident(name)} ${cascade ? safeSql`CASCADE` : safeSql`RESTRICT`};`
return { sql }
}
+18 -21
View File
@@ -2,7 +2,7 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { ident, literal } from './pg-format'
import { ident, joinSqlFragments, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { FUNCTIONS_SQL } from './sql/functions'
export const pgFunctionZod = z.object({
@@ -55,10 +55,10 @@ export function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgFunctionArrayZod
} {
let sql = /* SQL */ `
let sql = safeSql`
with f as (
${FUNCTIONS_SQL}
)
@@ -72,13 +72,13 @@ export function list({
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += ` where schema ${filter}`
sql = safeSql`${sql} where schema ${filter}`
}
if (limit) {
sql = `${sql} limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql = `${sql} offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
@@ -88,7 +88,7 @@ export function list({
}
type FunctionsRetrieveReturn = {
sql: string
sql: SafeSqlFragment
zod: typeof pgFunctionOptionalZod
}
@@ -114,7 +114,7 @@ export function retrieve({
args?: string[]
}): FunctionsRetrieveReturn {
if (id) {
const sql = /* SQL */ `
const sql = safeSql`
with f as (
${FUNCTIONS_SQL}
)
@@ -127,16 +127,8 @@ export function retrieve({
zod: pgFunctionOptionalZod,
}
} else if (name && schema && args) {
const sql = /* SQL */ `with f as (
${FUNCTIONS_SQL}
)
select
f.*
from f join pg_proc as p on id = p.oid where schema = ${literal(
schema
)} and name = ${literal(name)} and p.proargtypes::text = ${
args.length
? /* SQL */ `(
const argsFragment = args.length
? safeSql`(
select string_agg(type_oid::text, ' ') from (
select (
split_args.arr[
@@ -148,15 +140,20 @@ export function retrieve({
) as type_oid from (
select string_to_array(
unnest(
array[${args.map(literal)}]
array[${joinSqlFragments(args.map(literal), ',')}]
),
' '
) as arr
) as split_args
) args
)`
: literal('')
}`
: literal('')
const sql = safeSql`with f as (
${FUNCTIONS_SQL}
)
select
f.*
from f join pg_proc as p on id = p.oid where schema = ${literal(schema)} and name = ${literal(name)} and p.proargtypes::text = ${argsFragment}`
return {
sql,
+11 -8
View File
@@ -2,7 +2,7 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { literal } from './pg-format'
import { literal, safeSql, type SafeSqlFragment } from './pg-format'
import { INDEXES_SQL } from './sql/indexes'
const pgIndexZod = z.object({
@@ -54,10 +54,10 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgIndexArrayZod
} {
let sql = `
let sql = safeSql`
with indexes as (${INDEXES_SQL})
select *
from indexes
@@ -68,13 +68,13 @@ function list({
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += ` where schema ${filter}`
sql = safeSql`${sql} where schema ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -82,8 +82,11 @@ function list({
}
}
function retrieve({ id }: { id: number }): { sql: string; zod: typeof pgIndexOptionalZod } {
const sql = `
function retrieve({ id }: { id: number }): {
sql: SafeSqlFragment
zod: typeof pgIndexOptionalZod
} {
const sql = safeSql`
with indexes as (${INDEXES_SQL})
select *
from indexes
+13 -15
View File
@@ -2,7 +2,7 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { ident, literal } from './pg-format'
import { ident, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { POLICIES_SQL } from './sql/policies'
const pgPolicyZod = z.object({
@@ -30,11 +30,11 @@ export type PGPolicy = z.infer<typeof pgPolicyZod>
type PolicyIdentifier = Pick<PGPolicy, 'id'> | Pick<PGPolicy, 'name' | 'schema' | 'table'>
function getIdentifierWhereClause(identifier: PolicyIdentifier): string {
function getIdentifierWhereClause(identifier: PolicyIdentifier): SafeSqlFragment {
if ('id' in identifier && identifier.id) {
return `id = ${literal(identifier.id)}`
return safeSql`id = ${literal(identifier.id)}`
} else if ('name' in identifier && identifier.name && identifier.schema && identifier.table) {
return `name = ${literal(identifier.name)} AND schema = ${literal(identifier.schema)} AND table = ${literal(identifier.table)}`
return safeSql`name = ${literal(identifier.name)} AND schema = ${literal(identifier.schema)} AND table = ${literal(identifier.table)}`
}
throw new Error('Must provide either id or name, schema and table')
}
@@ -52,10 +52,10 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgPolicyArrayZod
} {
let sql = `
let sql = safeSql`
with policies as (${POLICIES_SQL})
select *
from policies
@@ -66,13 +66,13 @@ function list({
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += `where schema ${filter}`
sql = safeSql`${sql}where schema ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -81,10 +81,10 @@ function list({
}
function retrieve(identifier: PolicyIdentifier): {
sql: string
sql: SafeSqlFragment
zod: typeof pgPolicyOptionalZod
} {
const sql = `with policies as (${POLICIES_SQL}) select * from policies where ${getIdentifierWhereClause(identifier)};`
const sql = safeSql`with policies as (${POLICIES_SQL}) select * from policies where ${getIdentifierWhereClause(identifier)};`
return {
sql,
zod: pgPolicyOptionalZod,
@@ -147,10 +147,8 @@ function update(
return { sql }
}
function remove(identifier: Pick<PGPolicy, 'name' | 'schema' | 'table'>): { sql: string } {
const sql = `DROP POLICY ${ident(identifier.name)} ON ${ident(identifier.schema)}.${ident(
identifier.table
)};`
function remove(identifier: Pick<PGPolicy, 'name' | 'schema' | 'table'>): { sql: SafeSqlFragment } {
const sql = safeSql`DROP POLICY ${ident(identifier.name)} ON ${ident(identifier.schema)}.${ident(identifier.table)};`
return { sql }
}
+35 -35
View File
@@ -1,6 +1,6 @@
import { z } from 'zod'
import { ident, literal } from './pg-format'
import { ident, joinSqlFragments, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { PUBLICATIONS_SQL } from './sql/publications'
const pgPublicationTableZod = z.object({
@@ -32,15 +32,15 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgPublicationArrayZod
} {
let sql = `with publications as (${PUBLICATIONS_SQL}) select * from publications`
let sql = safeSql`with publications as (${PUBLICATIONS_SQL}) select * from publications`
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -50,20 +50,20 @@ function list({
type PublicationIdentifier = Pick<PGPublication, 'id'> | Pick<PGPublication, 'name'>
function getIdentifierWhereClause(identifier: PublicationIdentifier) {
function getIdentifierWhereClause(identifier: PublicationIdentifier): SafeSqlFragment {
if ('id' in identifier && identifier.id) {
return `${ident('id')} = ${literal(identifier.id)}`
return safeSql`${ident('id')} = ${literal(identifier.id)}`
} else if ('name' in identifier && identifier.name) {
return `${ident('name')} = ${literal(identifier.name)}`
return safeSql`${ident('name')} = ${literal(identifier.name)}`
}
throw new Error('Must provide either id or name')
}
function retrieve(identifier: PublicationIdentifier): {
sql: string
sql: SafeSqlFragment
zod: typeof pgPublicationOptionalZod
} {
const sql = `with publications as (${PUBLICATIONS_SQL}) select * from publications where ${getIdentifierWhereClause(identifier)};`
const sql = safeSql`with publications as (${PUBLICATIONS_SQL}) select * from publications where ${getIdentifierWhereClause(identifier)};`
return {
sql,
zod: pgPublicationOptionalZod,
@@ -86,35 +86,35 @@ function create({
publish_delete = false,
publish_truncate = false,
tables = null,
}: PublicationCreateParams): { sql: string } {
let tableClause: string
}: PublicationCreateParams): { sql: SafeSqlFragment } {
let tableClause: SafeSqlFragment
if (tables === undefined || tables === null) {
tableClause = 'FOR ALL TABLES'
tableClause = safeSql`FOR ALL TABLES`
} else if (tables.length === 0) {
tableClause = ''
tableClause = safeSql``
} else {
tableClause = `FOR TABLE ${tables
.map((t) => {
tableClause = safeSql`FOR TABLE ${joinSqlFragments(
tables.map((t) => {
if (!t.includes('.')) {
return ident(t)
}
const [schema, ...rest] = t.split('.')
const table = rest.join('.')
return `${ident(schema)}.${ident(table)}`
})
.join(',')}`
return safeSql`${ident(schema)}.${ident(table)}`
}),
','
)}`
}
let publishOps = []
const publishOps: Array<string> = []
if (publish_insert) publishOps.push('insert')
if (publish_update) publishOps.push('update')
if (publish_delete) publishOps.push('delete')
if (publish_truncate) publishOps.push('truncate')
const sql = `
const sql = safeSql`
CREATE PUBLICATION ${ident(name)} ${tableClause}
WITH (publish = '${publishOps.join(',')}');`
WITH (publish = ${literal(publishOps.join(','))});`
return { sql }
}
@@ -140,21 +140,21 @@ function update(
publish_truncate,
tables,
}: PublicationUpdateParams
): { sql: string } {
const sql = `
): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
declare
id oid := ${literal(id)};
old record;
new_name text := ${name === undefined ? null : literal(name)};
new_owner text := ${owner === undefined ? null : literal(owner)};
new_publish_insert bool := ${publish_insert ?? null};
new_publish_update bool := ${publish_update ?? null};
new_publish_delete bool := ${publish_delete ?? null};
new_publish_truncate bool := ${publish_truncate ?? null};
new_name text := ${name === undefined ? literal(null) : literal(name)};
new_owner text := ${owner === undefined ? literal(null) : literal(owner)};
new_publish_insert bool := ${literal(publish_insert ?? null)};
new_publish_update bool := ${literal(publish_update ?? null)};
new_publish_delete bool := ${literal(publish_delete ?? null)};
new_publish_truncate bool := ${literal(publish_truncate ?? null)};
new_tables text := ${
tables === undefined
? null
? literal(null)
: literal(
tables === null
? 'all tables'
@@ -166,7 +166,7 @@ declare
const [schema, ...rest] = t.split('.')
const table = rest.join('.')
return `${ident(schema)}.${ident(table)}`
return safeSql`${ident(schema)}.${ident(table)}`
})
.join(',')
)
@@ -237,8 +237,8 @@ end $$;
return { sql }
}
function remove(publication: Pick<PGPublication, 'name'>): { sql: string } {
const sql = `DROP PUBLICATION IF EXISTS ${ident(publication.name)};`
function remove(publication: Pick<PGPublication, 'name'>): { sql: SafeSqlFragment } {
const sql = safeSql`DROP PUBLICATION IF EXISTS ${ident(publication.name)};`
return { sql }
}
+53 -50
View File
@@ -1,6 +1,6 @@
import { z } from 'zod'
import { ident, literal } from './pg-format'
import { ident, joinSqlFragments, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { ROLES_SQL } from './sql/roles'
const pgRoleZod = z.object({
@@ -32,10 +32,10 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgRoleArrayZod
} {
let sql = `
let sql = safeSql`
with
roles as (${ROLES_SQL})
select
@@ -54,13 +54,13 @@ where
// ERROR: role name "pg_myrole" is reserved
// DETAIL: Role names starting with "pg_" are reserved.
// ```
sql += ` and not pg_catalog.starts_with(name, 'pg_')`
sql = safeSql`${sql} and not pg_catalog.starts_with(name, 'pg_')`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -70,20 +70,20 @@ where
type RoleIdentifier = Pick<PGRole, 'id'> | Pick<PGRole, 'name'>
function getIdentifierWhereClause(identifier: RoleIdentifier) {
function getIdentifierWhereClause(identifier: RoleIdentifier): SafeSqlFragment {
if ('id' in identifier && identifier.id) {
return `${ident('id')} = ${literal(identifier.id)}`
return safeSql`${ident('id')} = ${literal(identifier.id)}`
} else if ('name' in identifier && identifier.name) {
return `${ident('name')} = ${literal(identifier.name)}`
return safeSql`${ident('name')} = ${literal(identifier.name)}`
}
throw new Error('Must provide either id or name')
}
function retrieve(identifier: RoleIdentifier): {
sql: string
sql: SafeSqlFragment
zod: typeof pgRoleOptionalZod
} {
const sql = `with roles as (${ROLES_SQL}) select * from roles where ${getIdentifierWhereClause(identifier)};`
const sql = safeSql`with roles as (${ROLES_SQL}) select * from roles where ${getIdentifierWhereClause(identifier)};`
return {
sql,
zod: pgRoleOptionalZod,
@@ -102,9 +102,9 @@ type RoleCreateParams = {
connectionLimit?: number
password?: string
validUntil?: string
memberOf?: string[]
members?: string[]
admins?: string[]
memberOf?: Array<string>
members?: Array<string>
admins?: Array<string>
config?: Record<string, string>
}
function create({
@@ -123,26 +123,29 @@ function create({
members = [],
admins = [],
config = {},
}: RoleCreateParams): { sql: string } {
const sql = `
}: RoleCreateParams): { sql: SafeSqlFragment } {
const sql = safeSql`
create role ${ident(name)}
${isSuperuser ? 'superuser' : ''}
${canCreateDb ? 'createdb' : ''}
${canCreateRole ? 'createrole' : ''}
${inheritRole ? '' : 'noinherit'}
${canLogin ? 'login' : ''}
${isReplicationRole ? 'replication' : ''}
${canBypassRls ? 'bypassrls' : ''}
connection limit ${connectionLimit}
${password === undefined ? '' : `password ${literal(password)}`}
${validUntil === undefined ? '' : `valid until ${literal(validUntil)}`}
${memberOf.length === 0 ? '' : `in role ${memberOf.map(ident).join(',')}`}
${members.length === 0 ? '' : `role ${members.map(ident).join(',')}`}
${admins.length === 0 ? '' : `admin ${admins.map(ident).join(',')}`}
${isSuperuser ? safeSql`superuser` : safeSql``}
${canCreateDb ? safeSql`createdb` : safeSql``}
${canCreateRole ? safeSql`createrole` : safeSql``}
${inheritRole ? safeSql`` : safeSql`noinherit`}
${canLogin ? safeSql`login` : safeSql``}
${isReplicationRole ? safeSql`replication` : safeSql``}
${canBypassRls ? safeSql`bypassrls` : safeSql``}
connection limit ${literal(connectionLimit)}
${password === undefined ? safeSql`` : safeSql`password ${literal(password)}`}
${validUntil === undefined ? safeSql`` : safeSql`valid until ${literal(validUntil)}`}
${memberOf.length === 0 ? safeSql`` : safeSql`in role ${joinSqlFragments(memberOf.map(ident), ',')}`}
${members.length === 0 ? safeSql`` : safeSql`role ${joinSqlFragments(members.map(ident), ',')}`}
${admins.length === 0 ? safeSql`` : safeSql`admin ${joinSqlFragments(admins.map(ident), ',')}`}
;
${Object.entries(config)
.map(([param, value]) => `alter role ${ident(name)} set ${ident(param)} = ${literal(value)};`)
.join('\n')}
${joinSqlFragments(
Object.entries(config).map(
([param, value]) => safeSql`alter role ${ident(name)} set ${ident(param)} = ${literal(value)};`
),
'\n'
)}
`
return { sql }
}
@@ -160,7 +163,7 @@ type RoleUpdateParams = {
password?: string
validUntil?: string
}
function update(identifier: RoleIdentifier, params: RoleUpdateParams): { sql: string } {
function update(identifier: RoleIdentifier, params: RoleUpdateParams): { sql: SafeSqlFragment } {
const {
name: newName,
isSuperuser,
@@ -174,7 +177,7 @@ function update(identifier: RoleIdentifier, params: RoleUpdateParams): { sql: st
password,
validUntil,
} = params
const sql = `
const sql = safeSql`
do $$
declare
old record;
@@ -186,22 +189,22 @@ begin
end if;
execute(format('alter role %I
${isSuperuser === undefined ? '' : isSuperuser ? 'superuser' : 'nosuperuser'}
${canCreateDb === undefined ? '' : canCreateDb ? 'createdb' : 'nocreatedb'}
${canCreateRole === undefined ? '' : canCreateRole ? 'createrole' : 'nocreaterole'}
${inheritRole === undefined ? '' : inheritRole ? 'inherit' : 'noinherit'}
${canLogin === undefined ? '' : canLogin ? 'login' : 'nologin'}
${isReplicationRole === undefined ? '' : isReplicationRole ? 'replication' : 'noreplication'}
${canBypassRls === undefined ? '' : canBypassRls ? 'bypassrls' : 'nobypassrls'}
${connectionLimit === undefined ? '' : `connection limit ${connectionLimit}`}
${password === undefined ? '' : `password ${literal(password)}`}
${validUntil === undefined ? '' : `valid until %L`}
', old.name${validUntil === undefined ? '' : `, ${literal(validUntil)}`}));
${isSuperuser === undefined ? safeSql`` : isSuperuser ? safeSql`superuser` : safeSql`nosuperuser`}
${canCreateDb === undefined ? safeSql`` : canCreateDb ? safeSql`createdb` : safeSql`nocreatedb`}
${canCreateRole === undefined ? safeSql`` : canCreateRole ? safeSql`createrole` : safeSql`nocreaterole`}
${inheritRole === undefined ? safeSql`` : inheritRole ? safeSql`inherit` : safeSql`noinherit`}
${canLogin === undefined ? safeSql`` : canLogin ? safeSql`login` : safeSql`nologin`}
${isReplicationRole === undefined ? safeSql`` : isReplicationRole ? safeSql`replication` : safeSql`noreplication`}
${canBypassRls === undefined ? safeSql`` : canBypassRls ? safeSql`bypassrls` : safeSql`nobypassrls`}
${connectionLimit === undefined ? safeSql`` : safeSql`connection limit ${literal(connectionLimit)}`}
${password === undefined ? safeSql`` : safeSql`password ${literal(password)}`}
${validUntil === undefined ? safeSql`` : safeSql`valid until %L`}
', old.name${validUntil === undefined ? safeSql`` : safeSql`, ${literal(validUntil)}`}));
${
newName === undefined
? ''
: `
? safeSql``
: safeSql`
-- Using the same name in the rename clause gives an error, so only do it if the new name is different.
if ${literal(newName)} != old.name then
execute(format('alter role %I rename to %I;', old.name, ${literal(newName)}));
@@ -220,8 +223,8 @@ type RoleRemoveParams = {
function remove(
identifier: RoleIdentifier,
{ ifExists = false }: RoleRemoveParams = {}
): { sql: string } {
const sql = `
): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
declare
old record;
@@ -232,7 +235,7 @@ begin
raise exception 'Cannot find role with id %', id;
end if;
execute(format('drop role ${ifExists ? 'if exists' : ''} %I;', old.name));
execute(format('drop role ${ifExists ? safeSql`if exists` : safeSql``} %I;', old.name));
end
$$;
`
+28 -25
View File
@@ -1,7 +1,7 @@
import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { ident, literal } from './pg-format'
import { ident, joinSqlFragments, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { SCHEMAS_SQL } from './sql/schemas'
const pgSchemaZod = z.object({
@@ -22,18 +22,18 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgSchemaArrayZod
} {
let sql = SCHEMAS_SQL
if (!includeSystemSchemas) {
sql = `${sql} and not (n.nspname in (${DEFAULT_SYSTEM_SCHEMAS.map(literal).join(',')}))`
sql = safeSql`${sql} and not (n.nspname in (${joinSqlFragments(DEFAULT_SYSTEM_SCHEMAS.map(literal), ',')}))`
}
if (limit) {
sql = `${sql} limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql = `${sql} offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -41,20 +41,23 @@ function list({
}
}
function retrieve({ id }: { id: number }): { sql: string; zod: typeof pgSchemaOptionalZod }
function retrieve({ name }: { name: string }): { sql: string; zod: typeof pgSchemaOptionalZod }
function retrieve({ id }: { id: number }): { sql: SafeSqlFragment; zod: typeof pgSchemaOptionalZod }
function retrieve({ name }: { name: string }): {
sql: SafeSqlFragment
zod: typeof pgSchemaOptionalZod
}
function retrieve({ id, name }: { id?: number; name?: string }): {
sql: string
sql: SafeSqlFragment
zod: typeof pgSchemaOptionalZod
} {
if (id) {
const sql = `${SCHEMAS_SQL} and n.oid = ${literal(id)};`
const sql = safeSql`${SCHEMAS_SQL} and n.oid = ${literal(id)};`
return {
sql,
zod: pgSchemaOptionalZod,
}
} else {
const sql = `${SCHEMAS_SQL} and n.nspname = ${literal(name)};`
const sql = safeSql`${SCHEMAS_SQL} and n.nspname = ${literal(name)};`
return {
sql,
zod: pgSchemaOptionalZod,
@@ -66,9 +69,9 @@ type SchemaCreateParams = {
name: string
owner?: string
}
function create({ name, owner }: SchemaCreateParams): { sql: string } {
const sql = `create schema ${ident(name)}
${owner === undefined ? '' : `authorization ${ident(owner)}`};
function create({ name, owner }: SchemaCreateParams): { sql: SafeSqlFragment } {
const sql = safeSql`create schema ${ident(name)}
${owner === undefined ? safeSql`` : safeSql`authorization ${ident(owner)}`};
`
return { sql }
}
@@ -77,8 +80,8 @@ type SchemaUpdateParams = {
name?: string
owner?: string
}
function update({ id }: { id: number }, params: SchemaUpdateParams): { sql: string }
function update({ name }: { name: string }, params: SchemaUpdateParams): { sql: string }
function update({ id }: { id: number }, params: SchemaUpdateParams): { sql: SafeSqlFragment }
function update({ name }: { name: string }, params: SchemaUpdateParams): { sql: SafeSqlFragment }
function update(
{
id,
@@ -88,14 +91,14 @@ function update(
name?: string
},
{ name: newName, owner }: SchemaUpdateParams
): { sql: string } {
const sql = `
): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
declare
id oid := ${id === undefined ? `${literal(name)}::regnamespace` : literal(id)};
id oid := ${id === undefined ? safeSql`${literal(name)}::regnamespace` : literal(id)};
old record;
new_name text := ${newName === undefined ? null : literal(newName)};
new_owner text := ${owner === undefined ? null : literal(owner)};
new_name text := ${newName === undefined ? literal(null) : literal(newName)};
new_owner text := ${owner === undefined ? literal(null) : literal(owner)};
begin
select * into old from pg_namespace where oid = id;
if old is null then
@@ -119,8 +122,8 @@ $$;
type SchemaRemoveParams = {
cascade?: boolean
}
function remove({ id }: { id: number }, params?: SchemaRemoveParams): { sql: string }
function remove({ name }: { name: string }, params?: SchemaRemoveParams): { sql: string }
function remove({ id }: { id: number }, params?: SchemaRemoveParams): { sql: SafeSqlFragment }
function remove({ name }: { name: string }, params?: SchemaRemoveParams): { sql: SafeSqlFragment }
function remove(
{
id,
@@ -130,11 +133,11 @@ function remove(
name?: string
},
{ cascade = false }: SchemaRemoveParams = {}
): { sql: string } {
const sql = `
): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
declare
id oid := ${id === undefined ? `${literal(name)}::regnamespace` : literal(id)};
id oid := ${id === undefined ? safeSql`${literal(name)}::regnamespace` : literal(id)};
old record;
cascade bool := ${literal(cascade)};
begin
@@ -2,7 +2,14 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { ident, literal } from './pg-format'
import {
ident,
joinSqlFragments,
keyword,
literal,
safeSql,
type SafeSqlFragment,
} from './pg-format'
import { TABLE_PRIVILEGES_SQL } from './sql/table-privileges'
const pgTablePrivilegesZod = z.object({
@@ -50,10 +57,10 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgTablePrivilegesArrayZod
} {
let sql = `
let sql = safeSql`
with table_privileges as (${TABLE_PRIVILEGES_SQL})
select *
from table_privileges
@@ -64,13 +71,13 @@ from table_privileges
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += ` where schema ${filter}`
sql = safeSql`${sql} where schema ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -78,9 +85,12 @@ from table_privileges
}
}
function retrieve({ id }: { id: number }): { sql: string; zod: typeof pgTablePrivilegesOptionalZod }
function retrieve({ id }: { id: number }): {
sql: SafeSqlFragment
zod: typeof pgTablePrivilegesOptionalZod
}
function retrieve({ name, schema }: { name: string; schema?: string }): {
sql: string
sql: SafeSqlFragment
zod: typeof pgTablePrivilegesOptionalZod
}
function retrieve({
@@ -92,11 +102,11 @@ function retrieve({
name?: string
schema?: string
}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgTablePrivilegesOptionalZod
} {
if (id) {
const sql = /* SQL */ `
const sql = /* SQL */ safeSql`
with table_privileges as (${TABLE_PRIVILEGES_SQL})
select *
from table_privileges
@@ -106,7 +116,7 @@ where table_privileges.relation_id = ${literal(id)};`
zod: pgTablePrivilegesOptionalZod,
}
} else {
const sql = /* SQL */ `
const sql = /* SQL */ safeSql`
with table_privileges as (${TABLE_PRIVILEGES_SQL})
select *
from table_privileges
@@ -135,18 +145,19 @@ type TablePrivilegesGrant = {
| 'MAINTAIN'
isGrantable?: boolean
}
function grant(grants: TablePrivilegesGrant[]): { sql: string } {
const sql = `
function grant(grants: TablePrivilegesGrant[]): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
begin
${grants
.map(
${joinSqlFragments(
grants.map(
({ privilegeType, relationId, grantee, isGrantable }) =>
`execute format('grant ${privilegeType} on table %s to ${
grantee.toLowerCase() === 'public' ? 'public' : ident(grantee)
} ${isGrantable ? 'with grant option' : ''}', ${relationId}::regclass);`
)
.join('\n')}
safeSql`execute format('grant ${keyword(privilegeType)} on table %s to ${
grantee.toLowerCase() === 'public' ? safeSql`public` : ident(grantee)
} ${isGrantable ? safeSql`with grant option` : safeSql``}', ${literal(relationId)}::regclass);`
),
'\n'
)}
end $$;
`
return { sql }
@@ -166,16 +177,19 @@ type TablePrivilegesRevoke = {
| 'TRIGGER'
| 'MAINTAIN'
}
function revoke(revokes: TablePrivilegesRevoke[]): { sql: string } {
const sql = `
function revoke(revokes: TablePrivilegesRevoke[]): { sql: SafeSqlFragment } {
const sql = safeSql`
do $$
begin
${revokes
.map(
${joinSqlFragments(
revokes.map(
({ privilegeType, relationId, grantee }) =>
`execute format('revoke ${privilegeType} on table %s from ${grantee.toLowerCase() === 'public' ? 'public' : ident(grantee)}', ${relationId}::regclass);`
)
.join('\n')}
safeSql`execute format('revoke ${keyword(privilegeType)} on table %s from ${
grantee.toLowerCase() === 'public' ? safeSql`public` : ident(grantee)
}', ${literal(relationId)}::regclass);`
),
'\n'
)}
end $$;
`
return { sql }
+23 -23
View File
@@ -2,17 +2,17 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { ident, literal } from './pg-format'
import { ident, keyword, literal, safeSql, type SafeSqlFragment } from './pg-format'
import { TRIGGERS_SQL } from './sql/triggers'
type TriggerIdentifier = Pick<PGTrigger, 'id'> | Pick<PGTrigger, 'name' | 'schema' | 'table'>
function getIdentifierWhereClause(identifier: TriggerIdentifier): string {
function getIdentifierWhereClause(identifier: TriggerIdentifier): SafeSqlFragment {
if ('id' in identifier && identifier.id) {
return `${ident('id')} = ${literal(identifier.id)}`
return safeSql`${ident('id')} = ${literal(identifier.id)}`
}
if ('name' in identifier && identifier.name && identifier.table && identifier.schema) {
return `${ident('name')} = ${literal(identifier.name)} and ${ident('schema')} = ${literal(identifier.schema)} and ${ident('table')} = ${literal(identifier.table)}`
return safeSql`${ident('name')} = ${literal(identifier.name)} and ${ident('schema')} = ${literal(identifier.schema)} and ${ident('table')} = ${literal(identifier.table)}`
}
throw new Error('Must provide either id or name, schema and table')
}
@@ -51,23 +51,23 @@ export function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgTriggerArrayZod
} {
let sql = `with triggers as (${TRIGGERS_SQL}) select * from triggers`
let sql = safeSql`with triggers as (${TRIGGERS_SQL}) select * from triggers`
const filter = filterByList(
includedSchemas,
excludedSchemas,
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += ` where schema ${filter}`
sql = safeSql`${sql} where schema ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
@@ -76,14 +76,14 @@ export function list({
}
type TriggersRetrieveReturn = {
sql: string
sql: SafeSqlFragment
zod: typeof pgTriggerOptionalZod
}
export function retrieve(identifier: TriggerIdentifier): TriggersRetrieveReturn
export function retrieve(params: TriggerIdentifier): TriggersRetrieveReturn {
const whereIdentifierCondition = getIdentifierWhereClause(params)
const sql = `with triggers as (${TRIGGERS_SQL}) select * from triggers where ${whereIdentifierCondition};`
const sql = safeSql`with triggers as (${TRIGGERS_SQL}) select * from triggers where ${whereIdentifierCondition};`
return {
sql,
zod: pgTriggerOptionalZod,
@@ -148,23 +148,23 @@ export function update(
id: { name: string; schema: string; table: string },
params: PGTriggerUpdate
): {
sql: string
sql: SafeSqlFragment
zod: z.ZodType<void>
} {
const qualifiedTableName = `${ident(id.schema)}.${ident(id.table)}`
const qualifiedTableName = safeSql`${ident(id.schema)}.${ident(id.table)}`
let enabledModeSql = ''
let enabledModeSql = safeSql``
switch (params.enabled_mode) {
case 'ORIGIN':
enabledModeSql = `alter table ${qualifiedTableName} enable trigger ${ident(id.name)};`
enabledModeSql = safeSql`alter table ${qualifiedTableName} enable trigger ${ident(id.name)};`
break
case 'DISABLED':
enabledModeSql = `alter table ${qualifiedTableName} disable trigger ${ident(id.name)};`
enabledModeSql = safeSql`alter table ${qualifiedTableName} disable trigger ${ident(id.name)};`
break
case 'REPLICA':
case 'ALWAYS':
enabledModeSql = `alter table ${qualifiedTableName} enable ${params.enabled_mode} trigger ${ident(id.name)};`
enabledModeSql = safeSql`alter table ${qualifiedTableName} enable ${keyword(params.enabled_mode)} trigger ${ident(id.name)};`
break
default:
break
@@ -172,11 +172,11 @@ export function update(
const updateNameSql =
params.name && params.name !== id.name
? `alter trigger ${ident(id.name)} on ${qualifiedTableName} rename to ${ident(params.name)};`
: ''
? safeSql`alter trigger ${ident(id.name)} on ${qualifiedTableName} rename to ${ident(params.name)};`
: safeSql``
// updateNameSql must be last
const sql = `begin; ${enabledModeSql}; ${updateNameSql}; commit;`
const sql = safeSql`begin; ${enabledModeSql}; ${updateNameSql}; commit;`
return {
sql,
@@ -188,12 +188,12 @@ export function remove(
id: { name: string; schema: string; table: string },
{ cascade = false } = {}
): {
sql: string
sql: SafeSqlFragment
zod: z.ZodType<void>
} {
const qualifiedTableName = `${ident(id.schema)}.${ident(id.table)}`
const qualifiedTableName = safeSql`${ident(id.schema)}.${ident(id.table)}`
const sql = `drop trigger ${ident(id.name)} on ${qualifiedTableName} ${cascade ? 'cascade' : ''};`
const sql = safeSql`drop trigger ${ident(id.name)} on ${qualifiedTableName} ${cascade ? safeSql`cascade` : safeSql``};`
return {
sql,
+6 -5
View File
@@ -2,6 +2,7 @@ import { z } from 'zod'
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
import { filterByList } from './helpers'
import { literal, safeSql, type SafeSqlFragment } from './pg-format'
import { TYPES_SQL } from './sql/types'
const pgTypeZod = z.object({
@@ -36,12 +37,12 @@ function list({
limit?: number
offset?: number
} = {}): {
sql: string
sql: SafeSqlFragment
zod: typeof pgTypeArrayZod
} {
let sql = TYPES_SQL
if (!includeArrayTypes) {
sql += ` and not exists (
sql = safeSql`${sql} and not exists (
select from pg_type el
where el.oid = t.typelem
and el.typarray = t.oid
@@ -53,13 +54,13 @@ function list({
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
)
if (filter) {
sql += ` and n.nspname ${filter}`
sql = safeSql`${sql} and n.nspname ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
sql = safeSql`${sql} limit ${literal(limit)}`
}
if (offset) {
sql += ` offset ${offset}`
sql = safeSql`${sql} offset ${literal(offset)}`
}
return {
sql,
+2 -1
View File
@@ -1,5 +1,6 @@
import { z } from 'zod'
import { type SafeSqlFragment } from './pg-format'
import { VERSION_SQL } from './sql/version'
export const pgVersionZod = z.object({
@@ -9,7 +10,7 @@ export const pgVersionZod = z.object({
max_connections: z.number(),
})
function retrieve() {
function retrieve(): { sql: SafeSqlFragment; zod: typeof pgVersionZod } {
return {
sql: VERSION_SQL,
zod: pgVersionZod,
+3 -1
View File
@@ -1,4 +1,6 @@
export const CONFIG_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const CONFIG_SQL = /* SQL */ safeSql`
SELECT
name,
setting,
+3 -1
View File
@@ -1,4 +1,6 @@
export const EXTENSIONS_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const EXTENSIONS_SQL = /* SQL */ safeSql`
SELECT
e.name,
n.nspname AS schema,
+3 -1
View File
@@ -1,4 +1,6 @@
export const FUNCTIONS_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const FUNCTIONS_SQL = /* SQL */ safeSql`
-- CTE with sane arg_modes, arg_names, and arg_types.
-- All three are always of the same length.
-- All three include all args, including OUT and TABLE args.
+3 -1
View File
@@ -1,4 +1,6 @@
export const INDEXES_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const INDEXES_SQL = /* SQL */ safeSql`
SELECT
idx.indexrelid::int8 AS id,
idx.indrelid::int8 AS table_id,
+3 -1
View File
@@ -1,4 +1,6 @@
export const POLICIES_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const POLICIES_SQL = /* SQL */ safeSql`
select
pol.oid :: int8 as id,
n.nspname as schema,
+3 -1
View File
@@ -1,4 +1,6 @@
export const PUBLICATIONS_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const PUBLICATIONS_SQL = /* SQL */ safeSql`
SELECT
p.oid :: int8 AS id,
p.pubname AS name,
+3 -1
View File
@@ -1,4 +1,6 @@
export const ROLES_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const ROLES_SQL = /* SQL */ safeSql`
-- Can't use pg_authid here since some managed Postgres providers don't expose it
-- https://github.com/supabase/postgres-meta/issues/212
+3 -1
View File
@@ -1,4 +1,6 @@
export const SCHEMAS_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const SCHEMAS_SQL = /* SQL */ safeSql`
-- Adapted from information_schema.schemata
select
+3 -1
View File
@@ -1,4 +1,6 @@
export const TABLE_PRIVILEGES_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const TABLE_PRIVILEGES_SQL = /* SQL */ safeSql`
-- Despite the name \`table_privileges\`, this includes other kinds of relations:
-- views, matviews, etc. "Relation privileges" just doesn't roll off the tongue.
--
+3 -1
View File
@@ -1,4 +1,6 @@
export const TRIGGERS_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const TRIGGERS_SQL = /* SQL */ safeSql`
SELECT
pg_t.oid AS id,
pg_t.tgrelid AS table_id,
+3 -1
View File
@@ -1,4 +1,6 @@
export const TYPES_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const TYPES_SQL = /* SQL */ safeSql`
select
t.oid::int8 as id,
t.typname as name,
+3 -1
View File
@@ -1,4 +1,6 @@
export const VERSION_SQL = /* SQL */ `
import { safeSql } from '../pg-format'
export const VERSION_SQL = /* SQL */ safeSql`
select
version(),
current_setting('server_version_num')::int8 as version_number,