Skip to content

Commit 28cd3e6

Browse files
authored
perf: suboptimal tables query schema filter happens late (#980)
* wip: optimize queries * wip: refactor queries for root filtering * perf: add root level filtering to all queries * feat: add functions args retrieval * chore: fix functions * fix(table): use or for table relationships * test(functions): add tests for retrival argument based
1 parent 4205b26 commit 28cd3e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+788
-654
lines changed

src/lib/PostgresMetaColumnPrivileges.ts

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ident, literal } from 'pg-format'
22
import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js'
3-
import { filterByList } from './helpers.js'
4-
import { columnPrivilegesSql } from './sql/index.js'
3+
import { filterByValue, filterByList } from './helpers.js'
4+
import { COLUMN_PRIVILEGES_SQL } from './sql/column_privileges.sql.js'
55
import {
66
PostgresMetaResult,
77
PostgresColumnPrivileges,
@@ -29,25 +29,12 @@ export default class PostgresMetaColumnPrivileges {
2929
limit?: number
3030
offset?: number
3131
} = {}): Promise<PostgresMetaResult<PostgresColumnPrivileges[]>> {
32-
let sql = `
33-
with column_privileges as (${columnPrivilegesSql})
34-
select *
35-
from column_privileges
36-
`
37-
const filter = filterByList(
32+
const schemaFilter = filterByList(
3833
includedSchemas,
3934
excludedSchemas,
4035
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
4136
)
42-
if (filter) {
43-
sql += ` where relation_schema ${filter}`
44-
}
45-
if (limit) {
46-
sql += ` limit ${limit}`
47-
}
48-
if (offset) {
49-
sql += ` offset ${offset}`
50-
}
37+
const sql = COLUMN_PRIVILEGES_SQL({ schemaFilter, limit, offset })
5138
return await this.query(sql)
5239
}
5340

@@ -86,12 +73,8 @@ end $$;
8673

8774
// Return the updated column privileges for modified columns.
8875
const columnIds = [...new Set(grants.map(({ column_id }) => column_id))]
89-
sql = `
90-
with column_privileges as (${columnPrivilegesSql})
91-
select *
92-
from column_privileges
93-
where column_id in (${columnIds.map(literal).join(',')})
94-
`
76+
const columnIdsFilter = filterByValue(columnIds)
77+
sql = COLUMN_PRIVILEGES_SQL({ columnIdsFilter })
9578
return await this.query(sql)
9679
}
9780

@@ -130,12 +113,8 @@ end $$;
130113

131114
// Return the updated column privileges for modified columns.
132115
const columnIds = [...new Set(revokes.map(({ column_id }) => column_id))]
133-
sql = `
134-
with column_privileges as (${columnPrivilegesSql})
135-
select *
136-
from column_privileges
137-
where column_id in (${columnIds.map(literal).join(',')})
138-
`
116+
const columnIdsFilter = filterByValue(columnIds)
117+
sql = COLUMN_PRIVILEGES_SQL({ columnIdsFilter })
139118
return await this.query(sql)
140119
}
141120
}

src/lib/PostgresMetaColumns.ts

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { ident, literal } from 'pg-format'
22
import PostgresMetaTables from './PostgresMetaTables.js'
33
import { DEFAULT_SYSTEM_SCHEMAS } from './constants.js'
4-
import { columnsSql } from './sql/index.js'
54
import { PostgresMetaResult, PostgresColumn } from './types.js'
6-
import { filterByList } from './helpers.js'
5+
import { filterByValue, filterByList } from './helpers.js'
6+
import { COLUMNS_SQL } from './sql/columns.sql.js'
77

