@travetto/model-postgres 8.0.0-alpha.24 → 8.0.0-alpha.25
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 +7 -8
- package/__index__.ts +1 -1
- package/package.json +7 -7
- package/src/connection.ts +12 -13
- package/src/dialect.ts +14 -21
- package/support/service.postgresql.ts +1 -1
package/README.md
CHANGED
|
@@ -13,18 +13,18 @@ npm install @travetto/model-postgres
|
|
|
13
13
|
yarn add @travetto/model-postgres
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
This module provides a [Postgres](https://postgresql.org)-based implementation for the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module.
|
|
16
|
+
This module provides a [Postgres](https://postgresql.org)-based implementation for the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module. This source allows the [Data Modeling Support](https://github.com/travetto/travetto/tree/main/module/model#readme "Datastore abstraction for core operations.") module to read, write and query against [SQL](https://en.wikipedia.org/wiki/SQL) databases. In development mode, the [SQLModelService](https://github.com/travetto/travetto/tree/main/module/model-sql/src/service.ts#L69) will also modify the database schema in real time to minimize impact to development.
|
|
17
17
|
|
|
18
|
-
The schema generated will not generally map to existing tables as it is attempting to produce a document store like experience on top of a [SQL](https://en.wikipedia.org/wiki/SQL) database.
|
|
18
|
+
The schema generated will not generally map to existing tables as it is attempting to produce a document store like experience on top of a [SQL](https://en.wikipedia.org/wiki/SQL) database. Every table generated will have a `path_id` which determines it's location in the document hierarchy as well as sub tables will have a `parent_path_id` to associate records with the parent values.
|
|
19
19
|
|
|
20
20
|
Supported features:
|
|
21
|
-
* [
|
|
22
|
-
* [
|
|
23
|
-
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#
|
|
21
|
+
* [Bulk](https://github.com/travetto/travetto/tree/main/module/model/src/types/bulk.ts#L60)
|
|
22
|
+
* [CRUD](https://github.com/travetto/travetto/tree/main/module/model/src/types/crud.ts#L10)
|
|
23
|
+
* [Indexed](https://github.com/travetto/travetto/tree/main/module/model-indexed/src/types/service.ts#L21)
|
|
24
24
|
* [Query Crud](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/crud.ts#L11)
|
|
25
25
|
* [Facet](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/facet.ts#L14)
|
|
26
|
-
* [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/query.ts#L10)
|
|
27
26
|
* [Suggest](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/suggest.ts#L12)
|
|
27
|
+
* [Query](https://github.com/travetto/travetto/tree/main/module/model-query/src/types/query.ts#L10)
|
|
28
28
|
|
|
29
29
|
Out of the box, by installing the module, everything should be wired up by default.If you need to customize any aspect of the source or config, you can override and register it with the [Dependency Injection](https://github.com/travetto/travetto/tree/main/module/di#readme "Dependency registration/management and injection support.") module.
|
|
30
30
|
|
|
@@ -32,9 +32,8 @@ Out of the box, by installing the module, everything should be wired up by defau
|
|
|
32
32
|
```typescript
|
|
33
33
|
import type { AsyncContext } from '@travetto/context';
|
|
34
34
|
import { InjectableFactory } from '@travetto/di';
|
|
35
|
-
|
|
36
|
-
import { SQLModelService, type SQLModelConfig } from '@travetto/model-sql';
|
|
37
35
|
import { PostgreSQLDialect } from '@travetto/model-postgres';
|
|
36
|
+
import { type SQLModelConfig, SQLModelService } from '@travetto/model-sql';
|
|
38
37
|
|
|
39
38
|
export class Init {
|
|
40
39
|
@InjectableFactory({ primary: true })
|
package/__index__.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/model-postgres",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.25",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PostgreSQL backing for the travetto model module, with real-time modeling support for SQL schemas.",
|
|
6
6
|
"keywords": [
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
"directory": "module/model-postgres"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@travetto/config": "^8.0.0-alpha.
|
|
32
|
-
"@travetto/context": "^8.0.0-alpha.
|
|
33
|
-
"@travetto/model": "^8.0.0-alpha.
|
|
34
|
-
"@travetto/model-query": "^8.0.0-alpha.
|
|
35
|
-
"@travetto/model-sql": "^8.0.0-alpha.
|
|
31
|
+
"@travetto/config": "^8.0.0-alpha.22",
|
|
32
|
+
"@travetto/context": "^8.0.0-alpha.20",
|
|
33
|
+
"@travetto/model": "^8.0.0-alpha.23",
|
|
34
|
+
"@travetto/model-query": "^8.0.0-alpha.24",
|
|
35
|
+
"@travetto/model-sql": "^8.0.0-alpha.25",
|
|
36
36
|
"@types/pg": "^8.20.0",
|
|
37
37
|
"pg": "^8.22.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
40
|
+
"@travetto/cli": "^8.0.0-alpha.28"
|
|
41
41
|
},
|
|
42
42
|
"peerDependenciesMeta": {
|
|
43
43
|
"@travetto/cli": {
|
package/src/connection.ts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { type Pool, type PoolClient, default as pg } from 'pg';
|
|
2
2
|
|
|
3
|
-
import { castTo, ShutdownManager } from '@travetto/runtime';
|
|
4
3
|
import { type AsyncContext, WithAsyncContext } from '@travetto/context';
|
|
5
4
|
import { ExistsError } from '@travetto/model';
|
|
6
|
-
import { type SQLModelConfig
|
|
5
|
+
import { Connection, type SQLModelConfig } from '@travetto/model-sql';
|
|
6
|
+
import { castTo, ShutdownManager } from '@travetto/runtime';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Connection support for postgresql
|
|
10
10
|
*/
|
|
11
11
|
export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
12
|
-
|
|
13
12
|
#pool: Pool;
|
|
14
13
|
#config: SQLModelConfig;
|
|
15
14
|
|
|
16
|
-
constructor(
|
|
17
|
-
context: AsyncContext,
|
|
18
|
-
config: SQLModelConfig
|
|
19
|
-
) {
|
|
15
|
+
constructor(context: AsyncContext, config: SQLModelConfig) {
|
|
20
16
|
super(context);
|
|
21
17
|
this.#config = config;
|
|
22
18
|
}
|
|
@@ -33,7 +29,7 @@ export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
|
33
29
|
host: this.#config.host,
|
|
34
30
|
port: this.#config.port,
|
|
35
31
|
...castTo({
|
|
36
|
-
parseInputDatesAsUTC: true
|
|
32
|
+
parseInputDatesAsUTC: true
|
|
37
33
|
}),
|
|
38
34
|
...(this.#config.options || {})
|
|
39
35
|
});
|
|
@@ -52,7 +48,7 @@ export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
|
52
48
|
ShutdownManager.signal.addEventListener('abort', () => this.#pool.end());
|
|
53
49
|
}
|
|
54
50
|
|
|
55
|
-
async execute<T = unknown>(pool: PoolClient, query: string, values?: unknown[]): Promise<{ count: number
|
|
51
|
+
async execute<T = unknown>(pool: PoolClient, query: string, values?: unknown[]): Promise<{ count: number; records: T[] }> {
|
|
56
52
|
console.debug('Executing query', { query });
|
|
57
53
|
try {
|
|
58
54
|
const out = await pool.query(query, values);
|
|
@@ -62,10 +58,13 @@ export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
|
62
58
|
const code = error && typeof error === 'object' && 'code' in error ? error.code : undefined;
|
|
63
59
|
switch (code) {
|
|
64
60
|
// Index already exists
|
|
65
|
-
case '42P07':
|
|
61
|
+
case '42P07':
|
|
62
|
+
throw new ExistsError('index', query);
|
|
66
63
|
// Unique violation
|
|
67
|
-
case '23505':
|
|
68
|
-
|
|
64
|
+
case '23505':
|
|
65
|
+
throw new ExistsError('query', query);
|
|
66
|
+
default:
|
|
67
|
+
throw error;
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
}
|
|
@@ -77,4 +76,4 @@ export class PostgreSQLConnection extends Connection<PoolClient> {
|
|
|
77
76
|
release(pool: PoolClient): void {
|
|
78
77
|
pool.release();
|
|
79
78
|
}
|
|
80
|
-
}
|
|
79
|
+
}
|
package/src/dialect.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { SchemaFieldConfig } from '@travetto/schema';
|
|
2
|
-
import { Injectable } from '@travetto/di';
|
|
3
1
|
import type { AsyncContext } from '@travetto/context';
|
|
2
|
+
import { Injectable } from '@travetto/di';
|
|
4
3
|
import type { ModelType } from '@travetto/model';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import
|
|
4
|
+
import { SQLDialect, type SQLModelConfig, SQLModelUtil, type SQLTableDescription, type VisitStack } from '@travetto/model-sql';
|
|
5
|
+
import { type Class, castTo } from '@travetto/runtime';
|
|
6
|
+
import type { SchemaFieldConfig } from '@travetto/schema';
|
|
8
7
|
|
|
9
8
|
import { PostgreSQLConnection } from './connection.ts';
|
|
10
9
|
|
|
@@ -13,7 +12,6 @@ import { PostgreSQLConnection } from './connection.ts';
|
|
|
13
12
|
*/
|
|
14
13
|
@Injectable()
|
|
15
14
|
export class PostgreSQLDialect extends SQLDialect {
|
|
16
|
-
|
|
17
15
|
connection: PostgreSQLConnection;
|
|
18
16
|
|
|
19
17
|
constructor(context: AsyncContext, config: SQLModelConfig) {
|
|
@@ -48,7 +46,7 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
48
46
|
const IGNORE_FIELDS = [this.pathField.name, this.parentPathField.name, this.idxField.name].map(field => `'${field}'`);
|
|
49
47
|
|
|
50
48
|
// 1. Columns
|
|
51
|
-
const columns = await this.executeSQL<{ name: string
|
|
49
|
+
const columns = await this.executeSQL<{ name: string; type: string; is_not_null: boolean }>(`
|
|
52
50
|
SELECT
|
|
53
51
|
a.attname AS name,
|
|
54
52
|
pg_catalog.format_type(a.atttypid, a.atttypmod) AS type,
|
|
@@ -72,7 +70,7 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
// 2. Foreign Keys
|
|
75
|
-
const foreignKeys = await this.executeSQL<{ name: string
|
|
73
|
+
const foreignKeys = await this.executeSQL<{ name: string; from_column: string; to_column: string; to_table: string }>(`
|
|
76
74
|
SELECT
|
|
77
75
|
tc.constraint_name AS name,
|
|
78
76
|
kcu.column_name AS from_column,
|
|
@@ -88,7 +86,7 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
88
86
|
`);
|
|
89
87
|
|
|
90
88
|
// 3. Indices
|
|
91
|
-
const indices = await this.executeSQL<{ name: string
|
|
89
|
+
const indices = await this.executeSQL<{ name: string; is_unique: boolean; columns: string[] }>(`
|
|
92
90
|
SELECT
|
|
93
91
|
i.relname AS name,
|
|
94
92
|
ix.indisunique AS is_unique,
|
|
@@ -109,20 +107,15 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
109
107
|
return {
|
|
110
108
|
columns: columns.records.map(col => ({
|
|
111
109
|
...col,
|
|
112
|
-
type: col.type.toUpperCase()
|
|
113
|
-
.replace('CHARACTER VARYING', 'VARCHAR')
|
|
114
|
-
.replace('INTEGER', 'INT'),
|
|
110
|
+
type: col.type.toUpperCase().replace('CHARACTER VARYING', 'VARCHAR').replace('INTEGER', 'INT'),
|
|
115
111
|
is_not_null: !!col.is_not_null
|
|
116
112
|
})),
|
|
117
113
|
foreignKeys: foreignKeys.records,
|
|
118
|
-
indices: indices.records
|
|
119
|
-
.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.map(column => column.split(' '))
|
|
124
|
-
.map(([name, desc]) => ({ name, desc: desc === '1' }))
|
|
125
|
-
}))
|
|
114
|
+
indices: indices.records.map(idx => ({
|
|
115
|
+
name: idx.name,
|
|
116
|
+
is_unique: idx.is_unique,
|
|
117
|
+
columns: idx.columns.map(column => column.split(' ')).map(([name, desc]) => ({ name, desc: desc === '1' }))
|
|
118
|
+
}))
|
|
126
119
|
};
|
|
127
120
|
}
|
|
128
121
|
|
|
@@ -142,4 +135,4 @@ export class PostgreSQLDialect extends SQLDialect {
|
|
|
142
135
|
override getTruncateAllTablesSQL<T extends ModelType>(cls: Class<T>): string[] {
|
|
143
136
|
return [`TRUNCATE ${this.table(SQLModelUtil.classToStack(cls))} CASCADE;`];
|
|
144
137
|
}
|
|
145
|
-
}
|
|
138
|
+
}
|