@travetto/model-postgres 7.0.0-rc.2 → 7.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/package.json +7 -7
- package/src/connection.ts +7 -4
- package/src/dialect.ts +85 -1
- package/support/service.postgresql.ts +2 -2
package/README.md
CHANGED
|
@@ -60,11 +60,11 @@ export class SQLModelConfig<T extends {} = {}> {
|
|
|
60
60
|
/**
|
|
61
61
|
* Username
|
|
62
62
|
*/
|
|
63
|
-
user = '';
|
|
63
|
+
user = Runtime.production ? '' : 'travetto';
|
|
64
64
|
/**
|
|
65
65
|
* Password
|
|
66
66
|
*/
|
|
67
|
-
password = '';
|
|
67
|
+
password = Runtime.production ? '' : 'travetto';
|
|
68
68
|
/**
|
|
69
69
|
* Table prefix
|
|
70
70
|
*/
|
|
@@ -74,9 +74,9 @@ export class SQLModelConfig<T extends {} = {}> {
|
|
|
74
74
|
*/
|
|
75
75
|
database = 'app';
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
77
|
+
* Allow storage modification at runtime
|
|
78
78
|
*/
|
|
79
|
-
|
|
79
|
+
modifyStorage?: boolean;
|
|
80
80
|
/**
|
|
81
81
|
* Db version
|
|
82
82
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-postgres",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.4",
|
|
4
4
|
"description": "PostgreSQL backing for the travetto model module, with real-time modeling support for SQL schemas.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sql",
|
|
@@ -27,12 +27,12 @@
|
|
|
27
27
|
"directory": "module/model-postgres"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@travetto/cli": "^7.0.0-rc.
|
|
31
|
-
"@travetto/config": "^7.0.0-rc.
|
|
32
|
-
"@travetto/context": "^7.0.0-rc.
|
|
33
|
-
"@travetto/model": "^7.0.0-rc.
|
|
34
|
-
"@travetto/model-query": "^7.0.0-rc.
|
|
35
|
-
"@travetto/model-sql": "^7.0.0-rc.
|
|
30
|
+
"@travetto/cli": "^7.0.0-rc.4",
|
|
31
|
+
"@travetto/config": "^7.0.0-rc.4",
|
|
32
|
+
"@travetto/context": "^7.0.0-rc.4",
|
|
33
|
+
"@travetto/model": "^7.0.0-rc.4",
|
|
34
|
+
"@travetto/model-query": "^7.0.0-rc.4",
|
|
35
|
+
"@travetto/model-sql": "^7.0.0-rc.4",
|
|
36
36
|
"@types/pg": "^8.15.6",
|
|
37
37
|
"pg": "^8.16.3"
|
|
38
38
|
},
|
package/src/connection.ts
CHANGED
|
@@ -59,10 +59,13 @@ export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
|
59
59
|
const records: T[] = [...out.rows].map(value => ({ ...value }));
|
|
60
60
|
return { count: out.rowCount!, records };
|
|
61
61
|
} catch (error) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
throw
|
|
62
|
+
const code = error && typeof error === 'object' && 'code' in error ? error.code : undefined;
|
|
63
|
+
switch (code) {
|
|
64
|
+
// Index already exists
|
|
65
|
+
case '42P07': throw new ExistsError('index', query);
|
|
66
|
+
// Unique violation
|
|
67
|
+
case '23505': throw new ExistsError('query', query);
|
|
68
|
+
default: throw error;
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
}
|
package/src/dialect.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AsyncContext } from '@travetto/context';
|
|
|
4
4
|
import { ModelType } from '@travetto/model';
|
|
5
5
|
import { castTo, Class } from '@travetto/runtime';
|
|
6
6
|
|
|
7
|
-
import { SQLDialect, SQLModelConfig, SQLModelUtil, VisitStack } from '@travetto/model-sql';
|
|
7
|
+
import { SQLDialect, SQLModelConfig, SQLModelUtil, VisitStack, type SQLTableDescription } from '@travetto/model-sql';
|
|
8
8
|
|
|
9
9
|
import { PostgreSQLConnection } from './connection.ts';
|
|
10
10
|
|
|
@@ -44,6 +44,90 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
44
44
|
return `encode(digest('${value}', 'sha1'), 'hex')`;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
async describeTable(table: string): Promise<SQLTableDescription | undefined> {
|
|
48
|
+
const IGNORE_FIELDS = [this.pathField.name, this.parentPathField.name, this.idxField.name].map(field => `'${field}'`);
|
|
49
|
+
|
|
50
|
+
const [columns, foreignKeys, indices] = await Promise.all([
|
|
51
|
+
// 1. Columns
|
|
52
|
+
this.executeSQL<{ name: string, type: string, is_notnull: boolean }>(`
|
|
53
|
+
SELECT
|
|
54
|
+
a.attname AS name,
|
|
55
|
+
pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
|
|
56
|
+
a.attnotnull AS is_notnull
|
|
57
|
+
FROM pg_catalog.pg_attribute a
|
|
58
|
+
JOIN pg_catalog.pg_class c ON c.oid = a.attrelid
|
|
59
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
|
60
|
+
LEFT JOIN
|
|
61
|
+
pg_catalog.pg_attrdef ad ON ad.adrelid = c.oid AND ad.adnum = a.attnum
|
|
62
|
+
WHERE
|
|
63
|
+
c.relname = '${table}'
|
|
64
|
+
AND a.attnum > 0
|
|
65
|
+
AND NOT a.attisdropped
|
|
66
|
+
AND a.attname NOT IN (${IGNORE_FIELDS.join(',')})
|
|
67
|
+
ORDER BY
|
|
68
|
+
a.attnum;
|
|
69
|
+
`),
|
|
70
|
+
|
|
71
|
+
// 2. Foreign Keys
|
|
72
|
+
this.executeSQL<{ name: string, from_column: string, to_column: string, to_table: string }>(`
|
|
73
|
+
SELECT
|
|
74
|
+
tc.constraint_name AS name,
|
|
75
|
+
kcu.column_name AS from_column,
|
|
76
|
+
ccu.column_name AS to_column,
|
|
77
|
+
ccu.table_name AS to_table
|
|
78
|
+
FROM information_schema.table_constraints AS tc
|
|
79
|
+
JOIN information_schema.key_column_usage AS kcu
|
|
80
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
81
|
+
JOIN information_schema.constraint_column_usage AS ccu
|
|
82
|
+
ON ccu.constraint_name = tc.constraint_name
|
|
83
|
+
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
84
|
+
AND tc.table_name = '${table}'
|
|
85
|
+
`),
|
|
86
|
+
|
|
87
|
+
// 3. Indices
|
|
88
|
+
this.executeSQL<{ name: string, is_unique: boolean, columns: string[] }>(`
|
|
89
|
+
SELECT
|
|
90
|
+
i.relname AS name,
|
|
91
|
+
ix.indisunique AS is_unique,
|
|
92
|
+
ARRAY_AGG(a.attname || ' '|| CAST((o.OPTION & 1) AS VARCHAR) ORDER BY array_position(ix.indkey, a.attnum)) AS columns
|
|
93
|
+
FROM pg_class t
|
|
94
|
+
JOIN pg_index ix ON t.oid = ix.indrelid
|
|
95
|
+
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
96
|
+
CROSS JOIN LATERAL UNNEST(ix.indkey) WITH ordinality AS c (colnum, ordinality)
|
|
97
|
+
LEFT JOIN LATERAL UNNEST(ix.indoption) WITH ordinality AS o (OPTION, ordinality) ON c.ordinality = o.ordinality
|
|
98
|
+
LEFT JOIN pg_catalog.pg_constraint co ON co.conindid = ix.indexrelid
|
|
99
|
+
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = c.colnum
|
|
100
|
+
WHERE t.relname = '${table}'
|
|
101
|
+
AND NOT ix.indisprimary
|
|
102
|
+
AND co.conindid IS NULL
|
|
103
|
+
GROUP BY i.relname, ix.indisunique
|
|
104
|
+
`)
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
if (!columns.count) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
columns: columns.records.map(col => ({
|
|
113
|
+
...col,
|
|
114
|
+
type: col.type.toUpperCase()
|
|
115
|
+
.replace('CHARACTER VARYING', 'VARCHAR')
|
|
116
|
+
.replace('INTEGER', 'INT'),
|
|
117
|
+
is_notnull: !!col.is_notnull
|
|
118
|
+
})),
|
|
119
|
+
foreignKeys: foreignKeys.records,
|
|
120
|
+
indices: indices.records
|
|
121
|
+
.map(idx => ({
|
|
122
|
+
name: idx.name,
|
|
123
|
+
is_unique: idx.is_unique,
|
|
124
|
+
columns: idx.columns
|
|
125
|
+
.map(column => column.split(' '))
|
|
126
|
+
.map(([name, desc]) => ({ name, desc: desc === '1' }))
|
|
127
|
+
}))
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
47
131
|
/**
|
|
48
132
|
* Define column modification
|
|
49
133
|
*/
|
|
@@ -8,8 +8,8 @@ export const service: ServiceDescriptor = {
|
|
|
8
8
|
port: 5432,
|
|
9
9
|
image: `postgres:${version}-alpine`,
|
|
10
10
|
env: {
|
|
11
|
-
POSTGRES_USER: '
|
|
12
|
-
POSTGRES_PASSWORD: '
|
|
11
|
+
POSTGRES_USER: 'travetto',
|
|
12
|
+
POSTGRES_PASSWORD: 'travetto',
|
|
13
13
|
POSTGRES_DB: 'app'
|
|
14
14
|
}
|
|
15
15
|
};
|