Skip to content

Commit 238f9c4

Browse files
committed
feat: add column.isGenerated
Add generated columns support for PostgreSQL 12 and later fix #88
1 parent 04b160e commit 238f9c4

File tree

5 files changed

+47
-1
lines changed

5 files changed

+47
-1
lines changed

module-files/sql/12/column.sql

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
SELECT
2+
a.attrelid AS "parentOid",
3+
a.atttypid AS "typeOid",
4+
a.attnum AS "attributeNumber",
5+
c.relkind AS "parentKind", -- r: table, i: index, S: sequence, t: TOAST table, v: view, m: materialized view, c: composite type, f: foreign table, p: partitioned table, I: partitioned index
6+
a.attname AS "name",
7+
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS "defaultWithTypeCast",
8+
a.attnotnull AS "notNull",
9+
format_type(a.atttypid, atttypmod) AS "sqlType",
10+
CASE
11+
WHEN c.relkind = 'v' AND a.attndims = 0 AND right(format_type(a.atttypid, atttypmod), 2) = '[]' THEN 1 -- Cannot find a way to detect array dimensions in views.
12+
ELSE a.attndims
13+
END AS "arrayDimension",
14+
a.attnum AS position,
15+
d.description AS "comment",
16+
a.attgenerated <> '' AS "isGenerated"
17+
FROM
18+
pg_attribute a
19+
INNER JOIN pg_class c ON a.attrelid = c.oid
20+
LEFT JOIN pg_attrdef ad ON (a.attrelid = ad.adrelid
21+
AND a.attnum = ad.adnum)
22+
LEFT JOIN pg_description d ON (a.attrelid = d.objoid
23+
AND a.attnum = d.objsubid)
24+
WHERE
25+
c.relnamespace = ANY ($1)
26+
AND a.attnum > 0
27+
AND NOT a.attisdropped
28+
AND c.relkind IN ('m',
29+
'r',
30+
'v',
31+
'c',
32+
'p')
33+
ORDER BY
34+
c.relnamespace,
35+
LOWER(c.relname),
36+
a.attnum

src/pg-structure/column.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface ColumnConstructorArgs extends DbObjectConstructorArgs {
2626
arrayDimension: number;
2727
defaultWithTypeCast: string | null;
2828
attributeNumber: number;
29+
isGenerated?: boolean;
2930
}
3031

3132
/**
@@ -49,6 +50,7 @@ export default class Column extends DbObject {
4950
this.attributeNumber = args.attributeNumber;
5051
this.minValue = this.isSerial ? 1 : NUMERIC_BOUNDRIES?.[this.type.name]?.min;
5152
this.maxValue = NUMERIC_BOUNDRIES?.[this.type.name]?.max;
53+
this.isGenerated = args.isGenerated === true;
5254
}
5355

5456
/**
@@ -123,6 +125,9 @@ export default class Column extends DbObject {
123125
return isSerial(this.defaultWithTypeCast);
124126
}
125127

128+
/** Whether this column is a generated column. */
129+
public readonly isGenerated: boolean;
130+
126131
/**
127132
* - If data type identifies an exact numeric type, this contains the (declared or implicit) scale
128133
* of the type for this attribute. The scale indicates the number of significant digits to the right of the decimal point.

src/types/query-result.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export interface ColumnQueryResult {
6464
arrayDimension: number;
6565
position: number;
6666
comment: string | null;
67+
isGenerated?: boolean;
6768
}
6869

6970
/** @ignore */

test/column.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,8 @@ describe("Column", () => {
169169
it("should have uniqueIndexesNoPk.", () => {
170170
expect(idColumn.uniqueIndexesNoPk.map((i) => i.name)).toEqual(["ix_partial_unique"]);
171171
});
172+
173+
it("should return false for non generated columns", () => {
174+
expect(accountTable.get("name").isGenerated).toBeFalsy();
175+
});
172176
});

test/pg-structure.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,6 @@ describe("pgStructure()", () => {
8686
it("should accept options as first argument and reads client config from environment variables.", async () => {
8787
process.env.DBPX_USER = "xyz-user";
8888
process.env.DBPX_PASSWORD = "wrong-password";
89-
await expect(pgStructure({ envPrefix: "DBPX", name: "deneme" })).rejects.toThrow('password authentication failed for user "xyz-user"');
89+
await expect(pgStructure({ envPrefix: "DBPX", name: "deneme" })).rejects.toThrow(); // Different pg-version throw different messages.
9090
});
9191
});

0 commit comments

Comments
 (0)