@mikro-orm/postgresql 7.0.0-dev.102 → 7.0.0-dev.103
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/PostgreSqlPlatform.d.ts +2 -103
- package/PostgreSqlPlatform.js +2 -350
- package/index.d.ts +0 -3
- package/index.js +0 -3
- package/package.json +3 -3
- package/PostgreSqlExceptionConverter.d.ts +0 -8
- package/PostgreSqlExceptionConverter.js +0 -47
- package/PostgreSqlSchemaHelper.d.ts +0 -56
- package/PostgreSqlSchemaHelper.js +0 -548
- package/types/FullTextType.d.ts +0 -14
- package/types/FullTextType.js +0 -59
- package/types/index.d.ts +0 -1
- package/types/index.js +0 -1
package/PostgreSqlPlatform.d.ts
CHANGED
|
@@ -1,112 +1,11 @@
|
|
|
1
1
|
import { type IPostgresInterval } from 'postgres-interval';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { PostgreSqlSchemaHelper } from './PostgreSqlSchemaHelper.js';
|
|
5
|
-
import { PostgreSqlExceptionConverter } from './PostgreSqlExceptionConverter.js';
|
|
6
|
-
export declare class PostgreSqlPlatform extends AbstractSqlPlatform {
|
|
7
|
-
protected readonly schemaHelper: PostgreSqlSchemaHelper;
|
|
8
|
-
protected readonly exceptionConverter: PostgreSqlExceptionConverter;
|
|
9
|
-
setConfig(config: Configuration): void;
|
|
10
|
-
createNativeQueryBuilder(): PostgreSqlNativeQueryBuilder;
|
|
11
|
-
usesReturningStatement(): boolean;
|
|
12
|
-
usesCascadeStatement(): boolean;
|
|
13
|
-
supportsNativeEnums(): boolean;
|
|
14
|
-
usesEnumCheckConstraints(): boolean;
|
|
15
|
-
supportsCustomPrimaryKeyNames(): boolean;
|
|
16
|
-
getCurrentTimestampSQL(length: number): string;
|
|
17
|
-
getDateTimeTypeDeclarationSQL(column: {
|
|
18
|
-
length?: number;
|
|
19
|
-
}): string;
|
|
20
|
-
getDefaultDateTimeLength(): number;
|
|
2
|
+
import { BasePostgreSqlPlatform } from '@mikro-orm/sql';
|
|
3
|
+
export declare class PostgreSqlPlatform extends BasePostgreSqlPlatform {
|
|
21
4
|
convertIntervalToJSValue(value: string): unknown;
|
|
22
5
|
convertIntervalToDatabaseValue(value: IPostgresInterval): unknown;
|
|
23
|
-
getTimeTypeDeclarationSQL(): string;
|
|
24
|
-
getIntegerTypeDeclarationSQL(column: {
|
|
25
|
-
length?: number;
|
|
26
|
-
autoincrement?: boolean;
|
|
27
|
-
generated?: string;
|
|
28
|
-
}): string;
|
|
29
|
-
getBigIntTypeDeclarationSQL(column: {
|
|
30
|
-
autoincrement?: boolean;
|
|
31
|
-
}): string;
|
|
32
|
-
getTinyIntTypeDeclarationSQL(column: {
|
|
33
|
-
length?: number;
|
|
34
|
-
unsigned?: boolean;
|
|
35
|
-
autoincrement?: boolean;
|
|
36
|
-
}): string;
|
|
37
|
-
getUuidTypeDeclarationSQL(column: {
|
|
38
|
-
length?: number;
|
|
39
|
-
}): string;
|
|
40
|
-
getFullTextWhereClause(prop: EntityProperty): string;
|
|
41
|
-
supportsCreatingFullTextIndex(): boolean;
|
|
42
|
-
getFullTextIndexExpression(indexName: string, schemaName: string | undefined, tableName: string, columns: SimpleColumnMeta[]): string;
|
|
43
|
-
normalizeColumnType(type: string, options: {
|
|
44
|
-
length?: number;
|
|
45
|
-
precision?: number;
|
|
46
|
-
scale?: number;
|
|
47
|
-
autoincrement?: boolean;
|
|
48
|
-
}): string;
|
|
49
|
-
getMappedType(type: string): Type<unknown>;
|
|
50
|
-
getRegExpOperator(val?: unknown, flags?: string): string;
|
|
51
|
-
getRegExpValue(val: RegExp): {
|
|
52
|
-
$re: string;
|
|
53
|
-
$flags?: string;
|
|
54
|
-
};
|
|
55
|
-
isBigIntProperty(prop: EntityProperty): boolean;
|
|
56
|
-
getArrayDeclarationSQL(): string;
|
|
57
|
-
getFloatDeclarationSQL(): string;
|
|
58
|
-
getDoubleDeclarationSQL(): string;
|
|
59
|
-
getEnumTypeDeclarationSQL(column: {
|
|
60
|
-
fieldNames: string[];
|
|
61
|
-
items?: unknown[];
|
|
62
|
-
nativeEnumName?: string;
|
|
63
|
-
}): string;
|
|
64
|
-
supportsMultipleStatements(): boolean;
|
|
65
|
-
getBeginTransactionSQL(options?: {
|
|
66
|
-
isolationLevel?: IsolationLevel;
|
|
67
|
-
readOnly?: boolean;
|
|
68
|
-
}): string[];
|
|
69
|
-
marshallArray(values: string[]): string;
|
|
70
|
-
unmarshallArray(value: string): string[];
|
|
71
|
-
getVarcharTypeDeclarationSQL(column: {
|
|
72
|
-
length?: number;
|
|
73
|
-
}): string;
|
|
74
|
-
getCharTypeDeclarationSQL(column: {
|
|
75
|
-
length?: number;
|
|
76
|
-
}): string;
|
|
77
|
-
getIntervalTypeDeclarationSQL(column: {
|
|
78
|
-
length?: number;
|
|
79
|
-
}): string;
|
|
80
|
-
getBlobDeclarationSQL(): string;
|
|
81
|
-
getJsonDeclarationSQL(): string;
|
|
82
|
-
getSearchJsonPropertyKey(path: string[], type: string | undefined | Type, aliased: boolean, value?: unknown): string;
|
|
83
|
-
getJsonIndexDefinition(index: IndexDef): string[];
|
|
84
|
-
quoteIdentifier(id: string | {
|
|
85
|
-
toString: () => string;
|
|
86
|
-
}, quote?: string): string;
|
|
87
6
|
escape(value: any): string;
|
|
88
|
-
private pad;
|
|
89
|
-
/** @internal */
|
|
90
|
-
formatDate(date: Date): string;
|
|
91
|
-
indexForeignKeys(): boolean;
|
|
92
|
-
getDefaultMappedType(type: string): Type<unknown>;
|
|
93
|
-
supportsSchemas(): boolean;
|
|
94
|
-
getDefaultSchemaName(): string | undefined;
|
|
95
|
-
/**
|
|
96
|
-
* Returns the default name of index for the given columns
|
|
97
|
-
* cannot go past 63 character length for identifiers in MySQL
|
|
98
|
-
*/
|
|
99
|
-
getIndexName(tableName: string, columns: string[], type: 'index' | 'unique' | 'foreign' | 'primary' | 'sequence'): string;
|
|
100
|
-
getDefaultPrimaryName(tableName: string, columns: string[]): string;
|
|
101
|
-
/**
|
|
102
|
-
* @inheritDoc
|
|
103
|
-
*/
|
|
104
|
-
castColumn(prop?: {
|
|
105
|
-
columnTypes?: string[];
|
|
106
|
-
}): string;
|
|
107
7
|
/**
|
|
108
8
|
* @inheritDoc
|
|
109
9
|
*/
|
|
110
10
|
parseDate(value: string | number): Date;
|
|
111
|
-
getDefaultClientUrl(): string;
|
|
112
11
|
}
|
package/PostgreSqlPlatform.js
CHANGED
|
@@ -1,48 +1,8 @@
|
|
|
1
1
|
import { Client } from 'pg';
|
|
2
2
|
import parseDate from 'postgres-date';
|
|
3
3
|
import PostgresInterval from 'postgres-interval';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
import { PostgreSqlSchemaHelper } from './PostgreSqlSchemaHelper.js';
|
|
7
|
-
import { PostgreSqlExceptionConverter } from './PostgreSqlExceptionConverter.js';
|
|
8
|
-
import { FullTextType } from './types/FullTextType.js';
|
|
9
|
-
export class PostgreSqlPlatform extends AbstractSqlPlatform {
|
|
10
|
-
schemaHelper = new PostgreSqlSchemaHelper(this);
|
|
11
|
-
exceptionConverter = new PostgreSqlExceptionConverter();
|
|
12
|
-
setConfig(config) {
|
|
13
|
-
if (config.get('forceUtcTimezone') == null) {
|
|
14
|
-
config.set('forceUtcTimezone', true);
|
|
15
|
-
}
|
|
16
|
-
super.setConfig(config);
|
|
17
|
-
}
|
|
18
|
-
createNativeQueryBuilder() {
|
|
19
|
-
return new PostgreSqlNativeQueryBuilder(this);
|
|
20
|
-
}
|
|
21
|
-
usesReturningStatement() {
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
usesCascadeStatement() {
|
|
25
|
-
return true;
|
|
26
|
-
}
|
|
27
|
-
supportsNativeEnums() {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
usesEnumCheckConstraints() {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
supportsCustomPrimaryKeyNames() {
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
getCurrentTimestampSQL(length) {
|
|
37
|
-
return `current_timestamp(${length})`;
|
|
38
|
-
}
|
|
39
|
-
getDateTimeTypeDeclarationSQL(column) {
|
|
40
|
-
/* v8 ignore next */
|
|
41
|
-
return 'timestamptz' + (column.length != null ? `(${column.length})` : '');
|
|
42
|
-
}
|
|
43
|
-
getDefaultDateTimeLength() {
|
|
44
|
-
return 6;
|
|
45
|
-
}
|
|
4
|
+
import { BasePostgreSqlPlatform, Utils } from '@mikro-orm/sql';
|
|
5
|
+
export class PostgreSqlPlatform extends BasePostgreSqlPlatform {
|
|
46
6
|
convertIntervalToJSValue(value) {
|
|
47
7
|
return PostgresInterval(value);
|
|
48
8
|
}
|
|
@@ -52,214 +12,6 @@ export class PostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
52
12
|
}
|
|
53
13
|
return value;
|
|
54
14
|
}
|
|
55
|
-
getTimeTypeDeclarationSQL() {
|
|
56
|
-
return 'time(0)';
|
|
57
|
-
}
|
|
58
|
-
getIntegerTypeDeclarationSQL(column) {
|
|
59
|
-
if (column.autoincrement && !column.generated) {
|
|
60
|
-
return 'serial';
|
|
61
|
-
}
|
|
62
|
-
return 'int';
|
|
63
|
-
}
|
|
64
|
-
getBigIntTypeDeclarationSQL(column) {
|
|
65
|
-
/* v8 ignore next */
|
|
66
|
-
if (column.autoincrement) {
|
|
67
|
-
return `bigserial`;
|
|
68
|
-
}
|
|
69
|
-
return 'bigint';
|
|
70
|
-
}
|
|
71
|
-
getTinyIntTypeDeclarationSQL(column) {
|
|
72
|
-
return 'smallint';
|
|
73
|
-
}
|
|
74
|
-
getUuidTypeDeclarationSQL(column) {
|
|
75
|
-
return `uuid`;
|
|
76
|
-
}
|
|
77
|
-
getFullTextWhereClause(prop) {
|
|
78
|
-
if (prop.customType instanceof FullTextType) {
|
|
79
|
-
return `:column: @@ plainto_tsquery('${prop.customType.regconfig}', :query)`;
|
|
80
|
-
}
|
|
81
|
-
/* v8 ignore next */
|
|
82
|
-
if (prop.columnTypes[0] === 'tsvector') {
|
|
83
|
-
return `:column: @@ plainto_tsquery('simple', :query)`;
|
|
84
|
-
}
|
|
85
|
-
return `to_tsvector('simple', :column:) @@ plainto_tsquery('simple', :query)`;
|
|
86
|
-
}
|
|
87
|
-
supportsCreatingFullTextIndex() {
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
getFullTextIndexExpression(indexName, schemaName, tableName, columns) {
|
|
91
|
-
/* v8 ignore next */
|
|
92
|
-
const quotedTableName = this.quoteIdentifier(schemaName ? `${schemaName}.${tableName}` : tableName);
|
|
93
|
-
const quotedColumnNames = columns.map(c => this.quoteIdentifier(c.name));
|
|
94
|
-
const quotedIndexName = this.quoteIdentifier(indexName);
|
|
95
|
-
if (columns.length === 1 && columns[0].type === 'tsvector') {
|
|
96
|
-
return `create index ${quotedIndexName} on ${quotedTableName} using gin(${quotedColumnNames[0]})`;
|
|
97
|
-
}
|
|
98
|
-
return `create index ${quotedIndexName} on ${quotedTableName} using gin(to_tsvector('simple', ${quotedColumnNames.join(` || ' ' || `)}))`;
|
|
99
|
-
}
|
|
100
|
-
normalizeColumnType(type, options) {
|
|
101
|
-
const simpleType = this.extractSimpleType(type);
|
|
102
|
-
if (['int', 'int4', 'integer'].includes(simpleType)) {
|
|
103
|
-
return this.getIntegerTypeDeclarationSQL({});
|
|
104
|
-
}
|
|
105
|
-
if (['bigint', 'int8'].includes(simpleType)) {
|
|
106
|
-
return this.getBigIntTypeDeclarationSQL({});
|
|
107
|
-
}
|
|
108
|
-
if (['smallint', 'int2'].includes(simpleType)) {
|
|
109
|
-
return this.getSmallIntTypeDeclarationSQL({});
|
|
110
|
-
}
|
|
111
|
-
if (['boolean', 'bool'].includes(simpleType)) {
|
|
112
|
-
return this.getBooleanTypeDeclarationSQL();
|
|
113
|
-
}
|
|
114
|
-
if (['varchar', 'character varying'].includes(simpleType)) {
|
|
115
|
-
return this.getVarcharTypeDeclarationSQL(options);
|
|
116
|
-
}
|
|
117
|
-
if (['char', 'bpchar'].includes(simpleType)) {
|
|
118
|
-
return this.getCharTypeDeclarationSQL(options);
|
|
119
|
-
}
|
|
120
|
-
if (['decimal', 'numeric'].includes(simpleType)) {
|
|
121
|
-
return this.getDecimalTypeDeclarationSQL(options);
|
|
122
|
-
}
|
|
123
|
-
if (['interval'].includes(simpleType)) {
|
|
124
|
-
return this.getIntervalTypeDeclarationSQL(options);
|
|
125
|
-
}
|
|
126
|
-
return super.normalizeColumnType(type, options);
|
|
127
|
-
}
|
|
128
|
-
getMappedType(type) {
|
|
129
|
-
switch (this.extractSimpleType(type)) {
|
|
130
|
-
case 'tsvector': return Type.getType(FullTextType);
|
|
131
|
-
default: return super.getMappedType(type);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
getRegExpOperator(val, flags) {
|
|
135
|
-
/* v8 ignore next */
|
|
136
|
-
if ((val instanceof RegExp && val.flags.includes('i')) || flags?.includes('i')) {
|
|
137
|
-
return '~*';
|
|
138
|
-
}
|
|
139
|
-
return '~';
|
|
140
|
-
}
|
|
141
|
-
/* v8 ignore next */
|
|
142
|
-
getRegExpValue(val) {
|
|
143
|
-
if (val.flags.includes('i')) {
|
|
144
|
-
return { $re: val.source, $flags: val.flags };
|
|
145
|
-
}
|
|
146
|
-
return { $re: val.source };
|
|
147
|
-
}
|
|
148
|
-
isBigIntProperty(prop) {
|
|
149
|
-
return super.isBigIntProperty(prop) || (['bigserial', 'int8'].includes(prop.columnTypes?.[0]));
|
|
150
|
-
}
|
|
151
|
-
getArrayDeclarationSQL() {
|
|
152
|
-
return 'text[]';
|
|
153
|
-
}
|
|
154
|
-
getFloatDeclarationSQL() {
|
|
155
|
-
return 'real';
|
|
156
|
-
}
|
|
157
|
-
getDoubleDeclarationSQL() {
|
|
158
|
-
return 'double precision';
|
|
159
|
-
}
|
|
160
|
-
getEnumTypeDeclarationSQL(column) {
|
|
161
|
-
/* v8 ignore next */
|
|
162
|
-
if (column.nativeEnumName) {
|
|
163
|
-
return column.nativeEnumName;
|
|
164
|
-
}
|
|
165
|
-
if (column.items?.every(item => typeof item === 'string')) {
|
|
166
|
-
return 'text';
|
|
167
|
-
}
|
|
168
|
-
return `smallint`;
|
|
169
|
-
}
|
|
170
|
-
supportsMultipleStatements() {
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
getBeginTransactionSQL(options) {
|
|
174
|
-
if (options?.isolationLevel || options?.readOnly) {
|
|
175
|
-
let sql = 'start transaction';
|
|
176
|
-
sql += options.isolationLevel ? ` isolation level ${options.isolationLevel}` : '';
|
|
177
|
-
sql += options.readOnly ? ` read only` : '';
|
|
178
|
-
return [sql];
|
|
179
|
-
}
|
|
180
|
-
return ['begin'];
|
|
181
|
-
}
|
|
182
|
-
marshallArray(values) {
|
|
183
|
-
const quote = (v) => v === '' || v.match(/["{},\\]/) ? JSON.stringify(v) : v;
|
|
184
|
-
return `{${values.map(v => quote('' + v)).join(',')}}`;
|
|
185
|
-
}
|
|
186
|
-
unmarshallArray(value) {
|
|
187
|
-
if (value === '{}') {
|
|
188
|
-
return [];
|
|
189
|
-
}
|
|
190
|
-
return value.substring(1, value.length - 1).split(',').map(v => {
|
|
191
|
-
if (v === `""`) {
|
|
192
|
-
return '';
|
|
193
|
-
}
|
|
194
|
-
if (v.match(/"(.*)"/)) {
|
|
195
|
-
return v.substring(1, v.length - 1).replaceAll('\\"', '"');
|
|
196
|
-
}
|
|
197
|
-
return v;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
getVarcharTypeDeclarationSQL(column) {
|
|
201
|
-
if (column.length === -1) {
|
|
202
|
-
return 'varchar';
|
|
203
|
-
}
|
|
204
|
-
return super.getVarcharTypeDeclarationSQL(column);
|
|
205
|
-
}
|
|
206
|
-
getCharTypeDeclarationSQL(column) {
|
|
207
|
-
if (column.length === -1) {
|
|
208
|
-
return 'char';
|
|
209
|
-
}
|
|
210
|
-
return super.getCharTypeDeclarationSQL(column);
|
|
211
|
-
}
|
|
212
|
-
getIntervalTypeDeclarationSQL(column) {
|
|
213
|
-
return 'interval' + (column.length != null ? `(${column.length})` : '');
|
|
214
|
-
}
|
|
215
|
-
getBlobDeclarationSQL() {
|
|
216
|
-
return 'bytea';
|
|
217
|
-
}
|
|
218
|
-
getJsonDeclarationSQL() {
|
|
219
|
-
return 'jsonb';
|
|
220
|
-
}
|
|
221
|
-
getSearchJsonPropertyKey(path, type, aliased, value) {
|
|
222
|
-
const first = path.shift();
|
|
223
|
-
const last = path.pop();
|
|
224
|
-
const root = this.quoteIdentifier(aliased ? `${ALIAS_REPLACEMENT}.${first}` : first);
|
|
225
|
-
type = typeof type === 'string' ? this.getMappedType(type).runtimeType : String(type);
|
|
226
|
-
const types = {
|
|
227
|
-
number: 'float8',
|
|
228
|
-
bigint: 'int8',
|
|
229
|
-
boolean: 'bool',
|
|
230
|
-
};
|
|
231
|
-
const cast = (key) => raw(type in types ? `(${key})::${types[type]}` : key);
|
|
232
|
-
let lastOperator = '->>';
|
|
233
|
-
// force `->` for operator payloads with array values
|
|
234
|
-
if (Utils.isPlainObject(value) && Object.keys(value).every(key => ARRAY_OPERATORS.includes(key) && Array.isArray(value[key]))) {
|
|
235
|
-
lastOperator = '->';
|
|
236
|
-
}
|
|
237
|
-
if (path.length === 0) {
|
|
238
|
-
return cast(`${root}${lastOperator}'${last}'`);
|
|
239
|
-
}
|
|
240
|
-
return cast(`${root}->${path.map(a => this.quoteValue(a)).join('->')}${lastOperator}'${last}'`);
|
|
241
|
-
}
|
|
242
|
-
getJsonIndexDefinition(index) {
|
|
243
|
-
return index.columnNames
|
|
244
|
-
.map(column => {
|
|
245
|
-
if (!column.includes('.')) {
|
|
246
|
-
return column;
|
|
247
|
-
}
|
|
248
|
-
const path = column.split('.');
|
|
249
|
-
const first = path.shift();
|
|
250
|
-
const last = path.pop();
|
|
251
|
-
if (path.length === 0) {
|
|
252
|
-
return `(${this.quoteIdentifier(first)}->>${this.quoteValue(last)})`;
|
|
253
|
-
}
|
|
254
|
-
return `(${this.quoteIdentifier(first)}->${path.map(c => this.quoteValue(c)).join('->')}->>${this.quoteValue(last)})`;
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
quoteIdentifier(id, quote = '"') {
|
|
258
|
-
if (RawQueryFragment.isKnownFragment(id)) {
|
|
259
|
-
return super.quoteIdentifier(id);
|
|
260
|
-
}
|
|
261
|
-
return `${quote}${id.toString().replace('.', `${quote}.${quote}`)}${quote}`;
|
|
262
|
-
}
|
|
263
15
|
escape(value) {
|
|
264
16
|
if (typeof value === 'bigint') {
|
|
265
17
|
value = value.toString();
|
|
@@ -278,103 +30,6 @@ export class PostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
278
30
|
}
|
|
279
31
|
return value;
|
|
280
32
|
}
|
|
281
|
-
pad(number, digits) {
|
|
282
|
-
return String(number).padStart(digits, '0');
|
|
283
|
-
}
|
|
284
|
-
/** @internal */
|
|
285
|
-
formatDate(date) {
|
|
286
|
-
if (this.timezone === 'Z') {
|
|
287
|
-
return date.toISOString();
|
|
288
|
-
}
|
|
289
|
-
let offset = -date.getTimezoneOffset();
|
|
290
|
-
let year = date.getFullYear();
|
|
291
|
-
const isBCYear = year < 1;
|
|
292
|
-
/* v8 ignore next */
|
|
293
|
-
if (isBCYear) {
|
|
294
|
-
year = Math.abs(year) + 1;
|
|
295
|
-
}
|
|
296
|
-
const datePart = `${this.pad(year, 4)}-${this.pad(date.getMonth() + 1, 2)}-${this.pad(date.getDate(), 2)}`;
|
|
297
|
-
const timePart = `${this.pad(date.getHours(), 2)}:${this.pad(date.getMinutes(), 2)}:${this.pad(date.getSeconds(), 2)}.${this.pad(date.getMilliseconds(), 3)}`;
|
|
298
|
-
let ret = `${datePart}T${timePart}`;
|
|
299
|
-
/* v8 ignore next */
|
|
300
|
-
if (offset < 0) {
|
|
301
|
-
ret += '-';
|
|
302
|
-
offset *= -1;
|
|
303
|
-
}
|
|
304
|
-
else {
|
|
305
|
-
ret += '+';
|
|
306
|
-
}
|
|
307
|
-
ret += this.pad(Math.floor(offset / 60), 2) + ':' + this.pad(offset % 60, 2);
|
|
308
|
-
/* v8 ignore next */
|
|
309
|
-
if (isBCYear) {
|
|
310
|
-
ret += ' BC';
|
|
311
|
-
}
|
|
312
|
-
return ret;
|
|
313
|
-
}
|
|
314
|
-
indexForeignKeys() {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
getDefaultMappedType(type) {
|
|
318
|
-
const normalizedType = this.extractSimpleType(type);
|
|
319
|
-
const map = {
|
|
320
|
-
'int2': 'smallint',
|
|
321
|
-
'smallserial': 'smallint',
|
|
322
|
-
'int': 'integer',
|
|
323
|
-
'int4': 'integer',
|
|
324
|
-
'serial': 'integer',
|
|
325
|
-
'serial4': 'integer',
|
|
326
|
-
'int8': 'bigint',
|
|
327
|
-
'bigserial': 'bigint',
|
|
328
|
-
'serial8': 'bigint',
|
|
329
|
-
'numeric': 'decimal',
|
|
330
|
-
'bool': 'boolean',
|
|
331
|
-
'real': 'float',
|
|
332
|
-
'float4': 'float',
|
|
333
|
-
'float8': 'double',
|
|
334
|
-
'timestamp': 'datetime',
|
|
335
|
-
'timestamptz': 'datetime',
|
|
336
|
-
'bytea': 'blob',
|
|
337
|
-
'jsonb': 'json',
|
|
338
|
-
'character varying': 'varchar',
|
|
339
|
-
'bpchar': 'character',
|
|
340
|
-
};
|
|
341
|
-
return super.getDefaultMappedType(map[normalizedType] ?? type);
|
|
342
|
-
}
|
|
343
|
-
supportsSchemas() {
|
|
344
|
-
return true;
|
|
345
|
-
}
|
|
346
|
-
getDefaultSchemaName() {
|
|
347
|
-
return 'public';
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Returns the default name of index for the given columns
|
|
351
|
-
* cannot go past 63 character length for identifiers in MySQL
|
|
352
|
-
*/
|
|
353
|
-
getIndexName(tableName, columns, type) {
|
|
354
|
-
const indexName = super.getIndexName(tableName, columns, type);
|
|
355
|
-
if (indexName.length > 63) {
|
|
356
|
-
const suffix = type === 'primary' ? 'pkey' : type;
|
|
357
|
-
return `${indexName.substring(0, 55 - type.length)}_${Utils.hash(indexName, 5)}_${suffix}`;
|
|
358
|
-
}
|
|
359
|
-
return indexName;
|
|
360
|
-
}
|
|
361
|
-
getDefaultPrimaryName(tableName, columns) {
|
|
362
|
-
const indexName = `${tableName}_pkey`;
|
|
363
|
-
if (indexName.length > 63) {
|
|
364
|
-
return `${indexName.substring(0, 55 - 'pkey'.length)}_${Utils.hash(indexName, 5)}_pkey`;
|
|
365
|
-
}
|
|
366
|
-
return indexName;
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* @inheritDoc
|
|
370
|
-
*/
|
|
371
|
-
castColumn(prop) {
|
|
372
|
-
switch (prop?.columnTypes?.[0]) {
|
|
373
|
-
case this.getUuidTypeDeclarationSQL({}): return '::text';
|
|
374
|
-
case this.getBooleanTypeDeclarationSQL(): return '::int';
|
|
375
|
-
default: return '';
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
33
|
/**
|
|
379
34
|
* @inheritDoc
|
|
380
35
|
*/
|
|
@@ -395,7 +50,4 @@ export class PostgreSqlPlatform extends AbstractSqlPlatform {
|
|
|
395
50
|
}
|
|
396
51
|
return parsed;
|
|
397
52
|
}
|
|
398
|
-
getDefaultClientUrl() {
|
|
399
|
-
return 'postgresql://postgres@127.0.0.1:5432';
|
|
400
|
-
}
|
|
401
53
|
}
|
package/index.d.ts
CHANGED
|
@@ -2,8 +2,5 @@ export * from '@mikro-orm/sql';
|
|
|
2
2
|
export * from './PostgreSqlConnection.js';
|
|
3
3
|
export * from './PostgreSqlDriver.js';
|
|
4
4
|
export * from './PostgreSqlPlatform.js';
|
|
5
|
-
export * from './PostgreSqlSchemaHelper.js';
|
|
6
|
-
export * from './PostgreSqlExceptionConverter.js';
|
|
7
|
-
export * from './types/index.js';
|
|
8
5
|
export { PostgreSqlMikroORM as MikroORM, type PostgreSqlOptions as Options, definePostgreSqlConfig as defineConfig, } from './PostgreSqlMikroORM.js';
|
|
9
6
|
export { raw } from './raw.js';
|
package/index.js
CHANGED
|
@@ -2,8 +2,5 @@ export * from '@mikro-orm/sql';
|
|
|
2
2
|
export * from './PostgreSqlConnection.js';
|
|
3
3
|
export * from './PostgreSqlDriver.js';
|
|
4
4
|
export * from './PostgreSqlPlatform.js';
|
|
5
|
-
export * from './PostgreSqlSchemaHelper.js';
|
|
6
|
-
export * from './PostgreSqlExceptionConverter.js';
|
|
7
|
-
export * from './types/index.js';
|
|
8
5
|
export { PostgreSqlMikroORM as MikroORM, definePostgreSqlConfig as defineConfig, } from './PostgreSqlMikroORM.js';
|
|
9
6
|
export { raw } from './raw.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikro-orm/postgresql",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "7.0.0-dev.
|
|
4
|
+
"version": "7.0.0-dev.103",
|
|
5
5
|
"description": "TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, PostgreSQL and SQLite databases as well as usage with vanilla JavaScript.",
|
|
6
6
|
"exports": {
|
|
7
7
|
"./package.json": "./package.json",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"access": "public"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@mikro-orm/sql": "7.0.0-dev.
|
|
53
|
+
"@mikro-orm/sql": "7.0.0-dev.103",
|
|
54
54
|
"pg": "8.16.3",
|
|
55
55
|
"pg-cursor": "2.15.3",
|
|
56
56
|
"postgres-array": "3.0.4",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"kysely": "0.28.9"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
|
-
"@mikro-orm/core": "7.0.0-dev.
|
|
65
|
+
"@mikro-orm/core": "7.0.0-dev.103",
|
|
66
66
|
"kysely": "*"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ExceptionConverter, type Dictionary, type DriverException } from '@mikro-orm/core';
|
|
2
|
-
export declare class PostgreSqlExceptionConverter extends ExceptionConverter {
|
|
3
|
-
/**
|
|
4
|
-
* @see http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
|
|
5
|
-
* @see https://github.com/doctrine/dbal/blob/master/src/Driver/AbstractPostgreSQLDriver.php
|
|
6
|
-
*/
|
|
7
|
-
convertException(exception: Error & Dictionary): DriverException;
|
|
8
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { DeadlockException, ExceptionConverter, ForeignKeyConstraintViolationException, InvalidFieldNameException, NonUniqueFieldNameException, NotNullConstraintViolationException, SyntaxErrorException, TableExistsException, TableNotFoundException, UniqueConstraintViolationException, CheckConstraintViolationException, } from '@mikro-orm/core';
|
|
2
|
-
export class PostgreSqlExceptionConverter extends ExceptionConverter {
|
|
3
|
-
/**
|
|
4
|
-
* @see http://www.postgresql.org/docs/9.4/static/errcodes-appendix.html
|
|
5
|
-
* @see https://github.com/doctrine/dbal/blob/master/src/Driver/AbstractPostgreSQLDriver.php
|
|
6
|
-
*/
|
|
7
|
-
convertException(exception) {
|
|
8
|
-
if (exception.detail?.toString().trim()) {
|
|
9
|
-
exception.message += '\n - detail: ' + exception.detail;
|
|
10
|
-
}
|
|
11
|
-
if (exception.hint?.toString().trim()) {
|
|
12
|
-
exception.message += '\n - hint: ' + exception.hint;
|
|
13
|
-
}
|
|
14
|
-
/* v8 ignore next */
|
|
15
|
-
switch (exception.code) {
|
|
16
|
-
case '40001':
|
|
17
|
-
case '40P01':
|
|
18
|
-
return new DeadlockException(exception);
|
|
19
|
-
case '0A000':
|
|
20
|
-
// Foreign key constraint violations during a TRUNCATE operation
|
|
21
|
-
// are considered "feature not supported" in PostgreSQL.
|
|
22
|
-
if (exception.message.includes('truncate')) {
|
|
23
|
-
return new ForeignKeyConstraintViolationException(exception);
|
|
24
|
-
}
|
|
25
|
-
break;
|
|
26
|
-
case '23502':
|
|
27
|
-
return new NotNullConstraintViolationException(exception);
|
|
28
|
-
case '23503':
|
|
29
|
-
return new ForeignKeyConstraintViolationException(exception);
|
|
30
|
-
case '23505':
|
|
31
|
-
return new UniqueConstraintViolationException(exception);
|
|
32
|
-
case '23514':
|
|
33
|
-
return new CheckConstraintViolationException(exception);
|
|
34
|
-
case '42601':
|
|
35
|
-
return new SyntaxErrorException(exception);
|
|
36
|
-
case '42702':
|
|
37
|
-
return new NonUniqueFieldNameException(exception);
|
|
38
|
-
case '42703':
|
|
39
|
-
return new InvalidFieldNameException(exception);
|
|
40
|
-
case '42P01':
|
|
41
|
-
return new TableNotFoundException(exception);
|
|
42
|
-
case '42P07':
|
|
43
|
-
return new TableExistsException(exception);
|
|
44
|
-
}
|
|
45
|
-
return super.convertException(exception);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { type Dictionary } from '@mikro-orm/core';
|
|
2
|
-
import { SchemaHelper, type AbstractSqlConnection, type CheckDef, type Column, type DatabaseSchema, type DatabaseTable, type ForeignKey, type IndexDef, type Table, type TableDifference } from '@mikro-orm/sql';
|
|
3
|
-
export declare class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
4
|
-
static readonly DEFAULT_VALUES: {
|
|
5
|
-
'now()': string[];
|
|
6
|
-
'current_timestamp(?)': string[];
|
|
7
|
-
"('now'::text)::timestamp(?) with time zone": string[];
|
|
8
|
-
"('now'::text)::timestamp(?) without time zone": string[];
|
|
9
|
-
'null::character varying': string[];
|
|
10
|
-
'null::timestamp with time zone': string[];
|
|
11
|
-
'null::timestamp without time zone': string[];
|
|
12
|
-
};
|
|
13
|
-
getSchemaBeginning(charset: string, disableForeignKeys?: boolean): string;
|
|
14
|
-
getCreateDatabaseSQL(name: string): string;
|
|
15
|
-
getListTablesSQL(): string;
|
|
16
|
-
getNamespaces(connection: AbstractSqlConnection): Promise<string[]>;
|
|
17
|
-
private getIgnoredNamespacesConditionSQL;
|
|
18
|
-
loadInformationSchema(schema: DatabaseSchema, connection: AbstractSqlConnection, tables: Table[], schemas?: string[]): Promise<void>;
|
|
19
|
-
getAllIndexes(connection: AbstractSqlConnection, tables: Table[]): Promise<Dictionary<IndexDef[]>>;
|
|
20
|
-
getAllColumns(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>, nativeEnums?: Dictionary<{
|
|
21
|
-
name: string;
|
|
22
|
-
schema?: string;
|
|
23
|
-
items: string[];
|
|
24
|
-
}>): Promise<Dictionary<Column[]>>;
|
|
25
|
-
getAllChecks(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>): Promise<Dictionary<CheckDef[]>>;
|
|
26
|
-
getAllForeignKeys(connection: AbstractSqlConnection, tablesBySchemas: Map<string | undefined, Table[]>): Promise<Dictionary<Dictionary<ForeignKey>>>;
|
|
27
|
-
getNativeEnumDefinitions(connection: AbstractSqlConnection, schemas: string[]): Promise<Dictionary<{
|
|
28
|
-
name: string;
|
|
29
|
-
schema?: string;
|
|
30
|
-
items: string[];
|
|
31
|
-
}>>;
|
|
32
|
-
getCreateNativeEnumSQL(name: string, values: unknown[], schema?: string): string;
|
|
33
|
-
getDropNativeEnumSQL(name: string, schema?: string): string;
|
|
34
|
-
getAlterNativeEnumSQL(name: string, schema?: string, value?: string, items?: string[], oldItems?: string[]): string;
|
|
35
|
-
private getEnumDefinitions;
|
|
36
|
-
createTableColumn(column: Column, table: DatabaseTable): string | undefined;
|
|
37
|
-
getPreAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
38
|
-
castColumn(name: string, type: string): string;
|
|
39
|
-
dropForeignKey(tableName: string, constraintName: string): string;
|
|
40
|
-
getPostAlterTable(tableDiff: TableDifference, safe: boolean): string[];
|
|
41
|
-
private getAlterColumnAutoincrement;
|
|
42
|
-
getChangeColumnCommentSQL(tableName: string, to: Column, schemaName?: string): string;
|
|
43
|
-
alterTableComment(table: DatabaseTable, comment?: string): string;
|
|
44
|
-
normalizeDefaultValue(defaultValue: string, length: number): string | number;
|
|
45
|
-
appendComments(table: DatabaseTable): string[];
|
|
46
|
-
getDatabaseExistsSQL(name: string): string;
|
|
47
|
-
getDatabaseNotExistsError(dbName: string): string;
|
|
48
|
-
getManagementDbName(): string;
|
|
49
|
-
disableForeignKeysSQL(): string;
|
|
50
|
-
enableForeignKeysSQL(): string;
|
|
51
|
-
getRenameIndexSQL(tableName: string, index: IndexDef, oldIndexName: string): string[];
|
|
52
|
-
dropIndex(table: string, index: IndexDef, oldIndexName?: string): string;
|
|
53
|
-
private getIndexesSQL;
|
|
54
|
-
private getChecksSQL;
|
|
55
|
-
inferLengthFromColumnType(type: string): number | undefined;
|
|
56
|
-
}
|
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
import { EnumType, Type, Utils, DeferMode } from '@mikro-orm/core';
|
|
2
|
-
import { SchemaHelper, } from '@mikro-orm/sql';
|
|
3
|
-
export class PostgreSqlSchemaHelper extends SchemaHelper {
|
|
4
|
-
static DEFAULT_VALUES = {
|
|
5
|
-
'now()': ['now()', 'current_timestamp'],
|
|
6
|
-
'current_timestamp(?)': ['current_timestamp(?)'],
|
|
7
|
-
"('now'::text)::timestamp(?) with time zone": ['current_timestamp(?)'],
|
|
8
|
-
"('now'::text)::timestamp(?) without time zone": ['current_timestamp(?)'],
|
|
9
|
-
'null::character varying': ['null'],
|
|
10
|
-
'null::timestamp with time zone': ['null'],
|
|
11
|
-
'null::timestamp without time zone': ['null'],
|
|
12
|
-
};
|
|
13
|
-
getSchemaBeginning(charset, disableForeignKeys) {
|
|
14
|
-
if (disableForeignKeys) {
|
|
15
|
-
return `set names '${charset}';\n${this.disableForeignKeysSQL()}\n\n`;
|
|
16
|
-
}
|
|
17
|
-
return `set names '${charset}';\n\n`;
|
|
18
|
-
}
|
|
19
|
-
getCreateDatabaseSQL(name) {
|
|
20
|
-
return `create database ${name}`;
|
|
21
|
-
}
|
|
22
|
-
getListTablesSQL() {
|
|
23
|
-
return `select table_name, table_schema as schema_name, `
|
|
24
|
-
+ `(select pg_catalog.obj_description(c.oid) from pg_catalog.pg_class c
|
|
25
|
-
where c.oid = (select ('"' || table_schema || '"."' || table_name || '"')::regclass::oid) and c.relname = table_name) as table_comment `
|
|
26
|
-
+ `from information_schema.tables `
|
|
27
|
-
+ `where ${this.getIgnoredNamespacesConditionSQL('table_schema')} `
|
|
28
|
-
+ `and table_name != 'geometry_columns' and table_name != 'spatial_ref_sys' and table_type != 'VIEW' `
|
|
29
|
-
+ `and table_name not in (select inhrelid::regclass::text from pg_inherits) `
|
|
30
|
-
+ `order by table_name`;
|
|
31
|
-
}
|
|
32
|
-
async getNamespaces(connection) {
|
|
33
|
-
const sql = `select schema_name from information_schema.schemata `
|
|
34
|
-
+ `where ${this.getIgnoredNamespacesConditionSQL()} `
|
|
35
|
-
+ `order by schema_name`;
|
|
36
|
-
const res = await connection.execute(sql);
|
|
37
|
-
return res.map(row => row.schema_name);
|
|
38
|
-
}
|
|
39
|
-
getIgnoredNamespacesConditionSQL(column = 'schema_name') {
|
|
40
|
-
const ignored = [
|
|
41
|
-
'information_schema',
|
|
42
|
-
'tiger',
|
|
43
|
-
'topology',
|
|
44
|
-
/* v8 ignore next */
|
|
45
|
-
...this.platform.getConfig().get('schemaGenerator').ignoreSchema ?? [],
|
|
46
|
-
].map(s => this.platform.quoteValue(s)).join(', ');
|
|
47
|
-
const ignoredPrefixes = [
|
|
48
|
-
'pg_',
|
|
49
|
-
'crdb_',
|
|
50
|
-
'_timescaledb_',
|
|
51
|
-
].map(p => `"${column}" not like '${p}%'`).join(' and ');
|
|
52
|
-
return `${ignoredPrefixes} and "${column}" not in (${ignored})`;
|
|
53
|
-
}
|
|
54
|
-
async loadInformationSchema(schema, connection, tables, schemas) {
|
|
55
|
-
schemas ??= tables.length === 0 ? [schema.name] : tables.map(t => t.schema_name);
|
|
56
|
-
const nativeEnums = await this.getNativeEnumDefinitions(connection, schemas);
|
|
57
|
-
schema.setNativeEnums(nativeEnums);
|
|
58
|
-
if (tables.length === 0) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const tablesBySchema = this.getTablesGroupedBySchemas(tables);
|
|
62
|
-
const columns = await this.getAllColumns(connection, tablesBySchema, nativeEnums);
|
|
63
|
-
const indexes = await this.getAllIndexes(connection, tables);
|
|
64
|
-
const checks = await this.getAllChecks(connection, tablesBySchema);
|
|
65
|
-
const fks = await this.getAllForeignKeys(connection, tablesBySchema);
|
|
66
|
-
for (const t of tables) {
|
|
67
|
-
const key = this.getTableKey(t);
|
|
68
|
-
const table = schema.addTable(t.table_name, t.schema_name, t.table_comment);
|
|
69
|
-
const pks = await this.getPrimaryKeys(connection, indexes[key], table.name, table.schema);
|
|
70
|
-
const enums = this.getEnumDefinitions(checks[key] ?? []);
|
|
71
|
-
if (columns[key]) {
|
|
72
|
-
table.init(columns[key], indexes[key], checks[key], pks, fks[key], enums);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
async getAllIndexes(connection, tables) {
|
|
77
|
-
const sql = this.getIndexesSQL(tables);
|
|
78
|
-
const unquote = (str) => str.replace(/['"`]/g, '');
|
|
79
|
-
const allIndexes = await connection.execute(sql);
|
|
80
|
-
const ret = {};
|
|
81
|
-
for (const index of allIndexes) {
|
|
82
|
-
const key = this.getTableKey(index);
|
|
83
|
-
const indexDef = {
|
|
84
|
-
columnNames: index.index_def.map((name) => unquote(name)),
|
|
85
|
-
composite: index.index_def.length > 1,
|
|
86
|
-
// JSON columns can have unique index but not unique constraint, and we need to distinguish those, so we can properly drop them
|
|
87
|
-
constraint: index.contype === 'u',
|
|
88
|
-
keyName: index.constraint_name,
|
|
89
|
-
unique: index.unique,
|
|
90
|
-
primary: index.primary,
|
|
91
|
-
};
|
|
92
|
-
if (index.condeferrable) {
|
|
93
|
-
indexDef.deferMode = index.condeferred ? DeferMode.INITIALLY_DEFERRED : DeferMode.INITIALLY_IMMEDIATE;
|
|
94
|
-
}
|
|
95
|
-
if (index.index_def.some((col) => col.match(/[(): ,"'`]/)) || index.expression?.match(/ where /i)) {
|
|
96
|
-
indexDef.expression = index.expression;
|
|
97
|
-
}
|
|
98
|
-
if (index.deferrable) {
|
|
99
|
-
indexDef.deferMode = index.initially_deferred ? DeferMode.INITIALLY_DEFERRED : DeferMode.INITIALLY_IMMEDIATE;
|
|
100
|
-
}
|
|
101
|
-
ret[key] ??= [];
|
|
102
|
-
ret[key].push(indexDef);
|
|
103
|
-
}
|
|
104
|
-
return ret;
|
|
105
|
-
}
|
|
106
|
-
async getAllColumns(connection, tablesBySchemas, nativeEnums) {
|
|
107
|
-
const sql = `select table_schema as schema_name, table_name, column_name,
|
|
108
|
-
column_default,
|
|
109
|
-
is_nullable,
|
|
110
|
-
udt_name,
|
|
111
|
-
udt_schema,
|
|
112
|
-
coalesce(datetime_precision, character_maximum_length) length,
|
|
113
|
-
atttypmod custom_length,
|
|
114
|
-
numeric_precision,
|
|
115
|
-
numeric_scale,
|
|
116
|
-
data_type,
|
|
117
|
-
is_identity,
|
|
118
|
-
identity_generation,
|
|
119
|
-
generation_expression,
|
|
120
|
-
pg_catalog.col_description(pgc.oid, cols.ordinal_position::int) column_comment
|
|
121
|
-
from information_schema.columns cols
|
|
122
|
-
join pg_class pgc on cols.table_name = pgc.relname
|
|
123
|
-
join pg_attribute pga on pgc.oid = pga.attrelid and cols.column_name = pga.attname
|
|
124
|
-
where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(table_schema = ${this.platform.quoteValue(schema)} and table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}))`).join(' or ')})
|
|
125
|
-
order by ordinal_position`;
|
|
126
|
-
const allColumns = await connection.execute(sql);
|
|
127
|
-
const str = (val) => val != null ? '' + val : val;
|
|
128
|
-
const ret = {};
|
|
129
|
-
for (const col of allColumns) {
|
|
130
|
-
const mappedType = connection.getPlatform().getMappedType(col.data_type);
|
|
131
|
-
const increments = (col.column_default?.includes('nextval') || col.is_identity === 'YES') && connection.getPlatform().isNumericColumn(mappedType);
|
|
132
|
-
const key = this.getTableKey(col);
|
|
133
|
-
ret[key] ??= [];
|
|
134
|
-
let type = col.data_type.toLowerCase() === 'array'
|
|
135
|
-
? col.udt_name.replace(/^_(.*)$/, '$1[]')
|
|
136
|
-
: col.udt_name;
|
|
137
|
-
if (col.data_type === 'USER-DEFINED' && col.udt_schema && col.udt_schema !== this.platform.getDefaultSchemaName()) {
|
|
138
|
-
type = `${col.udt_schema}.${type}`;
|
|
139
|
-
}
|
|
140
|
-
if (type === 'bpchar') {
|
|
141
|
-
type = 'char';
|
|
142
|
-
}
|
|
143
|
-
if (type === 'vector' && col.length == null && col.custom_length != null && col.custom_length !== -1) {
|
|
144
|
-
col.length = col.custom_length;
|
|
145
|
-
}
|
|
146
|
-
if (col.length != null && !type.endsWith(`(${col.length})`) && !['text', 'date'].includes(type)) {
|
|
147
|
-
type += `(${col.length})`;
|
|
148
|
-
}
|
|
149
|
-
if (type === 'numeric' && col.numeric_precision != null && col.numeric_scale != null) {
|
|
150
|
-
type += `(${col.numeric_precision},${col.numeric_scale})`;
|
|
151
|
-
}
|
|
152
|
-
const length = this.inferLengthFromColumnType(type) === -1 ? -1 : col.length;
|
|
153
|
-
const column = {
|
|
154
|
-
name: col.column_name,
|
|
155
|
-
type,
|
|
156
|
-
mappedType,
|
|
157
|
-
length,
|
|
158
|
-
precision: col.numeric_precision,
|
|
159
|
-
scale: col.numeric_scale,
|
|
160
|
-
nullable: col.is_nullable === 'YES',
|
|
161
|
-
default: str(this.normalizeDefaultValue(col.column_default, col.length)),
|
|
162
|
-
unsigned: increments,
|
|
163
|
-
autoincrement: increments,
|
|
164
|
-
generated: col.is_identity === 'YES' ? (col.identity_generation === 'BY DEFAULT' ? 'by default as identity' : 'identity') : (col.generation_expression ? col.generation_expression + ' stored' : undefined),
|
|
165
|
-
comment: col.column_comment,
|
|
166
|
-
};
|
|
167
|
-
if (nativeEnums?.[column.type]) {
|
|
168
|
-
column.mappedType = Type.getType(EnumType);
|
|
169
|
-
column.nativeEnumName = column.type;
|
|
170
|
-
column.enumItems = nativeEnums[column.type]?.items;
|
|
171
|
-
}
|
|
172
|
-
ret[key].push(column);
|
|
173
|
-
}
|
|
174
|
-
return ret;
|
|
175
|
-
}
|
|
176
|
-
async getAllChecks(connection, tablesBySchemas) {
|
|
177
|
-
const sql = this.getChecksSQL(tablesBySchemas);
|
|
178
|
-
const allChecks = await connection.execute(sql);
|
|
179
|
-
const ret = {};
|
|
180
|
-
for (const check of allChecks) {
|
|
181
|
-
const key = this.getTableKey(check);
|
|
182
|
-
ret[key] ??= [];
|
|
183
|
-
const m = check.expression.match(/^check \(\((.*)\)\)$/i);
|
|
184
|
-
const def = m?.[1].replace(/\((.*?)\)::\w+/g, '$1');
|
|
185
|
-
ret[key].push({
|
|
186
|
-
name: check.name,
|
|
187
|
-
columnName: check.column_name,
|
|
188
|
-
definition: check.expression,
|
|
189
|
-
expression: def,
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
return ret;
|
|
193
|
-
}
|
|
194
|
-
async getAllForeignKeys(connection, tablesBySchemas) {
|
|
195
|
-
const sql = `select nsp1.nspname schema_name, cls1.relname table_name, nsp2.nspname referenced_schema_name,
|
|
196
|
-
cls2.relname referenced_table_name, a.attname column_name, af.attname referenced_column_name, conname constraint_name,
|
|
197
|
-
confupdtype update_rule, confdeltype delete_rule, array_position(con.conkey,a.attnum) as ord, condeferrable, condeferred,
|
|
198
|
-
pg_get_constraintdef(con.oid) as constraint_def
|
|
199
|
-
from pg_attribute a
|
|
200
|
-
join pg_constraint con on con.conrelid = a.attrelid AND a.attnum = ANY (con.conkey)
|
|
201
|
-
join pg_attribute af on af.attnum = con.confkey[array_position(con.conkey,a.attnum)] AND af.attrelid = con.confrelid
|
|
202
|
-
join pg_namespace nsp1 on nsp1.oid = con.connamespace
|
|
203
|
-
join pg_class cls1 on cls1.oid = con.conrelid
|
|
204
|
-
join pg_class cls2 on cls2.oid = confrelid
|
|
205
|
-
join pg_namespace nsp2 on nsp2.oid = cls2.relnamespace
|
|
206
|
-
where (${[...tablesBySchemas.entries()].map(([schema, tables]) => `(cls1.relname in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}) and nsp1.nspname = ${this.platform.quoteValue(schema)})`).join(' or ')})
|
|
207
|
-
and confrelid > 0
|
|
208
|
-
order by nsp1.nspname, cls1.relname, constraint_name, ord`;
|
|
209
|
-
const allFks = await connection.execute(sql);
|
|
210
|
-
const ret = {};
|
|
211
|
-
function mapReferentialIntegrity(value, def) {
|
|
212
|
-
const match = ['n', 'd'].includes(value) && def.match(/ON DELETE (SET (NULL|DEFAULT) \(.*?\))/);
|
|
213
|
-
if (match) {
|
|
214
|
-
return match[1];
|
|
215
|
-
}
|
|
216
|
-
/* v8 ignore next */
|
|
217
|
-
switch (value) {
|
|
218
|
-
case 'r': return 'RESTRICT';
|
|
219
|
-
case 'c': return 'CASCADE';
|
|
220
|
-
case 'n': return 'SET NULL';
|
|
221
|
-
case 'd': return 'SET DEFAULT';
|
|
222
|
-
case 'a':
|
|
223
|
-
default: return 'NO ACTION';
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
for (const fk of allFks) {
|
|
227
|
-
fk.update_rule = mapReferentialIntegrity(fk.update_rule, fk.constraint_def);
|
|
228
|
-
fk.delete_rule = mapReferentialIntegrity(fk.delete_rule, fk.constraint_def);
|
|
229
|
-
if (fk.condeferrable) {
|
|
230
|
-
fk.defer_mode = fk.condeferred ? DeferMode.INITIALLY_DEFERRED : DeferMode.INITIALLY_IMMEDIATE;
|
|
231
|
-
}
|
|
232
|
-
const key = this.getTableKey(fk);
|
|
233
|
-
ret[key] ??= [];
|
|
234
|
-
ret[key].push(fk);
|
|
235
|
-
}
|
|
236
|
-
Object.keys(ret).forEach(key => {
|
|
237
|
-
const [schemaName, tableName] = key.split('.');
|
|
238
|
-
ret[key] = this.mapForeignKeys(ret[key], tableName, schemaName);
|
|
239
|
-
});
|
|
240
|
-
return ret;
|
|
241
|
-
}
|
|
242
|
-
async getNativeEnumDefinitions(connection, schemas) {
|
|
243
|
-
const uniqueSchemas = Utils.unique(schemas);
|
|
244
|
-
const res = await connection.execute(`select t.typname as enum_name, n.nspname as schema_name, array_agg(e.enumlabel order by e.enumsortorder) as enum_value
|
|
245
|
-
from pg_type t
|
|
246
|
-
join pg_enum e on t.oid = e.enumtypid
|
|
247
|
-
join pg_catalog.pg_namespace n on n.oid = t.typnamespace
|
|
248
|
-
where n.nspname in (${Array(uniqueSchemas.length).fill('?').join(', ')})
|
|
249
|
-
group by t.typname, n.nspname`, uniqueSchemas);
|
|
250
|
-
return res.reduce((o, row) => {
|
|
251
|
-
let name = row.enum_name;
|
|
252
|
-
if (row.schema_name && row.schema_name !== this.platform.getDefaultSchemaName()) {
|
|
253
|
-
name = row.schema_name + '.' + name;
|
|
254
|
-
}
|
|
255
|
-
let items = row.enum_value;
|
|
256
|
-
if (!Array.isArray(items)) {
|
|
257
|
-
items = this.platform.unmarshallArray(row.enum_value);
|
|
258
|
-
}
|
|
259
|
-
o[name] = {
|
|
260
|
-
name: row.enum_name,
|
|
261
|
-
schema: row.schema_name,
|
|
262
|
-
items,
|
|
263
|
-
};
|
|
264
|
-
return o;
|
|
265
|
-
}, {});
|
|
266
|
-
}
|
|
267
|
-
getCreateNativeEnumSQL(name, values, schema) {
|
|
268
|
-
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
269
|
-
name = schema + '.' + name;
|
|
270
|
-
}
|
|
271
|
-
return `create type ${this.quote(name)} as enum (${values.map(value => this.platform.quoteValue(value)).join(', ')})`;
|
|
272
|
-
}
|
|
273
|
-
getDropNativeEnumSQL(name, schema) {
|
|
274
|
-
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
275
|
-
name = schema + '.' + name;
|
|
276
|
-
}
|
|
277
|
-
return `drop type ${this.quote(name)}`;
|
|
278
|
-
}
|
|
279
|
-
getAlterNativeEnumSQL(name, schema, value, items, oldItems) {
|
|
280
|
-
if (schema && schema !== this.platform.getDefaultSchemaName()) {
|
|
281
|
-
name = schema + '.' + name;
|
|
282
|
-
}
|
|
283
|
-
let suffix = '';
|
|
284
|
-
if (items && value && oldItems) {
|
|
285
|
-
const position = items.indexOf(value);
|
|
286
|
-
if (position > 0) {
|
|
287
|
-
suffix = ` after ${this.platform.quoteValue(items[position - 1])}`;
|
|
288
|
-
}
|
|
289
|
-
else if (items.length > 1 && oldItems.length > 0) {
|
|
290
|
-
suffix = ` before ${this.platform.quoteValue(oldItems[0])}`;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
return `alter type ${this.quote(name)} add value if not exists ${this.platform.quoteValue(value)}${suffix}`;
|
|
294
|
-
}
|
|
295
|
-
getEnumDefinitions(checks) {
|
|
296
|
-
return checks.reduce((o, item) => {
|
|
297
|
-
// check constraints are defined as one of:
|
|
298
|
-
// `CHECK ((type = ANY (ARRAY['local'::text, 'global'::text])))`
|
|
299
|
-
// `CHECK (("columnName" = ANY (ARRAY['local'::text, 'global'::text])))`
|
|
300
|
-
// `CHECK (((enum_test)::text = ANY ((ARRAY['a'::character varying, 'b'::character varying, 'c'::character varying])::text[])))`
|
|
301
|
-
// `CHECK ((("enumTest")::text = ANY ((ARRAY['a'::character varying, 'b'::character varying, 'c'::character varying])::text[])))`
|
|
302
|
-
// `CHECK ((type = 'a'::text))`
|
|
303
|
-
const m1 = item.definition?.match(/check \(\(\("?(\w+)"?\)::/i) || item.definition?.match(/check \(\("?(\w+)"? = /i);
|
|
304
|
-
const m2 = item.definition?.match(/\(array\[(.*)]\)/i) || item.definition?.match(/ = (.*)\)/i);
|
|
305
|
-
if (item.columnName && m1 && m2) {
|
|
306
|
-
const m3 = m2[1].match(/('[^']*'::text)/g);
|
|
307
|
-
let items;
|
|
308
|
-
/* v8 ignore next */
|
|
309
|
-
if (m3) {
|
|
310
|
-
items = m3.map((item) => item.trim().match(/^\(?'(.*)'/)?.[1]);
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
items = m2[1].split(',').map((item) => item.trim().match(/^\(?'(.*)'/)?.[1]);
|
|
314
|
-
}
|
|
315
|
-
items = items.filter(item => item !== undefined);
|
|
316
|
-
if (items.length > 0) {
|
|
317
|
-
o[item.columnName] = items;
|
|
318
|
-
item.expression = `${this.quote(item.columnName)} in ('${items.join("', '")}')`;
|
|
319
|
-
item.definition = `check (${item.expression})`;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return o;
|
|
323
|
-
}, {});
|
|
324
|
-
}
|
|
325
|
-
createTableColumn(column, table) {
|
|
326
|
-
const pk = table.getPrimaryKey();
|
|
327
|
-
const compositePK = pk?.composite;
|
|
328
|
-
const primaryKey = !this.hasNonDefaultPrimaryKeyName(table);
|
|
329
|
-
const col = [this.quote(column.name)];
|
|
330
|
-
if (column.autoincrement && !column.generated && !compositePK) {
|
|
331
|
-
col.push(column.mappedType.getColumnType({ autoincrement: true }, this.platform));
|
|
332
|
-
}
|
|
333
|
-
else {
|
|
334
|
-
let columnType = column.type;
|
|
335
|
-
if (column.nativeEnumName) {
|
|
336
|
-
const parts = column.type.split('.');
|
|
337
|
-
if (parts.length === 2 && parts[0] === '*') {
|
|
338
|
-
columnType = `${table.schema}.${parts[1]}`;
|
|
339
|
-
}
|
|
340
|
-
if (columnType.endsWith('[]')) {
|
|
341
|
-
columnType = this.quote(columnType.substring(0, columnType.length - 2)) + '[]';
|
|
342
|
-
}
|
|
343
|
-
else {
|
|
344
|
-
columnType = this.quote(columnType);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
if (column.generated === 'by default as identity') {
|
|
348
|
-
columnType += ` generated ${column.generated}`;
|
|
349
|
-
}
|
|
350
|
-
else if (column.generated) {
|
|
351
|
-
columnType += ` generated always as ${column.generated}`;
|
|
352
|
-
}
|
|
353
|
-
col.push(columnType);
|
|
354
|
-
Utils.runIfNotEmpty(() => col.push('null'), column.nullable);
|
|
355
|
-
Utils.runIfNotEmpty(() => col.push('not null'), !column.nullable);
|
|
356
|
-
}
|
|
357
|
-
if (column.autoincrement && !compositePK) {
|
|
358
|
-
Utils.runIfNotEmpty(() => col.push('primary key'), primaryKey && column.primary);
|
|
359
|
-
}
|
|
360
|
-
const useDefault = column.default != null && column.default !== 'null' && !column.autoincrement;
|
|
361
|
-
Utils.runIfNotEmpty(() => col.push(`default ${column.default}`), useDefault);
|
|
362
|
-
return col.join(' ');
|
|
363
|
-
}
|
|
364
|
-
getPreAlterTable(tableDiff, safe) {
|
|
365
|
-
const ret = [];
|
|
366
|
-
const parts = tableDiff.name.split('.');
|
|
367
|
-
const tableName = parts.pop();
|
|
368
|
-
const schemaName = parts.pop();
|
|
369
|
-
/* v8 ignore next */
|
|
370
|
-
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
|
|
371
|
-
const quotedName = this.quote(name);
|
|
372
|
-
// detect that the column was an enum before and remove the check constraint in such case here
|
|
373
|
-
const changedEnums = Object.values(tableDiff.changedColumns).filter(col => col.fromColumn.mappedType instanceof EnumType);
|
|
374
|
-
for (const col of changedEnums) {
|
|
375
|
-
if (!col.fromColumn.nativeEnumName && col.column.nativeEnumName && col.fromColumn.default) {
|
|
376
|
-
ret.push(`alter table ${quotedName} alter column "${col.column.name}" drop default`);
|
|
377
|
-
}
|
|
378
|
-
if (col.fromColumn.nativeEnumName && !col.column.nativeEnumName && col.fromColumn.default) {
|
|
379
|
-
ret.push(`alter table ${quotedName} alter column "${col.column.name}" drop default`);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
// changing uuid column type requires to cast it to text first
|
|
383
|
-
const uuids = Object.values(tableDiff.changedColumns).filter(col => col.changedProperties.has('type') && col.fromColumn.type === 'uuid');
|
|
384
|
-
for (const col of uuids) {
|
|
385
|
-
ret.push(`alter table ${quotedName} alter column "${col.column.name}" type text using ("${col.column.name}"::text)`);
|
|
386
|
-
}
|
|
387
|
-
for (const { column } of Object.values(tableDiff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
|
|
388
|
-
if (!column.autoincrement && column.default == null) {
|
|
389
|
-
ret.push(`alter table ${quotedName} alter column ${this.quote(column.name)} drop default`);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
return ret;
|
|
393
|
-
}
|
|
394
|
-
castColumn(name, type) {
|
|
395
|
-
if (type === 'uuid') {
|
|
396
|
-
type = 'text::uuid';
|
|
397
|
-
}
|
|
398
|
-
return ` using (${this.quote(name)}::${type})`;
|
|
399
|
-
}
|
|
400
|
-
dropForeignKey(tableName, constraintName) {
|
|
401
|
-
return `alter table ${this.quote(tableName)} drop constraint ${this.quote(constraintName)}`;
|
|
402
|
-
}
|
|
403
|
-
getPostAlterTable(tableDiff, safe) {
|
|
404
|
-
const ret = [];
|
|
405
|
-
const parts = tableDiff.name.split('.');
|
|
406
|
-
const tableName = parts.pop();
|
|
407
|
-
const schemaName = parts.pop();
|
|
408
|
-
/* v8 ignore next */
|
|
409
|
-
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
|
|
410
|
-
const quotedName = this.quote(name);
|
|
411
|
-
// detect that the column was an enum before and remove the check constraint in such a case here
|
|
412
|
-
const changedEnums = Object.values(tableDiff.changedColumns).filter(col => col.fromColumn.mappedType instanceof EnumType);
|
|
413
|
-
for (const col of changedEnums) {
|
|
414
|
-
if (!col.fromColumn.nativeEnumName && col.column.nativeEnumName && col.column.default) {
|
|
415
|
-
ret.push(`alter table ${quotedName} alter column "${col.column.name}" set default ${col.column.default}`);
|
|
416
|
-
}
|
|
417
|
-
if (col.fromColumn.nativeEnumName && !col.column.nativeEnumName && col.column.default) {
|
|
418
|
-
ret.push(`alter table ${quotedName} alter column "${col.column.name}" set default ${col.column.default}`);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
for (const { column } of Object.values(tableDiff.changedColumns).filter(diff => diff.changedProperties.has('autoincrement'))) {
|
|
422
|
-
ret.push(...this.getAlterColumnAutoincrement(tableName, column, schemaName));
|
|
423
|
-
}
|
|
424
|
-
return ret;
|
|
425
|
-
}
|
|
426
|
-
getAlterColumnAutoincrement(tableName, column, schemaName) {
|
|
427
|
-
const ret = [];
|
|
428
|
-
/* v8 ignore next */
|
|
429
|
-
const name = (schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName;
|
|
430
|
-
if (column.autoincrement) {
|
|
431
|
-
const seqName = this.platform.getIndexName(tableName, [column.name], 'sequence');
|
|
432
|
-
ret.push(`create sequence if not exists ${this.quote(seqName)}`);
|
|
433
|
-
ret.push(`select setval('${seqName}', (select max(${this.quote(column.name)}) from ${this.quote(name)}))`);
|
|
434
|
-
ret.push(`alter table ${this.quote(name)} alter column ${this.quote(column.name)} set default nextval('${seqName}')`);
|
|
435
|
-
}
|
|
436
|
-
return ret;
|
|
437
|
-
}
|
|
438
|
-
getChangeColumnCommentSQL(tableName, to, schemaName) {
|
|
439
|
-
const name = this.quote((schemaName && schemaName !== this.platform.getDefaultSchemaName() ? schemaName + '.' : '') + tableName);
|
|
440
|
-
const value = to.comment ? this.platform.quoteValue(to.comment) : 'null';
|
|
441
|
-
return `comment on column ${name}."${to.name}" is ${value}`;
|
|
442
|
-
}
|
|
443
|
-
alterTableComment(table, comment) {
|
|
444
|
-
return `comment on table ${table.getQuotedName()} is ${this.platform.quoteValue(comment ?? '')}`;
|
|
445
|
-
}
|
|
446
|
-
normalizeDefaultValue(defaultValue, length) {
|
|
447
|
-
if (!defaultValue || typeof defaultValue !== 'string') {
|
|
448
|
-
return super.normalizeDefaultValue(defaultValue, length, PostgreSqlSchemaHelper.DEFAULT_VALUES);
|
|
449
|
-
}
|
|
450
|
-
const match = defaultValue.match(/^'(.*)'::(.*)$/);
|
|
451
|
-
if (match) {
|
|
452
|
-
if (match[2] === 'integer') {
|
|
453
|
-
return +match[1];
|
|
454
|
-
}
|
|
455
|
-
return `'${match[1]}'`;
|
|
456
|
-
}
|
|
457
|
-
return super.normalizeDefaultValue(defaultValue, length, PostgreSqlSchemaHelper.DEFAULT_VALUES);
|
|
458
|
-
}
|
|
459
|
-
appendComments(table) {
|
|
460
|
-
const sql = [];
|
|
461
|
-
if (table.comment) {
|
|
462
|
-
const comment = this.platform.quoteValue(table.comment).replace(/^'|'$/g, '');
|
|
463
|
-
sql.push(`comment on table ${table.getQuotedName()} is ${this.platform.quoteValue(this.processComment(comment))}`);
|
|
464
|
-
}
|
|
465
|
-
for (const column of table.getColumns()) {
|
|
466
|
-
if (column.comment) {
|
|
467
|
-
const comment = this.platform.quoteValue(this.processComment(column.comment));
|
|
468
|
-
sql.push(`comment on column ${table.getQuotedName()}.${this.quote(column.name)} is ${comment}`);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
return sql;
|
|
472
|
-
}
|
|
473
|
-
getDatabaseExistsSQL(name) {
|
|
474
|
-
return `select 1 from pg_database where datname = '${name}'`;
|
|
475
|
-
}
|
|
476
|
-
getDatabaseNotExistsError(dbName) {
|
|
477
|
-
return `database "${dbName}" does not exist`;
|
|
478
|
-
}
|
|
479
|
-
getManagementDbName() {
|
|
480
|
-
return this.platform.getConfig().get('schemaGenerator', {}).managementDbName ?? 'postgres';
|
|
481
|
-
}
|
|
482
|
-
disableForeignKeysSQL() {
|
|
483
|
-
return `set session_replication_role = 'replica';`;
|
|
484
|
-
}
|
|
485
|
-
enableForeignKeysSQL() {
|
|
486
|
-
return `set session_replication_role = 'origin';`;
|
|
487
|
-
}
|
|
488
|
-
getRenameIndexSQL(tableName, index, oldIndexName) {
|
|
489
|
-
oldIndexName = this.quote(oldIndexName);
|
|
490
|
-
const keyName = this.quote(index.keyName);
|
|
491
|
-
return [`alter index ${oldIndexName} rename to ${keyName}`];
|
|
492
|
-
}
|
|
493
|
-
dropIndex(table, index, oldIndexName = index.keyName) {
|
|
494
|
-
if (index.primary || (index.unique && index.constraint)) {
|
|
495
|
-
return `alter table ${this.quote(table)} drop constraint ${this.quote(oldIndexName)}`;
|
|
496
|
-
}
|
|
497
|
-
return `drop index ${this.quote(oldIndexName)}`;
|
|
498
|
-
}
|
|
499
|
-
getIndexesSQL(tables) {
|
|
500
|
-
return `select indrelid::regclass as table_name, ns.nspname as schema_name, relname as constraint_name, idx.indisunique as unique, idx.indisprimary as primary, contype, condeferrable, condeferred,
|
|
501
|
-
array(
|
|
502
|
-
select pg_get_indexdef(idx.indexrelid, k + 1, true)
|
|
503
|
-
from generate_subscripts(idx.indkey, 1) as k
|
|
504
|
-
order by k
|
|
505
|
-
) as index_def,
|
|
506
|
-
pg_get_indexdef(idx.indexrelid) as expression,
|
|
507
|
-
c.condeferrable as deferrable,
|
|
508
|
-
c.condeferred as initially_deferred
|
|
509
|
-
from pg_index idx
|
|
510
|
-
join pg_class as i on i.oid = idx.indexrelid
|
|
511
|
-
join pg_namespace as ns on i.relnamespace = ns.oid
|
|
512
|
-
left join pg_constraint as c on c.conname = i.relname
|
|
513
|
-
where indrelid in (${tables.map(t => `${this.platform.quoteValue(`${this.quote(t.schema_name)}.${this.quote(t.table_name)}`)}::regclass`).join(', ')})
|
|
514
|
-
order by relname`;
|
|
515
|
-
}
|
|
516
|
-
getChecksSQL(tablesBySchemas) {
|
|
517
|
-
return `select ccu.table_name as table_name, ccu.table_schema as schema_name, pgc.conname as name, conrelid::regclass as table_from, ccu.column_name as column_name, pg_get_constraintdef(pgc.oid) as expression
|
|
518
|
-
from pg_constraint pgc
|
|
519
|
-
join pg_namespace nsp on nsp.oid = pgc.connamespace
|
|
520
|
-
join pg_class cls on pgc.conrelid = cls.oid
|
|
521
|
-
join information_schema.constraint_column_usage ccu on pgc.conname = ccu.constraint_name and nsp.nspname = ccu.constraint_schema
|
|
522
|
-
where contype = 'c' and (${[...tablesBySchemas.entries()].map(([schema, tables]) => `ccu.table_name in (${tables.map(t => this.platform.quoteValue(t.table_name)).join(',')}) and ccu.table_schema = ${this.platform.quoteValue(schema)}`).join(' or ')})
|
|
523
|
-
order by pgc.conname`;
|
|
524
|
-
}
|
|
525
|
-
inferLengthFromColumnType(type) {
|
|
526
|
-
const match = type.match(/^(\w+(?:\s+\w+)*)\s*(?:\(\s*(\d+)\s*\)|$)/);
|
|
527
|
-
if (!match) {
|
|
528
|
-
return;
|
|
529
|
-
}
|
|
530
|
-
if (!match[2]) {
|
|
531
|
-
switch (match[1]) {
|
|
532
|
-
case 'character varying':
|
|
533
|
-
case 'varchar':
|
|
534
|
-
case 'bpchar':
|
|
535
|
-
case 'char':
|
|
536
|
-
case 'character':
|
|
537
|
-
return -1;
|
|
538
|
-
case 'interval':
|
|
539
|
-
case 'time':
|
|
540
|
-
case 'timestamp':
|
|
541
|
-
case 'timestamptz':
|
|
542
|
-
return this.platform.getDefaultDateTimeLength();
|
|
543
|
-
}
|
|
544
|
-
return;
|
|
545
|
-
}
|
|
546
|
-
return +match[2];
|
|
547
|
-
}
|
|
548
|
-
}
|
package/types/FullTextType.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Type, type TransformContext, type RawQueryFragment } from '@mikro-orm/core';
|
|
2
|
-
import type { PostgreSqlPlatform } from '../PostgreSqlPlatform.js';
|
|
3
|
-
type FullTextWeight = 'A' | 'B' | 'C' | 'D';
|
|
4
|
-
export type WeightedFullTextValue = {
|
|
5
|
-
[K in FullTextWeight]?: string | null;
|
|
6
|
-
};
|
|
7
|
-
export declare class FullTextType extends Type<string | WeightedFullTextValue, string | null | RawQueryFragment> {
|
|
8
|
-
regconfig: string;
|
|
9
|
-
constructor(regconfig?: string);
|
|
10
|
-
compareAsType(): string;
|
|
11
|
-
getColumnType(): string;
|
|
12
|
-
convertToDatabaseValue(value: string | WeightedFullTextValue, platform: PostgreSqlPlatform, context?: TransformContext | boolean): string | null | RawQueryFragment;
|
|
13
|
-
}
|
|
14
|
-
export {};
|
package/types/FullTextType.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { raw, Type } from '@mikro-orm/core';
|
|
2
|
-
export class FullTextType extends Type {
|
|
3
|
-
regconfig;
|
|
4
|
-
constructor(regconfig = 'simple') {
|
|
5
|
-
super();
|
|
6
|
-
this.regconfig = regconfig;
|
|
7
|
-
}
|
|
8
|
-
compareAsType() {
|
|
9
|
-
return 'any';
|
|
10
|
-
}
|
|
11
|
-
getColumnType() {
|
|
12
|
-
return 'tsvector';
|
|
13
|
-
}
|
|
14
|
-
// Use convertToDatabaseValue to prepare insert queries as this method has
|
|
15
|
-
// access to the raw JS value. Return Knex#raw to prevent QueryBuilderHelper#mapData
|
|
16
|
-
// from sanitizing the returned chaing of SQL functions.
|
|
17
|
-
convertToDatabaseValue(value, platform, context) {
|
|
18
|
-
// Don't convert to values from select queries to the to_tsvector notation
|
|
19
|
-
// these should be compared as string using a special oparator or function
|
|
20
|
-
// this behaviour is defined in Platform#getFullTextWhereClause.
|
|
21
|
-
// This is always a string.
|
|
22
|
-
if (typeof context === 'object' && context.fromQuery) {
|
|
23
|
-
return value;
|
|
24
|
-
}
|
|
25
|
-
// Null values should not be processed
|
|
26
|
-
if (!value) {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
// the object from that looks like { A: 'test data', B: 'test data2' ... }
|
|
30
|
-
// must be converted to
|
|
31
|
-
// setweight(to_tsvector(regconfig, value), A) || setweight(to_tsvector(regconfig, value), B)... etc
|
|
32
|
-
// use Knex#raw to do binding of the values sanitization of the boundvalues
|
|
33
|
-
// as we return a raw string which should not be sanitzed anymore
|
|
34
|
-
if (typeof value === 'object') {
|
|
35
|
-
const bindings = [];
|
|
36
|
-
const sqlParts = [];
|
|
37
|
-
for (const [weight, data] of Object.entries(value)) {
|
|
38
|
-
// Check whether the weight is valid according to Postgres,
|
|
39
|
-
// Postgres allows the weight to be upper and lowercase.
|
|
40
|
-
if (!['A', 'B', 'C', 'D'].includes(weight.toUpperCase())) {
|
|
41
|
-
throw new Error('Weight should be one of A, B, C, D.');
|
|
42
|
-
}
|
|
43
|
-
// Ignore all values that are not a string
|
|
44
|
-
if (typeof data === 'string') {
|
|
45
|
-
sqlParts.push('setweight(to_tsvector(?, ?), ?)');
|
|
46
|
-
bindings.push(this.regconfig, data, weight);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Return null if the object has no valid strings
|
|
50
|
-
if (sqlParts.length === 0) {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
// Join all the `setweight` parts using the PostgreSQL tsvector `||` concatenation operator
|
|
54
|
-
return raw(sqlParts.join(' || '), bindings);
|
|
55
|
-
}
|
|
56
|
-
// if it's not an object, it is expected to be string which does not have to be wrapped in setweight.
|
|
57
|
-
return raw('to_tsvector(?, ?)', [this.regconfig, value]);
|
|
58
|
-
}
|
|
59
|
-
}
|
package/types/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './FullTextType.js';
|
package/types/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './FullTextType.js';
|