Skip to content

Commit

Permalink
hotfix: fetch the proper res target name from subselect (#365)
Browse files Browse the repository at this point in the history
hotfix: fetch the proper res target name from subselect
  • Loading branch information
Newbie012 authored Jan 7, 2025
1 parent b434ca6 commit af2f38e
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/sharp-hairs-share.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@ts-safeql/generate": patch
---

fixed an issue when dealing with column reference alias inside a subselect
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
fail-fast: false
services:
postgres:
image: postgres:14
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
Expand Down
8 changes: 6 additions & 2 deletions packages/generate/src/ast-describe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export type ASTDescribedColumnType =
| { kind: "union"; value: ASTDescribedColumnType[] }
| { kind: "array"; value: ASTDescribedColumnType }
| { kind: "object"; value: [string, ASTDescribedColumnType][] }
| { kind: "type"; value: string; type: string }
| { kind: "type"; value: string; type: string; base?: string }
| { kind: "literal"; value: string; base: ASTDescribedColumnType };

export function getASTDescription(params: ASTDescriptionOptions): Map<number, ASTDescribedColumn> {
Expand Down Expand Up @@ -133,6 +133,10 @@ export function getASTDescription(params: ASTDescriptionOptions): Map<number, AS
type: params.pgTypes.get(p.oid)?.name ?? "unknown",
};

if (p.baseOid !== null) {
type.base = params.pgTypes.get(p.baseOid)?.name;
}

return isArray ? { kind: "array", value: type } : type;
},
};
Expand Down Expand Up @@ -264,7 +268,7 @@ function getDescribedAExpr({
}

if (column.type.kind === "type") {
return { value: column.type.type, nullable: false };
return { value: column.type.base ?? column.type.type, nullable: false };
}

if (column.type.kind === "literal" && column.type.base.kind === "type") {
Expand Down
66 changes: 65 additions & 1 deletion packages/generate/src/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,9 @@ test("select enum", async () => {
test("select domain type", async () => {
await testQuery({
query: `SELECT phone_number from caregiver_phonenumber`,
expected: [["phone_number", { kind: "type", value: "string", type: "phone_number" }]],
expected: [
["phone_number", { kind: "type", value: "string", type: "phone_number", base: "text" }],
],
});
});

Expand Down Expand Up @@ -1667,6 +1669,35 @@ test("select case when with jsonb_build_object", async () => {
});
});

test("select case when with jsonb_build_object and left join", async () => {
await testQuery({
query: `
SELECT
CASE WHEN caregiver.id IS NOT NULL
THEN jsonb_build_object('is_test', phonenumber.phone_number NOT LIKE '%212718%')
ELSE NULL
END AS col
FROM caregiver
JOIN caregiver_phonenumber phonenumber ON caregiver.id = phonenumber.caregiver_id
`,
expected: [
[
"col",
{
kind: "union",
value: [
{
kind: "object",
value: [["is_test", { kind: "type", type: "bool", value: "boolean" }]],
},
{ kind: "type", type: "null", value: "null" },
],
},
],
],
});
});

test("1 + 2 => number", async () => {
await testQuery({
query: `SELECT 1 + 2`,
Expand Down Expand Up @@ -2002,3 +2033,36 @@ test("2 ^ 3 => number", async () => {
expected: [["?column?", { kind: "type", value: "number", type: "float8" }]],
});
});

test("select alias from subselect", async () => {
await testQuery({
query: `
SELECT x.*
FROM (
SELECT caregiver.id IS NOT NULL AS test
FROM caregiver
) x
`,
expected: [["test", { kind: "type", type: "int4", value: "number" }]],
});
});

test("select cols from function range", async () => {
await testQuery({
query: `
SELECT
a.id,
t.metadata IS NOT NULL AS "exists"
FROM
UNNEST(ARRAY[1, 2]) AS a(id)
LEFT JOIN (
VALUES (1, 'foo'), (2, null)
) AS t(id, metadata) ON t.id = a.id;
`,
expected: [
["id", { kind: "type", type: "bool", value: "boolean" }],
["exists", { kind: "type", type: "bool", value: "boolean" }],
],
unknownColumns: ["exists"], // TODO: `ast-get-source` needs to be refactored to handle this case
});
});
4 changes: 2 additions & 2 deletions packages/generate/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type JSToPostgresTypeMap = Record<string, unknown>;
type Sql = postgres.Sql<JSToPostgresTypeMap>;

export type ResolvedTarget =
| { kind: "type"; value: string; type: string }
| { kind: "type"; value: string; type: string; base?: string }
| { kind: "literal"; value: string; base: ResolvedTarget }
| { kind: "union"; value: ResolvedTarget[] }
| { kind: "array"; value: ResolvedTarget; syntax?: "array-type" | "type-reference" }
Expand Down Expand Up @@ -444,7 +444,7 @@ function getResolvedTargetEntry(params: {
}): ResolvedTargetEntry {
if (params.col.astDescribed !== undefined) {
return [
toCase(params.col.astDescribed.name, params.context.fieldTransform),
toCase(params.col.described.name, params.context.fieldTransform),
params.col.astDescribed.type,
];
}
Expand Down
6 changes: 5 additions & 1 deletion packages/generate/src/utils/get-relations-with-joins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,11 @@ function recursiveTraverseJoins(
return recursiveTraverseJoins([join, ...joins], joinExpr.rarg?.JoinExpr);
}

const relName = joinExpr.larg?.RangeVar?.relname ?? joinExpr.rarg?.RangeVar?.relname;
const relName =
joinExpr.larg?.RangeVar?.relname ??
joinExpr.larg?.RangeFunction?.alias?.aliasname ??
joinExpr.rarg?.RangeVar?.relname ??
joinExpr.rarg?.RangeFunction?.alias?.aliasname;

if (relName === undefined) {
throw new Error("relName is undefined");
Expand Down

0 comments on commit af2f38e

Please sign in to comment.