graphile-settings 4.9.2 → 4.10.0
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/esm/plugins/PublicKeySignature.d.ts +11 -0
- package/esm/plugins/PublicKeySignature.js +184 -0
- package/esm/plugins/conflict-detector.d.ts +7 -0
- package/esm/plugins/conflict-detector.js +67 -0
- package/esm/plugins/custom-inflector.d.ts +9 -0
- package/esm/plugins/custom-inflector.js +394 -0
- package/esm/plugins/enable-all-filter-columns.d.ts +60 -0
- package/esm/plugins/enable-all-filter-columns.js +85 -0
- package/esm/plugins/index.d.ts +16 -4
- package/esm/plugins/index.js +25 -4
- package/esm/plugins/inflector-logger.d.ts +7 -0
- package/esm/plugins/inflector-logger.js +215 -0
- package/esm/plugins/many-to-many-preset.d.ts +62 -0
- package/esm/plugins/many-to-many-preset.js +86 -0
- package/esm/plugins/meta-schema/cache.d.ts +4 -0
- package/esm/plugins/meta-schema/cache.js +7 -0
- package/esm/plugins/meta-schema/constraint-meta-builders.d.ts +13 -0
- package/esm/plugins/meta-schema/constraint-meta-builders.js +51 -0
- package/esm/plugins/meta-schema/graphql-meta-field.d.ts +4 -0
- package/esm/plugins/meta-schema/graphql-meta-field.js +201 -0
- package/esm/plugins/meta-schema/inflection-utils.d.ts +4 -0
- package/esm/plugins/meta-schema/inflection-utils.js +20 -0
- package/esm/plugins/meta-schema/name-meta-builders.d.ts +4 -0
- package/esm/plugins/meta-schema/name-meta-builders.js +38 -0
- package/esm/plugins/meta-schema/plugin.d.ts +2 -0
- package/esm/plugins/meta-schema/plugin.js +23 -0
- package/esm/plugins/meta-schema/relation-meta-builders.d.ts +8 -0
- package/esm/plugins/meta-schema/relation-meta-builders.js +115 -0
- package/esm/plugins/meta-schema/table-meta-builder.d.ts +2 -0
- package/esm/plugins/meta-schema/table-meta-builder.js +69 -0
- package/esm/plugins/meta-schema/table-meta-context.d.ts +13 -0
- package/esm/plugins/meta-schema/table-meta-context.js +11 -0
- package/esm/plugins/meta-schema/table-resource-utils.d.ts +12 -0
- package/esm/plugins/meta-schema/table-resource-utils.js +50 -0
- package/esm/plugins/meta-schema/type-mappings.d.ts +3 -0
- package/esm/plugins/meta-schema/type-mappings.js +75 -0
- package/esm/plugins/meta-schema/types.d.ts +206 -0
- package/esm/plugins/meta-schema/types.js +1 -0
- package/esm/plugins/meta-schema.d.ts +19 -0
- package/esm/plugins/meta-schema.js +20 -0
- package/esm/plugins/minimal-preset.d.ts +7 -0
- package/esm/plugins/minimal-preset.js +42 -0
- package/esm/plugins/pg-type-mappings.d.ts +41 -0
- package/esm/plugins/pg-type-mappings.js +122 -0
- package/esm/plugins/primary-key-only.d.ts +96 -0
- package/esm/plugins/primary-key-only.js +143 -0
- package/esm/plugins/required-input-plugin.d.ts +37 -0
- package/esm/plugins/required-input-plugin.js +88 -0
- package/esm/presets/constructive-preset.js +2 -1
- package/package.json +11 -9
- package/plugins/PublicKeySignature.d.ts +11 -0
- package/plugins/PublicKeySignature.js +191 -0
- package/plugins/conflict-detector.d.ts +7 -0
- package/plugins/conflict-detector.js +70 -0
- package/plugins/custom-inflector.d.ts +9 -0
- package/plugins/custom-inflector.js +397 -0
- package/plugins/enable-all-filter-columns.d.ts +60 -0
- package/plugins/enable-all-filter-columns.js +88 -0
- package/plugins/index.d.ts +16 -4
- package/plugins/index.js +54 -31
- package/plugins/inflector-logger.d.ts +7 -0
- package/plugins/inflector-logger.js +218 -0
- package/plugins/many-to-many-preset.d.ts +62 -0
- package/plugins/many-to-many-preset.js +89 -0
- package/plugins/meta-schema/cache.d.ts +4 -0
- package/plugins/meta-schema/cache.js +12 -0
- package/plugins/meta-schema/constraint-meta-builders.d.ts +13 -0
- package/plugins/meta-schema/constraint-meta-builders.js +58 -0
- package/plugins/meta-schema/graphql-meta-field.d.ts +4 -0
- package/plugins/meta-schema/graphql-meta-field.js +204 -0
- package/plugins/meta-schema/inflection-utils.d.ts +4 -0
- package/plugins/meta-schema/inflection-utils.js +25 -0
- package/plugins/meta-schema/name-meta-builders.d.ts +4 -0
- package/plugins/meta-schema/name-meta-builders.js +43 -0
- package/plugins/meta-schema/plugin.d.ts +2 -0
- package/plugins/meta-schema/plugin.js +26 -0
- package/plugins/meta-schema/relation-meta-builders.d.ts +8 -0
- package/plugins/meta-schema/relation-meta-builders.js +120 -0
- package/plugins/meta-schema/table-meta-builder.d.ts +2 -0
- package/plugins/meta-schema/table-meta-builder.js +72 -0
- package/plugins/meta-schema/table-meta-context.d.ts +13 -0
- package/plugins/meta-schema/table-meta-context.js +15 -0
- package/plugins/meta-schema/table-resource-utils.d.ts +12 -0
- package/plugins/meta-schema/table-resource-utils.js +60 -0
- package/plugins/meta-schema/type-mappings.d.ts +3 -0
- package/plugins/meta-schema/type-mappings.js +79 -0
- package/plugins/meta-schema/types.d.ts +206 -0
- package/plugins/meta-schema/types.js +2 -0
- package/plugins/meta-schema.d.ts +19 -0
- package/plugins/meta-schema.js +20 -0
- package/plugins/minimal-preset.d.ts +7 -0
- package/plugins/minimal-preset.js +45 -0
- package/plugins/pg-type-mappings.d.ts +41 -0
- package/plugins/pg-type-mappings.js +128 -0
- package/plugins/primary-key-only.d.ts +96 -0
- package/plugins/primary-key-only.js +147 -0
- package/plugins/required-input-plugin.d.ts +37 -0
- package/plugins/required-input-plugin.js +91 -0
- package/presets/constructive-preset.js +11 -10
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const PG_TO_GQL_TYPE = {
|
|
2
|
+
text: 'String',
|
|
3
|
+
varchar: 'String',
|
|
4
|
+
char: 'String',
|
|
5
|
+
name: 'String',
|
|
6
|
+
bpchar: 'String',
|
|
7
|
+
uuid: 'UUID',
|
|
8
|
+
int2: 'Int',
|
|
9
|
+
int4: 'Int',
|
|
10
|
+
integer: 'Int',
|
|
11
|
+
int8: 'BigInt',
|
|
12
|
+
bigint: 'BigInt',
|
|
13
|
+
float4: 'Float',
|
|
14
|
+
float8: 'Float',
|
|
15
|
+
numeric: 'BigFloat',
|
|
16
|
+
bool: 'Boolean',
|
|
17
|
+
boolean: 'Boolean',
|
|
18
|
+
timestamptz: 'Datetime',
|
|
19
|
+
timestamp: 'Datetime',
|
|
20
|
+
date: 'Date',
|
|
21
|
+
time: 'Time',
|
|
22
|
+
timetz: 'Time',
|
|
23
|
+
json: 'JSON',
|
|
24
|
+
jsonb: 'JSON',
|
|
25
|
+
interval: 'Interval',
|
|
26
|
+
point: 'Point',
|
|
27
|
+
geometry: 'GeoJSON',
|
|
28
|
+
geography: 'GeoJSON',
|
|
29
|
+
inet: 'InternetAddress',
|
|
30
|
+
cidr: 'InternetAddress',
|
|
31
|
+
xml: 'String',
|
|
32
|
+
bytea: 'String',
|
|
33
|
+
macaddr: 'String',
|
|
34
|
+
};
|
|
35
|
+
export function pgTypeToGqlType(pgTypeName) {
|
|
36
|
+
return PG_TO_GQL_TYPE[pgTypeName] || pgTypeName;
|
|
37
|
+
}
|
|
38
|
+
function resolveGqlTypeName(build, codec) {
|
|
39
|
+
if (!codec)
|
|
40
|
+
return 'unknown';
|
|
41
|
+
try {
|
|
42
|
+
const codecForLookup = codec.arrayOfCodec || codec;
|
|
43
|
+
if (build?.hasGraphQLTypeForPgCodec?.(codecForLookup, 'output')) {
|
|
44
|
+
const resolved = build.getGraphQLTypeNameByPgCodec?.(codecForLookup, 'output');
|
|
45
|
+
if (resolved)
|
|
46
|
+
return resolved;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Fall through to static fallback mapping.
|
|
51
|
+
}
|
|
52
|
+
const pgTypeName = codec.name || 'unknown';
|
|
53
|
+
const mapped = pgTypeToGqlType(pgTypeName);
|
|
54
|
+
if (mapped !== pgTypeName)
|
|
55
|
+
return mapped;
|
|
56
|
+
const nestedTypeName = codec.arrayOfCodec?.name;
|
|
57
|
+
return nestedTypeName ? pgTypeToGqlType(nestedTypeName) : pgTypeName;
|
|
58
|
+
}
|
|
59
|
+
export function buildFieldMeta(name, attr, build) {
|
|
60
|
+
const pgType = attr?.codec?.name || 'unknown';
|
|
61
|
+
const isNotNull = attr?.notNull || false;
|
|
62
|
+
const hasDefault = attr?.hasDefault || false;
|
|
63
|
+
return {
|
|
64
|
+
name,
|
|
65
|
+
type: {
|
|
66
|
+
pgType,
|
|
67
|
+
gqlType: build ? resolveGqlTypeName(build, attr?.codec) : pgTypeToGqlType(pgType),
|
|
68
|
+
isArray: !!attr?.codec?.arrayOfCodec,
|
|
69
|
+
isNotNull,
|
|
70
|
+
hasDefault,
|
|
71
|
+
},
|
|
72
|
+
isNotNull,
|
|
73
|
+
hasDefault,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
export interface TableMeta {
|
|
2
|
+
name: string;
|
|
3
|
+
schemaName: string;
|
|
4
|
+
fields: FieldMeta[];
|
|
5
|
+
indexes: IndexMeta[];
|
|
6
|
+
constraints: ConstraintsMeta;
|
|
7
|
+
foreignKeyConstraints: ForeignKeyConstraintMeta[];
|
|
8
|
+
primaryKeyConstraints: PrimaryKeyConstraintMeta[];
|
|
9
|
+
uniqueConstraints: UniqueConstraintMeta[];
|
|
10
|
+
relations: RelationsMeta;
|
|
11
|
+
inflection: InflectionMeta;
|
|
12
|
+
query: QueryMeta;
|
|
13
|
+
}
|
|
14
|
+
export interface FieldMeta {
|
|
15
|
+
name: string;
|
|
16
|
+
type: TypeMeta;
|
|
17
|
+
isNotNull: boolean;
|
|
18
|
+
hasDefault: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface TypeMeta {
|
|
21
|
+
pgType: string;
|
|
22
|
+
gqlType: string;
|
|
23
|
+
isArray: boolean;
|
|
24
|
+
isNotNull?: boolean;
|
|
25
|
+
hasDefault?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface IndexMeta {
|
|
28
|
+
name: string;
|
|
29
|
+
isUnique: boolean;
|
|
30
|
+
isPrimary: boolean;
|
|
31
|
+
columns: string[];
|
|
32
|
+
fields: FieldMeta[];
|
|
33
|
+
}
|
|
34
|
+
export interface ConstraintsMeta {
|
|
35
|
+
primaryKey: PrimaryKeyConstraintMeta | null;
|
|
36
|
+
unique: UniqueConstraintMeta[];
|
|
37
|
+
foreignKey: ForeignKeyConstraintMeta[];
|
|
38
|
+
}
|
|
39
|
+
export interface PrimaryKeyConstraintMeta {
|
|
40
|
+
name: string;
|
|
41
|
+
fields: FieldMeta[];
|
|
42
|
+
}
|
|
43
|
+
export interface UniqueConstraintMeta {
|
|
44
|
+
name: string;
|
|
45
|
+
fields: FieldMeta[];
|
|
46
|
+
}
|
|
47
|
+
export interface ForeignKeyConstraintMeta {
|
|
48
|
+
name: string;
|
|
49
|
+
fields: FieldMeta[];
|
|
50
|
+
referencedTable: string;
|
|
51
|
+
referencedFields: string[];
|
|
52
|
+
refFields: FieldMeta[];
|
|
53
|
+
refTable: {
|
|
54
|
+
name: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export interface RelationsMeta {
|
|
58
|
+
belongsTo: BelongsToRelation[];
|
|
59
|
+
has: HasRelation[];
|
|
60
|
+
hasOne: HasRelation[];
|
|
61
|
+
hasMany: HasRelation[];
|
|
62
|
+
manyToMany: ManyToManyRelation[];
|
|
63
|
+
}
|
|
64
|
+
export interface BelongsToRelation {
|
|
65
|
+
fieldName: string | null;
|
|
66
|
+
isUnique: boolean;
|
|
67
|
+
type: string | null;
|
|
68
|
+
keys: FieldMeta[];
|
|
69
|
+
references: {
|
|
70
|
+
name: string;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export interface HasRelation {
|
|
74
|
+
fieldName: string | null;
|
|
75
|
+
isUnique: boolean;
|
|
76
|
+
type: string | null;
|
|
77
|
+
keys: FieldMeta[];
|
|
78
|
+
referencedBy: {
|
|
79
|
+
name: string;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export interface ManyToManyRelation {
|
|
83
|
+
fieldName: string | null;
|
|
84
|
+
type: string | null;
|
|
85
|
+
junctionTable: {
|
|
86
|
+
name: string;
|
|
87
|
+
};
|
|
88
|
+
junctionLeftConstraint: ForeignKeyConstraintMeta;
|
|
89
|
+
junctionLeftKeyAttributes: FieldMeta[];
|
|
90
|
+
junctionRightConstraint: ForeignKeyConstraintMeta;
|
|
91
|
+
junctionRightKeyAttributes: FieldMeta[];
|
|
92
|
+
leftKeyAttributes: FieldMeta[];
|
|
93
|
+
rightKeyAttributes: FieldMeta[];
|
|
94
|
+
rightTable: {
|
|
95
|
+
name: string;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export interface InflectionMeta {
|
|
99
|
+
tableType: string;
|
|
100
|
+
allRows: string;
|
|
101
|
+
connection: string;
|
|
102
|
+
edge: string;
|
|
103
|
+
filterType: string | null;
|
|
104
|
+
orderByType: string;
|
|
105
|
+
conditionType: string;
|
|
106
|
+
patchType: string | null;
|
|
107
|
+
createInputType: string;
|
|
108
|
+
createPayloadType: string;
|
|
109
|
+
updatePayloadType: string | null;
|
|
110
|
+
deletePayloadType: string;
|
|
111
|
+
}
|
|
112
|
+
export interface QueryMeta {
|
|
113
|
+
all: string;
|
|
114
|
+
one: string | null;
|
|
115
|
+
create: string | null;
|
|
116
|
+
update: string | null;
|
|
117
|
+
delete: string | null;
|
|
118
|
+
}
|
|
119
|
+
export interface PgCodec {
|
|
120
|
+
name: string;
|
|
121
|
+
attributes?: Record<string, PgAttribute>;
|
|
122
|
+
arrayOfCodec?: PgCodec | null;
|
|
123
|
+
isAnonymous?: boolean;
|
|
124
|
+
extensions?: {
|
|
125
|
+
pg?: {
|
|
126
|
+
schemaName?: string;
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
export interface PgAttribute {
|
|
131
|
+
codec?: PgCodec | null;
|
|
132
|
+
notNull?: boolean;
|
|
133
|
+
hasDefault?: boolean;
|
|
134
|
+
}
|
|
135
|
+
export interface PgUnique {
|
|
136
|
+
attributes: string[];
|
|
137
|
+
isPrimary?: boolean;
|
|
138
|
+
tags?: {
|
|
139
|
+
name?: string;
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
export interface PgRelation {
|
|
143
|
+
isReferencee?: boolean;
|
|
144
|
+
localAttributes?: string[];
|
|
145
|
+
remoteAttributes?: string[];
|
|
146
|
+
remoteResource?: PgTableResource | null;
|
|
147
|
+
}
|
|
148
|
+
export interface PgTableResource {
|
|
149
|
+
codec?: PgCodec;
|
|
150
|
+
uniques?: PgUnique[];
|
|
151
|
+
relations?: Record<string, PgRelation>;
|
|
152
|
+
parameters?: unknown;
|
|
153
|
+
isVirtual?: boolean;
|
|
154
|
+
isUnique?: boolean;
|
|
155
|
+
getRelation?: (relationName: string) => PgRelation | undefined;
|
|
156
|
+
getRelations?: () => Record<string, PgRelation>;
|
|
157
|
+
}
|
|
158
|
+
export interface PgManyToManyRelationDetails {
|
|
159
|
+
leftTable: PgTableResource;
|
|
160
|
+
leftRelationName: string;
|
|
161
|
+
junctionTable: PgTableResource;
|
|
162
|
+
rightRelationName: string;
|
|
163
|
+
rightTable: PgTableResource;
|
|
164
|
+
allowsMultipleEdgesToNode?: boolean;
|
|
165
|
+
}
|
|
166
|
+
export interface MetaInflection {
|
|
167
|
+
tableType: (codec: PgCodec) => string;
|
|
168
|
+
_attributeName?: (input: {
|
|
169
|
+
attributeName: string;
|
|
170
|
+
codec: PgCodec;
|
|
171
|
+
}) => string;
|
|
172
|
+
camelCase?: (value: string) => string;
|
|
173
|
+
_manyToManyRelation?: (details: PgManyToManyRelationDetails) => string | null | undefined;
|
|
174
|
+
allRows?: (resource: PgTableResource) => string | null | undefined;
|
|
175
|
+
connectionType?: (tableType: string) => string | null | undefined;
|
|
176
|
+
edgeType?: (tableType: string) => string | null | undefined;
|
|
177
|
+
filterType?: (tableType: string) => string | null | undefined;
|
|
178
|
+
orderByType?: (tableType: string) => string | null | undefined;
|
|
179
|
+
conditionType?: (tableType: string) => string | null | undefined;
|
|
180
|
+
patchType?: (tableType: string) => string | null | undefined;
|
|
181
|
+
createInputType?: (resource: PgTableResource) => string | null | undefined;
|
|
182
|
+
createPayloadType?: (resource: PgTableResource) => string | null | undefined;
|
|
183
|
+
updatePayloadType?: (resource: PgTableResource) => string | null | undefined;
|
|
184
|
+
deletePayloadType?: (resource: PgTableResource) => string | null | undefined;
|
|
185
|
+
tableFieldName?: (resource: PgTableResource) => string | null | undefined;
|
|
186
|
+
createField?: (resource: PgTableResource) => string | null | undefined;
|
|
187
|
+
updateByKeys?: (resource: PgTableResource) => string | null | undefined;
|
|
188
|
+
deleteByKeys?: (resource: PgTableResource) => string | null | undefined;
|
|
189
|
+
}
|
|
190
|
+
export interface GqlTypeResolverBuild {
|
|
191
|
+
hasGraphQLTypeForPgCodec?: (codec: PgCodec, mode?: 'output' | 'input' | string) => boolean;
|
|
192
|
+
getGraphQLTypeNameByPgCodec?: (codec: PgCodec, mode?: 'output' | 'input' | string) => string | null | undefined;
|
|
193
|
+
}
|
|
194
|
+
export interface MetaBuild extends GqlTypeResolverBuild {
|
|
195
|
+
input: {
|
|
196
|
+
pgRegistry: {
|
|
197
|
+
pgResources: Record<string, PgTableResource>;
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
inflection: MetaInflection;
|
|
201
|
+
options?: {
|
|
202
|
+
pgSchemas?: string[];
|
|
203
|
+
[key: string]: unknown;
|
|
204
|
+
};
|
|
205
|
+
pgManyToManyRealtionshipsByResource?: Map<unknown, unknown>;
|
|
206
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostGraphile v5 Meta Schema Plugin
|
|
3
|
+
*
|
|
4
|
+
* Exposes a `_meta` GraphQL query that provides metadata about tables, fields,
|
|
5
|
+
* constraints, indexes, and relations for code generation tooling.
|
|
6
|
+
*/
|
|
7
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
8
|
+
import { cachedTablesMeta } from './meta-schema/cache';
|
|
9
|
+
import { MetaSchemaPlugin } from './meta-schema/plugin';
|
|
10
|
+
import { buildFieldMeta, pgTypeToGqlType } from './meta-schema/type-mappings';
|
|
11
|
+
export { MetaSchemaPlugin };
|
|
12
|
+
export declare const MetaSchemaPreset: GraphileConfig.Preset;
|
|
13
|
+
/** @internal Exported for testing only */
|
|
14
|
+
export { pgTypeToGqlType as _pgTypeToGqlType };
|
|
15
|
+
/** @internal Exported for testing only */
|
|
16
|
+
export { buildFieldMeta as _buildFieldMeta };
|
|
17
|
+
/** @internal Exported for testing only */
|
|
18
|
+
export { cachedTablesMeta as _cachedTablesMeta };
|
|
19
|
+
export default MetaSchemaPlugin;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PostGraphile v5 Meta Schema Plugin
|
|
3
|
+
*
|
|
4
|
+
* Exposes a `_meta` GraphQL query that provides metadata about tables, fields,
|
|
5
|
+
* constraints, indexes, and relations for code generation tooling.
|
|
6
|
+
*/
|
|
7
|
+
import { cachedTablesMeta } from './meta-schema/cache';
|
|
8
|
+
import { MetaSchemaPlugin } from './meta-schema/plugin';
|
|
9
|
+
import { buildFieldMeta, pgTypeToGqlType } from './meta-schema/type-mappings';
|
|
10
|
+
export { MetaSchemaPlugin };
|
|
11
|
+
export const MetaSchemaPreset = {
|
|
12
|
+
plugins: [MetaSchemaPlugin],
|
|
13
|
+
};
|
|
14
|
+
/** @internal Exported for testing only */
|
|
15
|
+
export { pgTypeToGqlType as _pgTypeToGqlType };
|
|
16
|
+
/** @internal Exported for testing only */
|
|
17
|
+
export { buildFieldMeta as _buildFieldMeta };
|
|
18
|
+
/** @internal Exported for testing only */
|
|
19
|
+
export { cachedTablesMeta as _cachedTablesMeta };
|
|
20
|
+
export default MetaSchemaPlugin;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal preset with all the PostgreSQL functionality but without Node/Relay features.
|
|
4
|
+
* This keeps `id` columns as `id` (no renaming to `rowId`).
|
|
5
|
+
*/
|
|
6
|
+
export declare const MinimalPreset: GraphileConfig.Preset;
|
|
7
|
+
export default MinimalPreset;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defaultPreset as graphileBuildPreset } from 'graphile-build';
|
|
2
|
+
import { defaultPreset as graphileBuildPgPreset } from 'graphile-build-pg';
|
|
3
|
+
/**
|
|
4
|
+
* Minimal PostGraphile v5 preset without Node/Relay features.
|
|
5
|
+
*
|
|
6
|
+
* This preset builds a clean GraphQL API from PostgreSQL without:
|
|
7
|
+
* - Global Node ID (Relay spec) - so `id` columns stay as `id`
|
|
8
|
+
* - Schema prefixing for naming conflicts
|
|
9
|
+
*
|
|
10
|
+
* We use the default presets from graphile-build and graphile-build-pg
|
|
11
|
+
* and disable all Node-related plugins.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* List of Node/Relay-related plugins to disable.
|
|
15
|
+
* These implement the Relay Global Object Identification spec which:
|
|
16
|
+
* - Adds a global `id` field to types
|
|
17
|
+
* - Renames actual `id` columns to `rowId`
|
|
18
|
+
* - Adds Node interface and nodeId lookups
|
|
19
|
+
*
|
|
20
|
+
* Since we use UUIDs, we don't need any of this.
|
|
21
|
+
*/
|
|
22
|
+
const NODE_PLUGINS_TO_DISABLE = [
|
|
23
|
+
// Core Node plugins from graphile-build
|
|
24
|
+
'NodePlugin',
|
|
25
|
+
'AddNodeInterfaceToSuitableTypesPlugin',
|
|
26
|
+
'NodeIdCodecBase64JSONPlugin',
|
|
27
|
+
'NodeIdCodecPipeStringPlugin',
|
|
28
|
+
'RegisterQueryNodePlugin',
|
|
29
|
+
'NodeAccessorPlugin',
|
|
30
|
+
// PG-specific Node plugins from graphile-build-pg
|
|
31
|
+
'PgNodeIdAttributesPlugin',
|
|
32
|
+
'PgTableNodePlugin',
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Minimal preset with all the PostgreSQL functionality but without Node/Relay features.
|
|
36
|
+
* This keeps `id` columns as `id` (no renaming to `rowId`).
|
|
37
|
+
*/
|
|
38
|
+
export const MinimalPreset = {
|
|
39
|
+
extends: [graphileBuildPreset, graphileBuildPgPreset],
|
|
40
|
+
disablePlugins: NODE_PLUGINS_TO_DISABLE,
|
|
41
|
+
};
|
|
42
|
+
export default MinimalPreset;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
2
|
+
/**
|
|
3
|
+
* Type mapping configuration for custom PostgreSQL types.
|
|
4
|
+
*/
|
|
5
|
+
export interface TypeMapping {
|
|
6
|
+
/** PostgreSQL type name */
|
|
7
|
+
name: string;
|
|
8
|
+
/** PostgreSQL schema/namespace name */
|
|
9
|
+
namespaceName: string;
|
|
10
|
+
/** GraphQL type to map to */
|
|
11
|
+
type: 'String';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Plugin that maps custom PostgreSQL types to GraphQL scalar types.
|
|
15
|
+
*
|
|
16
|
+
* This is useful for domain types or composite types that should be
|
|
17
|
+
* represented as simple scalars (String, JSON) in the GraphQL API.
|
|
18
|
+
*
|
|
19
|
+
* For example, if you have:
|
|
20
|
+
* CREATE DOMAIN email AS text;
|
|
21
|
+
* CREATE TYPE url AS (value text);
|
|
22
|
+
*
|
|
23
|
+
* This plugin will map them to GraphQL String type instead of creating
|
|
24
|
+
* complex object types.
|
|
25
|
+
*
|
|
26
|
+
* The plugin handles both:
|
|
27
|
+
* 1. Domain types (simple aliases) - maps directly to the target scalar
|
|
28
|
+
* 2. Composite types - extracts the first field's value when converting from PG
|
|
29
|
+
*/
|
|
30
|
+
export declare const PgTypeMappingsPlugin: GraphileConfig.Plugin;
|
|
31
|
+
/**
|
|
32
|
+
* Preset that includes the PG type mappings plugin.
|
|
33
|
+
*
|
|
34
|
+
* This preset maps common custom PostgreSQL types to GraphQL scalars:
|
|
35
|
+
* - email -> String
|
|
36
|
+
* - hostname -> String
|
|
37
|
+
* - url -> String
|
|
38
|
+
* - origin -> String
|
|
39
|
+
*/
|
|
40
|
+
export declare const PgTypeMappingsPreset: GraphileConfig.Preset;
|
|
41
|
+
export default PgTypeMappingsPlugin;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { GraphQLString } from 'graphql';
|
|
2
|
+
import sql from 'pg-sql2';
|
|
3
|
+
/**
|
|
4
|
+
* Default type mappings for common custom PostgreSQL types.
|
|
5
|
+
* These are typically domain types or composite types that should be
|
|
6
|
+
* represented as simple scalars in GraphQL.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_MAPPINGS = [
|
|
9
|
+
{ name: 'email', namespaceName: 'public', type: 'String' },
|
|
10
|
+
{ name: 'hostname', namespaceName: 'public', type: 'String' },
|
|
11
|
+
{ name: 'origin', namespaceName: 'public', type: 'String' },
|
|
12
|
+
{ name: 'url', namespaceName: 'public', type: 'String' },
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Plugin that maps custom PostgreSQL types to GraphQL scalar types.
|
|
16
|
+
*
|
|
17
|
+
* This is useful for domain types or composite types that should be
|
|
18
|
+
* represented as simple scalars (String, JSON) in the GraphQL API.
|
|
19
|
+
*
|
|
20
|
+
* For example, if you have:
|
|
21
|
+
* CREATE DOMAIN email AS text;
|
|
22
|
+
* CREATE TYPE url AS (value text);
|
|
23
|
+
*
|
|
24
|
+
* This plugin will map them to GraphQL String type instead of creating
|
|
25
|
+
* complex object types.
|
|
26
|
+
*
|
|
27
|
+
* The plugin handles both:
|
|
28
|
+
* 1. Domain types (simple aliases) - maps directly to the target scalar
|
|
29
|
+
* 2. Composite types - extracts the first field's value when converting from PG
|
|
30
|
+
*/
|
|
31
|
+
export const PgTypeMappingsPlugin = {
|
|
32
|
+
name: 'PgTypeMappingsPlugin',
|
|
33
|
+
version: '1.0.0',
|
|
34
|
+
gather: {
|
|
35
|
+
hooks: {
|
|
36
|
+
async pgCodecs_findPgCodec(info, event) {
|
|
37
|
+
if (event.pgCodec) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const { pgType: type, serviceName } = event;
|
|
41
|
+
// Find the namespace for this type
|
|
42
|
+
const namespace = await info.helpers.pgIntrospection.getNamespace(serviceName, type.typnamespace);
|
|
43
|
+
if (!namespace) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Check if this type matches any of our mappings
|
|
47
|
+
const mapping = DEFAULT_MAPPINGS.find(m => m.name === type.typname && m.namespaceName === namespace.nspname);
|
|
48
|
+
if (!mapping) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Create a codec for this type
|
|
52
|
+
// For composite types, the fromPg function extracts the first field's value
|
|
53
|
+
// For domain types, it just passes through the value
|
|
54
|
+
event.pgCodec = {
|
|
55
|
+
name: type.typname,
|
|
56
|
+
sqlType: sql.identifier(namespace.nspname, type.typname),
|
|
57
|
+
fromPg: (value) => {
|
|
58
|
+
if (value == null) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
// If it's already a scalar, return it
|
|
62
|
+
if (typeof value !== 'object' || Array.isArray(value)) {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
// For composite types, extract the first field's value
|
|
66
|
+
const obj = value;
|
|
67
|
+
const keys = Object.keys(obj);
|
|
68
|
+
if (keys.length > 0) {
|
|
69
|
+
return obj[keys[0]];
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
},
|
|
73
|
+
toPg: (value) => value,
|
|
74
|
+
attributes: undefined,
|
|
75
|
+
executor: null,
|
|
76
|
+
extensions: {
|
|
77
|
+
oid: type._id,
|
|
78
|
+
pg: {
|
|
79
|
+
serviceName,
|
|
80
|
+
schemaName: namespace.nspname,
|
|
81
|
+
name: type.typname,
|
|
82
|
+
},
|
|
83
|
+
tags: {
|
|
84
|
+
// Mark this as a custom mapped type
|
|
85
|
+
pgTypeMappings: mapping.type,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
schema: {
|
|
93
|
+
hooks: {
|
|
94
|
+
init(_, build) {
|
|
95
|
+
const { setGraphQLTypeForPgCodec } = build;
|
|
96
|
+
// Map our custom codecs to GraphQL types
|
|
97
|
+
for (const codec of Object.values(build.input.pgRegistry.pgCodecs)) {
|
|
98
|
+
const mappingType = codec.extensions?.tags?.pgTypeMappings;
|
|
99
|
+
if (mappingType) {
|
|
100
|
+
const gqlTypeName = GraphQLString.name;
|
|
101
|
+
setGraphQLTypeForPgCodec(codec, 'input', gqlTypeName);
|
|
102
|
+
setGraphQLTypeForPgCodec(codec, 'output', gqlTypeName);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return _;
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* Preset that includes the PG type mappings plugin.
|
|
112
|
+
*
|
|
113
|
+
* This preset maps common custom PostgreSQL types to GraphQL scalars:
|
|
114
|
+
* - email -> String
|
|
115
|
+
* - hostname -> String
|
|
116
|
+
* - url -> String
|
|
117
|
+
* - origin -> String
|
|
118
|
+
*/
|
|
119
|
+
export const PgTypeMappingsPreset = {
|
|
120
|
+
plugins: [PgTypeMappingsPlugin],
|
|
121
|
+
};
|
|
122
|
+
export default PgTypeMappingsPlugin;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration options for unique lookup behavior.
|
|
4
|
+
*/
|
|
5
|
+
export interface UniqueLookupOptions {
|
|
6
|
+
/**
|
|
7
|
+
* If true, disables ALL unique constraint lookups including primary keys.
|
|
8
|
+
* Users must use collection queries with filters instead.
|
|
9
|
+
* Default: false (primary key lookups are kept)
|
|
10
|
+
*/
|
|
11
|
+
disableAllUniqueLookups?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* PrimaryKeyOnlyPlugin - Disables non-primary-key unique constraint lookups for
|
|
15
|
+
* BOTH queries AND mutations.
|
|
16
|
+
*
|
|
17
|
+
* WHY THIS EXISTS:
|
|
18
|
+
* PostGraphile v5 creates fields for EVERY unique constraint on a table:
|
|
19
|
+
*
|
|
20
|
+
* QUERIES (PgRowByUniquePlugin):
|
|
21
|
+
* - `user(id)`, `userByEmail(email)`, `userByUsername(username)`
|
|
22
|
+
*
|
|
23
|
+
* MUTATIONS (PgMutationUpdateDeletePlugin):
|
|
24
|
+
* - `updateUser`, `updateUserByEmail`, `updateUserByUsername`
|
|
25
|
+
* - `deleteUser`, `deleteUserByEmail`, `deleteUserByUsername`
|
|
26
|
+
*
|
|
27
|
+
* For code generation (React Query, etc.), this creates unnecessary complexity.
|
|
28
|
+
* The same operations can be done using the primary key lookup or filters.
|
|
29
|
+
* Standardizing on primary keys reduces the API surface and generated code.
|
|
30
|
+
*
|
|
31
|
+
* SOURCE CODE REFERENCES:
|
|
32
|
+
*
|
|
33
|
+
* 1. Query fields (PgRowByUniquePlugin):
|
|
34
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRowByUniquePlugin.ts#L42-L257
|
|
35
|
+
*
|
|
36
|
+
* The behavior check for queries:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const fieldBehaviorScope = "query:resource:single";
|
|
39
|
+
* if (!build.behavior.pgResourceUniqueMatches([resource, unique], fieldBehaviorScope)) {
|
|
40
|
+
* return memo; // Skip this field
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* 2. Mutation fields (PgMutationUpdateDeletePlugin):
|
|
45
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgMutationUpdateDeletePlugin.ts
|
|
46
|
+
*
|
|
47
|
+
* The behavior check for mutations:
|
|
48
|
+
* ```typescript
|
|
49
|
+
* const constraintMode = `constraint:${mode}`; // "constraint:resource:update" or "constraint:resource:delete"
|
|
50
|
+
* ...resource.uniques.filter((unique) => {
|
|
51
|
+
* return build.behavior.pgResourceUniqueMatches([resource, unique], constraintMode);
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* OUR FIX:
|
|
56
|
+
* We use the behavior system's OVERRIDE phase (not inferred) to disable these behaviors.
|
|
57
|
+
* The override phase runs AFTER the behavior multiplication/preferences system processes
|
|
58
|
+
* behaviors, giving us the final say on what's enabled/disabled.
|
|
59
|
+
*
|
|
60
|
+
* Behaviors we control:
|
|
61
|
+
* - `-single` - Disables query lookups (userByEmail, etc.)
|
|
62
|
+
* - `-constraint:resource:update` - Disables updateByX mutations
|
|
63
|
+
* - `-constraint:resource:delete` - Disables deleteByX mutations
|
|
64
|
+
*
|
|
65
|
+
* CONFIGURATION OPTIONS:
|
|
66
|
+
*
|
|
67
|
+
* 1. `disableAllUniqueLookups: false` (default - PrimaryKeyOnlyPreset):
|
|
68
|
+
* - Primary key: query lookup + mutations enabled
|
|
69
|
+
* - Non-primary-key: everything disabled
|
|
70
|
+
* Result: `user(id)`, `updateUser`, `deleteUser` only
|
|
71
|
+
*
|
|
72
|
+
* 2. `disableAllUniqueLookups: true` (NoUniqueLookupPreset):
|
|
73
|
+
* - Primary key: query lookup DISABLED, mutations ENABLED
|
|
74
|
+
* - Non-primary-key: everything disabled
|
|
75
|
+
* Result: No query lookups (use filters), but `updateUser`, `deleteUser` still work
|
|
76
|
+
*/
|
|
77
|
+
/**
|
|
78
|
+
* Creates a plugin that controls unique constraint lookup behavior.
|
|
79
|
+
*
|
|
80
|
+
* @param options - Configuration options
|
|
81
|
+
* @param options.disableAllUniqueLookups - If true, disables ALL unique lookups including primary keys
|
|
82
|
+
*/
|
|
83
|
+
export declare function createUniqueLookupPlugin(options?: UniqueLookupOptions): GraphileConfig.Plugin;
|
|
84
|
+
export declare const PrimaryKeyOnlyPlugin: GraphileConfig.Plugin;
|
|
85
|
+
export declare const NoUniqueLookupPlugin: GraphileConfig.Plugin;
|
|
86
|
+
/**
|
|
87
|
+
* Preset that keeps only primary key lookups.
|
|
88
|
+
* Use this in your main preset's `extends` array.
|
|
89
|
+
*/
|
|
90
|
+
export declare const PrimaryKeyOnlyPreset: GraphileConfig.Preset;
|
|
91
|
+
/**
|
|
92
|
+
* Preset that disables ALL unique lookups (including primary keys).
|
|
93
|
+
* Users must use collection queries with filters instead.
|
|
94
|
+
* Use this in your main preset's `extends` array.
|
|
95
|
+
*/
|
|
96
|
+
export declare const NoUniqueLookupPreset: GraphileConfig.Preset;
|