88
export default class PostgresMetaColumns {
99
query: (sql: string) => Promise<PostgresMetaResult<any>>
@@ -29,32 +29,13 @@ export default class PostgresMetaColumns {
2929
limit?: number
3030
offset?: number
3131
} = {}): Promise<PostgresMetaResult<PostgresColumn[]>> {
32-
let sql = `
33-
WITH
34-
columns AS (${columnsSql})
35-
SELECT
36-
*
37-
FROM
38-
columns
39-
WHERE
40-
true`
41-
const filter = filterByList(
32+
const schemaFilter = filterByList(
4233
includedSchemas,
4334
excludedSchemas,
4435
!includeSystemSchemas ? DEFAULT_SYSTEM_SCHEMAS : undefined
4536
)
46-
if (filter) {
47-
sql += ` AND schema ${filter}`
48-
}
49-
if (tableId !== undefined) {
50-
sql += ` AND table_id = ${literal(tableId)}`
51-
}
52-
if (limit) {
53-
sql += ` LIMIT ${limit}`
54-
}
55-
if (offset) {
56-
sql += ` OFFSET ${offset}`
57-
}
37+
const tableIdFilter = tableId ? filterByValue([`${tableId}`]) : undefined
38+
const sql = COLUMNS_SQL({ schemaFilter, tableIdFilter, limit, offset })
5839
return await this.query(sql)
5940
}
6041

@@ -79,14 +60,16 @@ WHERE
7960
table?: string
8061
schema?: string
8162
}): Promise<PostgresMetaResult<PostgresColumn>> {
63+
const schemaFilter = schema ? filterByList([schema], []) : undefined
8264
if (id) {
8365
const regexp = /^(\d+)\.(\d+)$/
8466
if (!regexp.test(id)) {
8567
return { data: null, error: { message: 'Invalid format for column ID' } }
8668
}
8769
const matches = id.match(regexp) as RegExpMatchArray
8870
const [tableId, ordinalPos] = matches.slice(1).map(Number)
89-
const sql = `${columnsSql} AND c.oid = ${tableId} AND a.attnum = ${ordinalPos};`
71+
const idsFilter = filterByValue([`${tableId}.${ordinalPos}`])
72+
const sql = COLUMNS_SQL({ idsFilter })
9073
const { data, error } = await this.query(sql)
9174
if (error) {
9275
return { data, error }
@@ -96,9 +79,8 @@ WHERE
9679
return { data: data[0], error }
9780
}
9881
} else if (name && table) {
99-
const sql = `${columnsSql} AND a.attname = ${literal(name)} AND c.relname = ${literal(
100-
table
101-
)} AND nc.nspname = ${literal(schema)};`
82+
const columnNameFilter = filterByValue([`${table}.${name}`])
83+
const sql = `${COLUMNS_SQL({ schemaFilter, columnNameFilter })};`
10284
const { data, error } = await this.query(sql)
10385
if (error) {
10486
return { data, error }

src/lib/PostgresMetaConfig.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { configSql } from './sql/index.js'
1+
import { CONFIG_SQL } from './sql/config.sql.js'
22
import { PostgresMetaResult, PostgresConfig } from './types.js'
33

44
export default class PostgresMetaConfig {
@@ -15,13 +15,7 @@ export default class PostgresMetaConfig {
1515
limit?: number
1616
offset?: number
1717
} = {}): Promise<PostgresMetaResult<PostgresConfig[]>> {
18-
let sql = configSql
19-
if (limit) {
20-
sql = `${sql} LIMIT ${limit}`
21-
}
22-
if (offset) {
23-
sql = `${sql} OFFSET ${offset}`
24-
}
18+
const sql = CONFIG_SQL({ limit, offset })
2519
return await this.query(sql)
2620
}
2721
}

src/lib/PostgresMetaExtensions.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ident, literal } from 'pg-format'
2-
import { extensionsSql } from './sql/index.js'
32
import { PostgresMetaResult, PostgresExtension } from './types.js'
3+
import { EXTENSIONS_SQL } from './sql/extensions.sql.js'
4+
import { filterByValue } from './helpers.js'
45

56
export default class PostgresMetaExtensions {
67
query: (sql: string) => Promise<PostgresMetaResult<any>>
@@ -16,18 +17,13 @@ export default class PostgresMetaExtensions {
1617
limit?: number
1718
offset?: number
1819
} = {}): Promise<PostgresMetaResult<PostgresExtension[]>> {
19-
let sql = extensionsSql
20-
if (limit) {
21-
sql = `${sql} LIMIT ${limit}`
22-
}
23-
if (offset) {
24-
sql = `${sql} OFFSET ${offset}`
25-
}
20+
const sql = EXTENSIONS_SQL({ limit, offset })
2621
return await this.query(sql)
2722
}
2823

2924
async retrieve({ name }: { name: string }): Promise<PostgresMetaResult<PostgresExtension>> {
30-
const sql = `${extensionsSql} WHERE name = ${literal(name)};`
25+
const nameFilter = filterByValue([name])
26+
const sql = EXTENSIONS_SQL({ nameFilter })
3127
const { data, error } = await this.query(sql)
3228
if (error) {
3329
return { data, error }

src/lib/PostgresMetaForeignTables.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { literal } from 'pg-format'
2-
import { coalesceRowsToArray, filterByList } from './helpers.js'
3-
import { columnsSql, foreignTablesSql } from './sql/index.js'
1+
import { coalesceRowsToArray, filterByList, filterByValue } from './helpers.js'
42
import { PostgresMetaResult, PostgresForeignTable } from './types.js'
3+
import { FOREIGN_TABLES_SQL } from './sql/foreign_tables.sql.js'
4+
import { COLUMNS_SQL } from './sql/columns.sql.js'
55

66
export default class PostgresMetaForeignTables {
77
query: (sql: string) => Promise<PostgresMetaResult<any>>
@@ -37,17 +37,8 @@ export default class PostgresMetaForeignTables {
3737
offset?: number
3838
includeColumns?: boolean
3939
} = {}): Promise<PostgresMetaResult<PostgresForeignTable[]>> {
40-
let sql = generateEnrichedForeignTablesSql({ includeColumns })
41-
const filter = filterByList(includedSchemas, excludedSchemas)
42-
if (filter) {
43-
sql += ` where schema ${filter}`
44-
}
45-
if (limit) {
46-
sql += ` limit ${limit}`
47-
}
48-
if (offset) {
49-
sql += ` offset ${offset}`
50-
}
40+
const schemaFilter = filterByList(includedSchemas, excludedSchemas)
41+
const sql = generateEnrichedForeignTablesSql({ includeColumns, schemaFilter, limit, offset })
5142
return await this.query(sql)
5243
}
5344

@@ -69,9 +60,11 @@ export default class PostgresMetaForeignTables {
6960
schema?: string
7061
}): Promise<PostgresMetaResult<PostgresForeignTable>> {
7162
if (id) {
72-
const sql = `${generateEnrichedForeignTablesSql({
63+
const idsFilter = filterByValue([`${id}`])
64+
const sql = generateEnrichedForeignTablesSql({
7365
includeColumns: true,
74-
})} where foreign_tables.id = ${literal(id)};`
66+
idsFilter,
67+
})
7568
const { data, error } = await this.query(sql)
7669
if (error) {
7770
return { data, error }
@@ -81,11 +74,11 @@ export default class PostgresMetaForeignTables {
8174
return { data: data[0], error }
8275
}
8376
} else if (name) {
84-
const sql = `${generateEnrichedForeignTablesSql({
77+
const nameFilter = filterByValue([`${schema}.${name}`])
78+
const sql = generateEnrichedForeignTablesSql({
8579
includeColumns: true,
86-
})} where foreign_tables.name = ${literal(name)} and foreign_tables.schema = ${literal(
87-
schema
88-
)};`
80+
tableIdentifierFilter: nameFilter,
81+
})
8982
const { data, error } = await this.query(sql)
9083
if (error) {
9184
return { data, error }
@@ -103,9 +96,23 @@ export default class PostgresMetaForeignTables {
10396
}
10497
}
10598

106-
const generateEnrichedForeignTablesSql = ({ includeColumns }: { includeColumns: boolean }) => `
107-
with foreign_tables as (${foreignTablesSql})
108-
${includeColumns ? `, columns as (${columnsSql})` : ''}
99+
const generateEnrichedForeignTablesSql = ({
100+
includeColumns,
101+
schemaFilter,
102+
idsFilter,
103+
tableIdentifierFilter,
104+
limit,
105+
offset,
106+
}: {
107+
includeColumns: boolean
108+
schemaFilter?: string
109+
idsFilter?: string
110+
tableIdentifierFilter?: string
111+
limit?: number
112+
offset?: number
113+
}) => `
114+
with foreign_tables as (${FOREIGN_TABLES_SQL({ schemaFilter, tableIdentifierFilter, limit, offset })})
115+
${includeColumns ? `, columns as (${COLUMNS_SQL({ schemaFilter, tableIdentifierFilter, tableIdFilter: idsFilter })})` : ''}
109116
select
110117
*
111118
${

0 commit comments

Comments
 (0)