diff --git a/grafast/dataplan-pg/src/steps/pgSelect.ts b/grafast/dataplan-pg/src/steps/pgSelect.ts index c1ea34232..3d07aee5c 100644 --- a/grafast/dataplan-pg/src/steps/pgSelect.ts +++ b/grafast/dataplan-pg/src/steps/pgSelect.ts @@ -251,6 +251,10 @@ export interface PgSelectOptions< joinAsLateral?: boolean; } +function withIndexes(frag: SQL, idx: number) { + return sql`${frag} as ${sql.identifier(String(idx))}`; +} + /** * This represents selecting from a class-like entity (table, view, etc); i.e. * it represents `SELECT , FROM `. You can also add @@ -1430,6 +1434,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} private buildSelect( options: { extraSelects?: readonly SQL[]; + asJsonAgg?: boolean; } = Object.create(null), ) { const { extraSelects = EMPTY_ARRAY } = options; @@ -1437,20 +1442,22 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} const l = this.selects.length; const extraSelectIndexes = extraSelects.map((_, i) => i + l); - const fragmentsWithAliases = selects.map( - (frag, idx) => sql`${frag} as ${sql.identifier(String(idx))}`, - ); - const sqlAliases: SQL[] = []; for (const [a, b] of this._symbolSubstitutes.entries()) { sqlAliases.push(sql.symbolAlias(a, b)); } const aliases = sql.join(sqlAliases, ""); - const selection = - fragmentsWithAliases.length > 0 - ? sql`\n${sql.indent(sql.join(fragmentsWithAliases, ",\n"))}` - : sql` /* NOTHING?! */`; + const selection = options.asJsonAgg + ? selects.length === 0 + ? // Postgres "cannot accumulate empty arrays" + sql`\n${sql.indent`array[null::text]`}` + : sql`\n${sql.indent`array[${sql.indent( + sql.join(selects, ",\n"), + )}]::text[]`}` + : selects.length > 0 + ? sql`\n${sql.indent(sql.join(selects.map(withIndexes), ",\n"))}` + : sql` /* NOTHING?! */`; return { sql: sql`${aliases}select${selection}`, extraSelectIndexes }; } @@ -1837,7 +1844,7 @@ and ${sql.indent(sql.parens(condition(i + 1)))}`} const baseQuery = sql`${select}${from}${join}${where}${groupBy}${having}${orderBy}${limitAndOffset}`; const query = options.asJsonAgg ? // 's' for 'subquery' - sql`select json_agg(s) from (${sql.indent(baseQuery)}) s` + sql`array(${sql.indent(baseQuery)})::text` : baseQuery; return { sql: query, extraSelectIndexes };