Skip to content

Commit

Permalink
analyze-select-statement - renaming for "view-result" since it isn't …
Browse files Browse the repository at this point in the history
…just about views now (updated 13:08)
  • Loading branch information
mmkal committed Sep 4, 2024
1 parent c210bfa commit f88c54f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import * as lodash from 'lodash'

/**
* Returns a list of results that stem from a special query used to retrieve type information from the database.
* @param pool
* @param viewFriendlySql the query to be analysed
* @returns
* @param client
* @param selectStatementSql the query to be analysed - must be a single select statement
*/
export const getViewResult = async (pool: Client, viewFriendlySql: string): Promise<ViewResult[]> => {
const viewResultQuery = sql<ViewResult>`
export const analyzeSelectStatement = async (
client: Client,
selectStatementSql: string,
): Promise<SelectStatementAnalyzedColumn[]> => {
const viewResultQuery = sql<SelectStatementAnalyzedColumn>`
select
schema_name,
table_column_name,
Expand All @@ -18,12 +20,12 @@ export const getViewResult = async (pool: Client, viewFriendlySql: string): Prom
comment,
formatted_query
from
pg_temp.gettypes(${viewFriendlySql})
pg_temp.analyze_select_statement_columns(${selectStatementSql})
`
return pool.transaction(async t => {
await t.query(getTypesSql)
const results = await t.any<ViewResult>(viewResultQuery)
const deduped = lodash.uniqBy<ViewResult>(results, JSON.stringify)
return client.transaction(async t => {
await t.query(defineAnalyzeSelectStatementColumnsFunction)
const results = await t.any<SelectStatementAnalyzedColumn>(viewResultQuery)
const deduped = lodash.uniqBy<SelectStatementAnalyzedColumn>(results, JSON.stringify)
const formattedSqlStatements = lodash.uniqBy(deduped, r => r.formatted_query)

assert.ok(
Expand All @@ -35,8 +37,8 @@ export const getViewResult = async (pool: Client, viewFriendlySql: string): Prom
})
}

// this query is for a type in a temp schema so this tool doesn't work with it
export type ViewResult = {
// can't use typegen here because it relies on a function in a temp schema
export type SelectStatementAnalyzedColumn = {
/** postgres type: `text` */
schema_name: string | null

Expand All @@ -59,7 +61,7 @@ export type ViewResult = {
/**
* A query, which creates a tmp table for the purpose of analysing types of another query
*/
const getTypesSql = sql`
const defineAnalyzeSelectStatementColumnsFunction = sql`
drop type if exists pg_temp.types_type cascade;
create type pg_temp.types_type as (
Expand All @@ -77,7 +79,7 @@ const getTypesSql = sql`
-- and https://www.cybertec-postgresql.com/en/abusing-postgresql-as-an-sql-beautifier
-- nullable: https://stackoverflow.com/a/63980243
create or replace function pg_temp.gettypes(sql_query text)
create or replace function pg_temp.analyze_select_statement_columns(sql_query text)
returns setof pg_temp.types_type as
$$
declare
Expand Down
10 changes: 5 additions & 5 deletions packages/typegen/src/query/column-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {singular} from 'pluralize'
import {AnalysedQuery, AnalysedQueryField, DescribedQuery, QueryField} from '../types'
import {tryOrDefault} from '../util'
import {memoizeQueryFn} from '../utils/memoize'
import {SelectStatementAnalyzedColumn, analyzeSelectStatement} from './analyze-select-statement'
import {aliasMappings, getASTModifiedToSingleSelect, getSuggestedTags, suggestedTags, templateToValidSql} from './parse'
import {ViewResult, getViewResult} from './view-result'

export class AnalyseQueryError extends Error {
public readonly [Symbol.toStringTag] = 'AnalyseQueryError'
Expand All @@ -36,22 +36,22 @@ export const getColumnInfo = memoizeQueryFn(async (pool: Client, query: Describe

const singleSelectAst = modifiedAST.ast
const singleSelectSql = toSql.statement(singleSelectAst)
const viewResult = modifiedAST.modifications.includes('cte')
const analyzedSelectStatement = modifiedAST.modifications.includes('cte')
? [] // not smart enough to figure out what types are referenced via a CTE
: await getViewResult(pool, singleSelectSql)
: await analyzeSelectStatement(pool, singleSelectSql)

return {
...query,
suggestedTags: generateTags(query),
fields: query.fields.map(field => getFieldInfo(viewResult, singleSelectAst, field)),
fields: query.fields.map(field => getFieldInfo(analyzedSelectStatement, singleSelectAst, field)),
}
} catch (e) {
const recover = getDefaultAnalysedQuery(query)
throw new AnalyseQueryError(e, query, recover)
}
})

const getFieldInfo = (viewResult: ViewResult[], ast: SelectFromStatement, field: QueryField) => {
const getFieldInfo = (viewResult: SelectStatementAnalyzedColumn[], ast: SelectFromStatement, field: QueryField) => {
const viewableAst =
viewResult[0]?.formatted_query === undefined
? ast //
Expand Down

0 comments on commit f88c54f

Please sign in to comment.