graphile-settings 3.1.1 → 4.0.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/README.md +170 -85
- package/esm/index.d.ts +37 -0
- package/esm/index.js +54 -103
- package/esm/plugins/conflict-detector.d.ts +7 -0
- package/esm/plugins/conflict-detector.js +55 -0
- package/esm/plugins/custom-inflector.d.ts +9 -0
- package/esm/plugins/custom-inflector.js +382 -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 +19 -0
- package/esm/plugins/index.js +26 -0
- 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/presets/constructive-preset.d.ts +40 -0
- package/esm/presets/constructive-preset.js +137 -0
- package/esm/presets/index.d.ts +7 -0
- package/esm/presets/index.js +7 -0
- package/index.d.ts +37 -3
- package/index.js +56 -129
- package/package.json +16 -22
- package/plugins/conflict-detector.d.ts +7 -0
- package/plugins/conflict-detector.js +58 -0
- package/plugins/custom-inflector.d.ts +9 -0
- package/plugins/custom-inflector.js +385 -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 +19 -0
- package/plugins/index.js +56 -0
- 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/presets/constructive-preset.d.ts +40 -0
- package/presets/constructive-preset.js +140 -0
- package/presets/index.d.ts +7 -0
- package/presets/index.js +11 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InflectorLoggerPreset = exports.InflectorLoggerPlugin = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* InflectorLoggerPlugin - Logs inflector calls during schema build for debugging.
|
|
6
|
+
*
|
|
7
|
+
* This plugin wraps key inflectors to log what fields are being generated and why.
|
|
8
|
+
* It passes through to the default behavior but logs the inputs and outputs.
|
|
9
|
+
*
|
|
10
|
+
* WHEN DO PLUGINS RUN?
|
|
11
|
+
* Plugins only run at BUILD TIME, not on every request. The schema is built once
|
|
12
|
+
* and cached. This means logging only happens during schema generation, not during
|
|
13
|
+
* query execution.
|
|
14
|
+
*
|
|
15
|
+
* SOURCE CODE REFERENCES:
|
|
16
|
+
*
|
|
17
|
+
* 1. PgRowByUniquePlugin - Creates root Query fields for unique constraints
|
|
18
|
+
* (e.g., `userById`, `userByEmail`, `postBySlug`)
|
|
19
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRowByUniquePlugin.ts#L42-L257
|
|
20
|
+
*
|
|
21
|
+
* 2. PgRelationsPlugin - Creates relationship fields on types for foreign keys
|
|
22
|
+
* - Forward relations: `post.author` (from posts.author_id -> users.id)
|
|
23
|
+
* - Backward relations: `user.posts` (from users.id <- posts.author_id)
|
|
24
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L167-L638
|
|
25
|
+
*
|
|
26
|
+
* 3. PgAttributesPlugin - Creates fields for table columns
|
|
27
|
+
* Also contains the `_attributeName` inflector that renames `id` to `rowId`
|
|
28
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgAttributesPlugin.ts#L289-L298
|
|
29
|
+
*
|
|
30
|
+
* 4. PgTablesPlugin - Creates GraphQL types for tables
|
|
31
|
+
* Contains the `_schemaPrefix` inflector that adds schema prefixes
|
|
32
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgTablesPlugin.ts#L261-L271
|
|
33
|
+
*
|
|
34
|
+
* USAGE:
|
|
35
|
+
* Add InflectorLoggerPlugin to your preset's plugins array.
|
|
36
|
+
* Set INFLECTOR_LOG=1 environment variable to enable logging.
|
|
37
|
+
*/
|
|
38
|
+
const LOG_ENABLED = process.env.INFLECTOR_LOG === '1';
|
|
39
|
+
function log(category, message, details) {
|
|
40
|
+
if (!LOG_ENABLED)
|
|
41
|
+
return;
|
|
42
|
+
const detailsStr = details ? ` ${JSON.stringify(details)}` : '';
|
|
43
|
+
console.log(`[Inflector:${category}]${detailsStr} => ${message}`);
|
|
44
|
+
}
|
|
45
|
+
exports.InflectorLoggerPlugin = {
|
|
46
|
+
name: 'InflectorLoggerPlugin',
|
|
47
|
+
version: '1.0.0',
|
|
48
|
+
description: 'Logs inflector calls during schema build for debugging',
|
|
49
|
+
inflection: {
|
|
50
|
+
replace: {
|
|
51
|
+
/**
|
|
52
|
+
* Logs when root Query fields are created for unique constraints.
|
|
53
|
+
* Source: PgRowByUniquePlugin
|
|
54
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRowByUniquePlugin.ts#L50-L63
|
|
55
|
+
*/
|
|
56
|
+
rowByUnique(previous, _options, details) {
|
|
57
|
+
const result = previous(details);
|
|
58
|
+
const { unique, resource } = details;
|
|
59
|
+
log('rowByUnique', result, {
|
|
60
|
+
resource: resource.name,
|
|
61
|
+
uniqueAttributes: unique.attributes,
|
|
62
|
+
isPrimary: unique.isPrimary,
|
|
63
|
+
});
|
|
64
|
+
return result;
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* Logs when forward relation fields are created (e.g., post.author).
|
|
68
|
+
* Source: PgRelationsPlugin
|
|
69
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L228-L230
|
|
70
|
+
*/
|
|
71
|
+
singleRelation(previous, _options, details) {
|
|
72
|
+
const result = previous(details);
|
|
73
|
+
const { codec, relationName, registry } = details;
|
|
74
|
+
const relation = registry.pgRelations[codec.name]?.[relationName];
|
|
75
|
+
log('singleRelation', result, {
|
|
76
|
+
fromType: codec.name,
|
|
77
|
+
relationName,
|
|
78
|
+
toType: relation?.remoteResource?.name,
|
|
79
|
+
localAttributes: relation?.localAttributes,
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* Logs when backward single relation fields are created.
|
|
85
|
+
* Source: PgRelationsPlugin
|
|
86
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L250-L252
|
|
87
|
+
*/
|
|
88
|
+
singleRelationBackwards(previous, _options, details) {
|
|
89
|
+
const result = previous(details);
|
|
90
|
+
const { codec, relationName, registry } = details;
|
|
91
|
+
const relation = registry.pgRelations[codec.name]?.[relationName];
|
|
92
|
+
log('singleRelationBackwards', result, {
|
|
93
|
+
fromType: codec.name,
|
|
94
|
+
relationName,
|
|
95
|
+
toType: relation?.remoteResource?.name,
|
|
96
|
+
remoteAttributes: relation?.remoteAttributes,
|
|
97
|
+
});
|
|
98
|
+
return result;
|
|
99
|
+
},
|
|
100
|
+
/**
|
|
101
|
+
* Logs when many-relation fields are created (e.g., user.posts).
|
|
102
|
+
* Source: PgRelationsPlugin
|
|
103
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L268-L270
|
|
104
|
+
*/
|
|
105
|
+
_manyRelation(previous, _options, details) {
|
|
106
|
+
const result = previous(details);
|
|
107
|
+
const { codec, relationName, registry } = details;
|
|
108
|
+
const relation = registry.pgRelations[codec.name]?.[relationName];
|
|
109
|
+
log('manyRelation', result, {
|
|
110
|
+
fromType: codec.name,
|
|
111
|
+
relationName,
|
|
112
|
+
toType: relation?.remoteResource?.name,
|
|
113
|
+
remoteAttributes: relation?.remoteAttributes,
|
|
114
|
+
});
|
|
115
|
+
return result;
|
|
116
|
+
},
|
|
117
|
+
/**
|
|
118
|
+
* Logs when connection fields are created for many relations.
|
|
119
|
+
* Source: PgRelationsPlugin
|
|
120
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L271-L279
|
|
121
|
+
*/
|
|
122
|
+
manyRelationConnection(previous, _options, details) {
|
|
123
|
+
const result = previous(details);
|
|
124
|
+
const { codec, relationName } = details;
|
|
125
|
+
log('manyRelationConnection', result, {
|
|
126
|
+
fromType: codec.name,
|
|
127
|
+
relationName,
|
|
128
|
+
});
|
|
129
|
+
return result;
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* Logs when list fields are created for many relations.
|
|
133
|
+
* Source: PgRelationsPlugin
|
|
134
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgRelationsPlugin.ts#L280-L288
|
|
135
|
+
*/
|
|
136
|
+
manyRelationList(previous, _options, details) {
|
|
137
|
+
const result = previous(details);
|
|
138
|
+
const { codec, relationName } = details;
|
|
139
|
+
log('manyRelationList', result, {
|
|
140
|
+
fromType: codec.name,
|
|
141
|
+
relationName,
|
|
142
|
+
});
|
|
143
|
+
return result;
|
|
144
|
+
},
|
|
145
|
+
/**
|
|
146
|
+
* Logs when root connection fields are created (e.g., Query.users).
|
|
147
|
+
* Source: PgAllRowsPlugin
|
|
148
|
+
*/
|
|
149
|
+
allRowsConnection(previous, _options, resource) {
|
|
150
|
+
const result = previous(resource);
|
|
151
|
+
log('allRowsConnection', result, {
|
|
152
|
+
resource: resource.name,
|
|
153
|
+
});
|
|
154
|
+
return result;
|
|
155
|
+
},
|
|
156
|
+
/**
|
|
157
|
+
* Logs when update mutation fields are created.
|
|
158
|
+
* Source: PgMutationUpdateDeletePlugin
|
|
159
|
+
*/
|
|
160
|
+
updateByKeysField(previous, _options, details) {
|
|
161
|
+
const result = previous(details);
|
|
162
|
+
const { resource, unique } = details;
|
|
163
|
+
log('updateByKeysField', result, {
|
|
164
|
+
resource: resource.name,
|
|
165
|
+
uniqueAttributes: unique.attributes,
|
|
166
|
+
isPrimary: unique.isPrimary,
|
|
167
|
+
});
|
|
168
|
+
return result;
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* Logs when delete mutation fields are created.
|
|
172
|
+
* Source: PgMutationUpdateDeletePlugin
|
|
173
|
+
*/
|
|
174
|
+
deleteByKeysField(previous, _options, details) {
|
|
175
|
+
const result = previous(details);
|
|
176
|
+
const { resource, unique } = details;
|
|
177
|
+
log('deleteByKeysField', result, {
|
|
178
|
+
resource: resource.name,
|
|
179
|
+
uniqueAttributes: unique.attributes,
|
|
180
|
+
isPrimary: unique.isPrimary,
|
|
181
|
+
});
|
|
182
|
+
return result;
|
|
183
|
+
},
|
|
184
|
+
/**
|
|
185
|
+
* Logs when attribute (column) fields are created.
|
|
186
|
+
* Source: PgAttributesPlugin
|
|
187
|
+
* https://github.com/graphile/crystal/blob/924b2515c6bd30e5905ac1419a25244b40c8bb4d/graphile-build/graphile-build-pg/src/plugins/PgAttributesPlugin.ts#L289-L298
|
|
188
|
+
*/
|
|
189
|
+
attribute(previous, _options, details) {
|
|
190
|
+
const result = previous(details);
|
|
191
|
+
const { attributeName, codec } = details;
|
|
192
|
+
log('attribute', result, {
|
|
193
|
+
codec: codec.name,
|
|
194
|
+
attributeName,
|
|
195
|
+
});
|
|
196
|
+
return result;
|
|
197
|
+
},
|
|
198
|
+
/**
|
|
199
|
+
* Logs when table types are created.
|
|
200
|
+
* Source: PgTablesPlugin
|
|
201
|
+
*/
|
|
202
|
+
tableType(previous, _options, codec) {
|
|
203
|
+
const result = previous(codec);
|
|
204
|
+
log('tableType', result, {
|
|
205
|
+
codec: codec.name,
|
|
206
|
+
});
|
|
207
|
+
return result;
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Preset that includes the inflector logger plugin.
|
|
214
|
+
* Use this in your main preset's `extends` array.
|
|
215
|
+
*/
|
|
216
|
+
exports.InflectorLoggerPreset = {
|
|
217
|
+
plugins: [exports.InflectorLoggerPlugin],
|
|
218
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { GraphileConfig } from 'graphile-config';
|
|
2
|
+
/**
|
|
3
|
+
* Many-to-Many Preset with OPT-IN behavior (disabled by default).
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS:
|
|
6
|
+
* The default @graphile-contrib/pg-many-to-many plugin adds many-to-many connection
|
|
7
|
+
* fields to EVERY junction table automatically. This can bloat the API with fields
|
|
8
|
+
* that may never be used.
|
|
9
|
+
*
|
|
10
|
+
* OUR FIX:
|
|
11
|
+
* We override the default behavior to be OPT-IN instead of OPT-OUT:
|
|
12
|
+
* - By default, NO many-to-many fields are generated
|
|
13
|
+
* - To enable for a specific junction table, use: @behavior +manyToMany
|
|
14
|
+
*
|
|
15
|
+
* USAGE:
|
|
16
|
+
* To enable many-to-many for a specific junction table, add a smart comment:
|
|
17
|
+
*
|
|
18
|
+
* ```sql
|
|
19
|
+
* -- Enable many-to-many through this junction table
|
|
20
|
+
* COMMENT ON TABLE post_tags IS E'@behavior +manyToMany';
|
|
21
|
+
*
|
|
22
|
+
* -- Or enable on a specific constraint
|
|
23
|
+
* COMMENT ON CONSTRAINT post_tags_tag_id_fkey ON post_tags IS E'@behavior +manyToMany';
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* SOURCE CODE REFERENCE:
|
|
27
|
+
* The many-to-many plugin uses the behavior system to control field generation:
|
|
28
|
+
* https://github.com/graphile-contrib/pg-many-to-many/blob/v2.0.0-rc.1/src/PgManyToManyRelationPlugin.ts#L478-L503
|
|
29
|
+
*
|
|
30
|
+
* The plugin defines these behaviors:
|
|
31
|
+
* - `manyToMany` - Controls whether many-to-many fields are generated
|
|
32
|
+
* - `connection` - Controls whether connection fields are generated
|
|
33
|
+
* - `list` - Controls whether list fields are generated
|
|
34
|
+
*
|
|
35
|
+
* By default, the plugin's entityBehavior for pgManyToMany includes:
|
|
36
|
+
* `["manyToMany", "connection", "list", behavior]`
|
|
37
|
+
*
|
|
38
|
+
* We override this to be `-manyToMany` by default, requiring explicit opt-in.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Plugin that makes many-to-many fields opt-in by default.
|
|
42
|
+
*
|
|
43
|
+
* This overrides the default behavior from @graphile-contrib/pg-many-to-many
|
|
44
|
+
* to require explicit `@behavior +manyToMany` smart tags.
|
|
45
|
+
*/
|
|
46
|
+
export declare const ManyToManyOptInPlugin: GraphileConfig.Plugin;
|
|
47
|
+
/**
|
|
48
|
+
* Preset that includes the many-to-many plugin with opt-in behavior.
|
|
49
|
+
*
|
|
50
|
+
* Use this in your main preset's `extends` array:
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const preset: GraphileConfig.Preset = {
|
|
53
|
+
* extends: [
|
|
54
|
+
* MinimalPreset,
|
|
55
|
+
* ManyToManyOptInPreset,
|
|
56
|
+
* // ... other presets
|
|
57
|
+
* ],
|
|
58
|
+
* };
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare const ManyToManyOptInPreset: GraphileConfig.Preset;
|
|
62
|
+
export default ManyToManyOptInPreset;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ManyToManyOptInPreset = exports.ManyToManyOptInPlugin = void 0;
|
|
4
|
+
const pg_many_to_many_1 = require("@graphile-contrib/pg-many-to-many");
|
|
5
|
+
/**
|
|
6
|
+
* Many-to-Many Preset with OPT-IN behavior (disabled by default).
|
|
7
|
+
*
|
|
8
|
+
* WHY THIS EXISTS:
|
|
9
|
+
* The default @graphile-contrib/pg-many-to-many plugin adds many-to-many connection
|
|
10
|
+
* fields to EVERY junction table automatically. This can bloat the API with fields
|
|
11
|
+
* that may never be used.
|
|
12
|
+
*
|
|
13
|
+
* OUR FIX:
|
|
14
|
+
* We override the default behavior to be OPT-IN instead of OPT-OUT:
|
|
15
|
+
* - By default, NO many-to-many fields are generated
|
|
16
|
+
* - To enable for a specific junction table, use: @behavior +manyToMany
|
|
17
|
+
*
|
|
18
|
+
* USAGE:
|
|
19
|
+
* To enable many-to-many for a specific junction table, add a smart comment:
|
|
20
|
+
*
|
|
21
|
+
* ```sql
|
|
22
|
+
* -- Enable many-to-many through this junction table
|
|
23
|
+
* COMMENT ON TABLE post_tags IS E'@behavior +manyToMany';
|
|
24
|
+
*
|
|
25
|
+
* -- Or enable on a specific constraint
|
|
26
|
+
* COMMENT ON CONSTRAINT post_tags_tag_id_fkey ON post_tags IS E'@behavior +manyToMany';
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* SOURCE CODE REFERENCE:
|
|
30
|
+
* The many-to-many plugin uses the behavior system to control field generation:
|
|
31
|
+
* https://github.com/graphile-contrib/pg-many-to-many/blob/v2.0.0-rc.1/src/PgManyToManyRelationPlugin.ts#L478-L503
|
|
32
|
+
*
|
|
33
|
+
* The plugin defines these behaviors:
|
|
34
|
+
* - `manyToMany` - Controls whether many-to-many fields are generated
|
|
35
|
+
* - `connection` - Controls whether connection fields are generated
|
|
36
|
+
* - `list` - Controls whether list fields are generated
|
|
37
|
+
*
|
|
38
|
+
* By default, the plugin's entityBehavior for pgManyToMany includes:
|
|
39
|
+
* `["manyToMany", "connection", "list", behavior]`
|
|
40
|
+
*
|
|
41
|
+
* We override this to be `-manyToMany` by default, requiring explicit opt-in.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Plugin that makes many-to-many fields opt-in by default.
|
|
45
|
+
*
|
|
46
|
+
* This overrides the default behavior from @graphile-contrib/pg-many-to-many
|
|
47
|
+
* to require explicit `@behavior +manyToMany` smart tags.
|
|
48
|
+
*/
|
|
49
|
+
exports.ManyToManyOptInPlugin = {
|
|
50
|
+
name: 'ManyToManyOptInPlugin',
|
|
51
|
+
version: '1.0.0',
|
|
52
|
+
description: 'Makes many-to-many fields opt-in by default (disabled unless explicitly enabled)',
|
|
53
|
+
schema: {
|
|
54
|
+
entityBehavior: {
|
|
55
|
+
pgManyToMany: {
|
|
56
|
+
// Override the default behavior to be opt-out (disabled by default)
|
|
57
|
+
// The 'inferred' phase runs before 'override', so we use 'inferred'
|
|
58
|
+
// to set the default before any smart tags are processed.
|
|
59
|
+
inferred: {
|
|
60
|
+
provides: ['manyToManyOptIn'],
|
|
61
|
+
before: ['default'],
|
|
62
|
+
callback(behavior) {
|
|
63
|
+
// Default to disabled - require explicit @behavior +manyToMany
|
|
64
|
+
return ['-manyToMany', behavior];
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Preset that includes the many-to-many plugin with opt-in behavior.
|
|
73
|
+
*
|
|
74
|
+
* Use this in your main preset's `extends` array:
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const preset: GraphileConfig.Preset = {
|
|
77
|
+
* extends: [
|
|
78
|
+
* MinimalPreset,
|
|
79
|
+
* ManyToManyOptInPreset,
|
|
80
|
+
* // ... other presets
|
|
81
|
+
* ],
|
|
82
|
+
* };
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
exports.ManyToManyOptInPreset = {
|
|
86
|
+
extends: [pg_many_to_many_1.PgManyToManyPreset],
|
|
87
|
+
plugins: [exports.ManyToManyOptInPlugin],
|
|
88
|
+
};
|
|
89
|
+
exports.default = exports.ManyToManyOptInPreset;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cachedTablesMeta = void 0;
|
|
4
|
+
exports.getCachedTablesMeta = getCachedTablesMeta;
|
|
5
|
+
exports.setCachedTablesMeta = setCachedTablesMeta;
|
|
6
|
+
exports.cachedTablesMeta = [];
|
|
7
|
+
function getCachedTablesMeta() {
|
|
8
|
+
return exports.cachedTablesMeta;
|
|
9
|
+
}
|
|
10
|
+
function setCachedTablesMeta(tablesMeta) {
|
|
11
|
+
exports.cachedTablesMeta = tablesMeta;
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type BuildContext } from './table-meta-context';
|
|
2
|
+
import type { ForeignKeyConstraintMeta, PgAttribute, PgCodec, PgRelation, PgUnique, PrimaryKeyConstraintMeta, UniqueConstraintMeta } from './types';
|
|
3
|
+
export declare function buildForeignKeyConstraint(constraintName: string, localCodec: PgCodec, localAttributes: Record<string, PgAttribute>, localAttributeNames: string[], remoteCodec: PgCodec | undefined, remoteAttributes: Record<string, PgAttribute>, remoteAttributeNames: string[], context: BuildContext): ForeignKeyConstraintMeta;
|
|
4
|
+
export declare function buildIndexes(codec: PgCodec, attributes: Record<string, PgAttribute>, uniques: PgUnique[], context: BuildContext): {
|
|
5
|
+
name: string;
|
|
6
|
+
isUnique: boolean;
|
|
7
|
+
isPrimary: boolean;
|
|
8
|
+
columns: string[];
|
|
9
|
+
fields: import("./types").FieldMeta[];
|
|
10
|
+
}[];
|
|
11
|
+
export declare function buildPrimaryKey(codec: PgCodec, attributes: Record<string, PgAttribute>, uniques: PgUnique[], context: BuildContext): PrimaryKeyConstraintMeta | null;
|
|
12
|
+
export declare function buildUniqueConstraints(codec: PgCodec, attributes: Record<string, PgAttribute>, uniques: PgUnique[], context: BuildContext): UniqueConstraintMeta[];
|
|
13
|
+
export declare function buildForeignKeyConstraints(codec: PgCodec, attributes: Record<string, PgAttribute>, relations: Record<string, PgRelation>, context: BuildContext): ForeignKeyConstraintMeta[];
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildForeignKeyConstraint = buildForeignKeyConstraint;
|
|
4
|
+
exports.buildIndexes = buildIndexes;
|
|
5
|
+
exports.buildPrimaryKey = buildPrimaryKey;
|
|
6
|
+
exports.buildUniqueConstraints = buildUniqueConstraints;
|
|
7
|
+
exports.buildForeignKeyConstraints = buildForeignKeyConstraints;
|
|
8
|
+
const type_mappings_1 = require("./type-mappings");
|
|
9
|
+
const table_meta_context_1 = require("./table-meta-context");
|
|
10
|
+
function buildForeignKeyConstraint(constraintName, localCodec, localAttributes, localAttributeNames, remoteCodec, remoteAttributes, remoteAttributeNames, context) {
|
|
11
|
+
const referencedTable = remoteCodec?.name || 'unknown';
|
|
12
|
+
const referencedFields = remoteAttributeNames.map((attrName) => remoteCodec ? context.inflectAttr(attrName, remoteCodec) : attrName);
|
|
13
|
+
return {
|
|
14
|
+
name: constraintName,
|
|
15
|
+
fields: (0, table_meta_context_1.buildFieldList)(localAttributeNames, localCodec, localAttributes, context),
|
|
16
|
+
referencedTable,
|
|
17
|
+
referencedFields,
|
|
18
|
+
refFields: remoteAttributeNames.map((attrName) => (0, type_mappings_1.buildFieldMeta)(remoteCodec ? context.inflectAttr(attrName, remoteCodec) : attrName, remoteAttributes[attrName], context.build)),
|
|
19
|
+
refTable: { name: referencedTable },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function buildIndexes(codec, attributes, uniques, context) {
|
|
23
|
+
return uniques.map((unique) => ({
|
|
24
|
+
name: unique.tags?.name || `${codec.name}_${unique.attributes.join('_')}_idx`,
|
|
25
|
+
isUnique: true,
|
|
26
|
+
isPrimary: !!unique.isPrimary,
|
|
27
|
+
columns: unique.attributes.map((attrName) => context.inflectAttr(attrName, codec)),
|
|
28
|
+
fields: (0, table_meta_context_1.buildFieldList)(unique.attributes, codec, attributes, context),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
function buildPrimaryKey(codec, attributes, uniques, context) {
|
|
32
|
+
const primaryUnique = uniques.find((unique) => unique.isPrimary);
|
|
33
|
+
if (!primaryUnique)
|
|
34
|
+
return null;
|
|
35
|
+
return {
|
|
36
|
+
name: primaryUnique.tags?.name || `${codec.name}_pkey`,
|
|
37
|
+
fields: (0, table_meta_context_1.buildFieldList)(primaryUnique.attributes, codec, attributes, context),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function buildUniqueConstraints(codec, attributes, uniques, context) {
|
|
41
|
+
return uniques
|
|
42
|
+
.filter((unique) => !unique.isPrimary)
|
|
43
|
+
.map((unique) => ({
|
|
44
|
+
name: unique.tags?.name || `${codec.name}_${unique.attributes.join('_')}_key`,
|
|
45
|
+
fields: (0, table_meta_context_1.buildFieldList)(unique.attributes, codec, attributes, context),
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
function buildForeignKeyConstraints(codec, attributes, relations, context) {
|
|
49
|
+
const constraints = [];
|
|
50
|
+
for (const [relationName, relation] of Object.entries(relations)) {
|
|
51
|
+
if (relation.isReferencee !== false)
|
|
52
|
+
continue;
|
|
53
|
+
const remoteCodec = relation.remoteResource?.codec;
|
|
54
|
+
const remoteAttributes = remoteCodec?.attributes || {};
|
|
55
|
+
constraints.push(buildForeignKeyConstraint(relationName, codec, attributes, relation.localAttributes || [], remoteCodec, remoteAttributes, relation.remoteAttributes || [], context));
|
|
56
|
+
}
|
|
57
|
+
return constraints;
|
|
58
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extendQueryWithMetaField = extendQueryWithMetaField;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
function nn(type) {
|
|
6
|
+
return new graphql_1.GraphQLNonNull(type);
|
|
7
|
+
}
|
|
8
|
+
function nnList(type) {
|
|
9
|
+
return nn(new graphql_1.GraphQLList(nn(type)));
|
|
10
|
+
}
|
|
11
|
+
function createMetaSchemaType() {
|
|
12
|
+
const MetaTypeType = new graphql_1.GraphQLObjectType({
|
|
13
|
+
name: 'MetaType',
|
|
14
|
+
description: 'Information about a PostgreSQL type',
|
|
15
|
+
fields: () => ({
|
|
16
|
+
pgType: { type: nn(graphql_1.GraphQLString) },
|
|
17
|
+
gqlType: { type: nn(graphql_1.GraphQLString) },
|
|
18
|
+
isArray: { type: nn(graphql_1.GraphQLBoolean) },
|
|
19
|
+
isNotNull: { type: graphql_1.GraphQLBoolean },
|
|
20
|
+
hasDefault: { type: graphql_1.GraphQLBoolean },
|
|
21
|
+
}),
|
|
22
|
+
});
|
|
23
|
+
const MetaFieldType = new graphql_1.GraphQLObjectType({
|
|
24
|
+
name: 'MetaField',
|
|
25
|
+
description: 'Information about a table field/column',
|
|
26
|
+
fields: () => ({
|
|
27
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
28
|
+
type: { type: nn(MetaTypeType) },
|
|
29
|
+
isNotNull: { type: nn(graphql_1.GraphQLBoolean) },
|
|
30
|
+
hasDefault: { type: nn(graphql_1.GraphQLBoolean) },
|
|
31
|
+
}),
|
|
32
|
+
});
|
|
33
|
+
const MetaIndexType = new graphql_1.GraphQLObjectType({
|
|
34
|
+
name: 'MetaIndex',
|
|
35
|
+
description: 'Information about a database index',
|
|
36
|
+
fields: () => ({
|
|
37
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
38
|
+
isUnique: { type: nn(graphql_1.GraphQLBoolean) },
|
|
39
|
+
isPrimary: { type: nn(graphql_1.GraphQLBoolean) },
|
|
40
|
+
columns: { type: nnList(graphql_1.GraphQLString) },
|
|
41
|
+
fields: { type: new graphql_1.GraphQLList(nn(MetaFieldType)) },
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
const MetaPrimaryKeyConstraintType = new graphql_1.GraphQLObjectType({
|
|
45
|
+
name: 'MetaPrimaryKeyConstraint',
|
|
46
|
+
description: 'Information about a primary key constraint',
|
|
47
|
+
fields: () => ({
|
|
48
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
49
|
+
fields: { type: nnList(MetaFieldType) },
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
const MetaUniqueConstraintType = new graphql_1.GraphQLObjectType({
|
|
53
|
+
name: 'MetaUniqueConstraint',
|
|
54
|
+
description: 'Information about a unique constraint',
|
|
55
|
+
fields: () => ({
|
|
56
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
57
|
+
fields: { type: nnList(MetaFieldType) },
|
|
58
|
+
}),
|
|
59
|
+
});
|
|
60
|
+
const MetaRefTableType = new graphql_1.GraphQLObjectType({
|
|
61
|
+
name: 'MetaRefTable',
|
|
62
|
+
description: 'Reference to a related table',
|
|
63
|
+
fields: () => ({
|
|
64
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
65
|
+
}),
|
|
66
|
+
});
|
|
67
|
+
const MetaForeignKeyConstraintType = new graphql_1.GraphQLObjectType({
|
|
68
|
+
name: 'MetaForeignKeyConstraint',
|
|
69
|
+
description: 'Information about a foreign key constraint',
|
|
70
|
+
fields: () => ({
|
|
71
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
72
|
+
fields: { type: nnList(MetaFieldType) },
|
|
73
|
+
referencedTable: { type: nn(graphql_1.GraphQLString) },
|
|
74
|
+
referencedFields: { type: nnList(graphql_1.GraphQLString) },
|
|
75
|
+
refFields: { type: new graphql_1.GraphQLList(nn(MetaFieldType)) },
|
|
76
|
+
refTable: { type: MetaRefTableType },
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
const MetaConstraintsType = new graphql_1.GraphQLObjectType({
|
|
80
|
+
name: 'MetaConstraints',
|
|
81
|
+
description: 'Table constraints',
|
|
82
|
+
fields: () => ({
|
|
83
|
+
primaryKey: { type: MetaPrimaryKeyConstraintType },
|
|
84
|
+
unique: { type: nnList(MetaUniqueConstraintType) },
|
|
85
|
+
foreignKey: { type: nnList(MetaForeignKeyConstraintType) },
|
|
86
|
+
}),
|
|
87
|
+
});
|
|
88
|
+
const MetaInflectionType = new graphql_1.GraphQLObjectType({
|
|
89
|
+
name: 'MetaInflection',
|
|
90
|
+
description: 'Table inflection names',
|
|
91
|
+
fields: () => ({
|
|
92
|
+
tableType: { type: nn(graphql_1.GraphQLString) },
|
|
93
|
+
allRows: { type: nn(graphql_1.GraphQLString) },
|
|
94
|
+
connection: { type: nn(graphql_1.GraphQLString) },
|
|
95
|
+
edge: { type: nn(graphql_1.GraphQLString) },
|
|
96
|
+
filterType: { type: graphql_1.GraphQLString },
|
|
97
|
+
orderByType: { type: nn(graphql_1.GraphQLString) },
|
|
98
|
+
conditionType: { type: nn(graphql_1.GraphQLString) },
|
|
99
|
+
patchType: { type: graphql_1.GraphQLString },
|
|
100
|
+
createInputType: { type: nn(graphql_1.GraphQLString) },
|
|
101
|
+
createPayloadType: { type: nn(graphql_1.GraphQLString) },
|
|
102
|
+
updatePayloadType: { type: graphql_1.GraphQLString },
|
|
103
|
+
deletePayloadType: { type: nn(graphql_1.GraphQLString) },
|
|
104
|
+
}),
|
|
105
|
+
});
|
|
106
|
+
const MetaQueryType = new graphql_1.GraphQLObjectType({
|
|
107
|
+
name: 'MetaQuery',
|
|
108
|
+
description: 'Table query/mutation names',
|
|
109
|
+
fields: () => ({
|
|
110
|
+
all: { type: nn(graphql_1.GraphQLString) },
|
|
111
|
+
one: { type: graphql_1.GraphQLString },
|
|
112
|
+
create: { type: graphql_1.GraphQLString },
|
|
113
|
+
update: { type: graphql_1.GraphQLString },
|
|
114
|
+
delete: { type: graphql_1.GraphQLString },
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
const MetaBelongsToRelationType = new graphql_1.GraphQLObjectType({
|
|
118
|
+
name: 'MetaBelongsToRelation',
|
|
119
|
+
description: 'A belongs-to (forward FK) relation',
|
|
120
|
+
fields: () => ({
|
|
121
|
+
fieldName: { type: graphql_1.GraphQLString },
|
|
122
|
+
isUnique: { type: nn(graphql_1.GraphQLBoolean) },
|
|
123
|
+
type: { type: graphql_1.GraphQLString },
|
|
124
|
+
keys: { type: nnList(MetaFieldType) },
|
|
125
|
+
references: { type: nn(MetaRefTableType) },
|
|
126
|
+
}),
|
|
127
|
+
});
|
|
128
|
+
const MetaHasRelationType = new graphql_1.GraphQLObjectType({
|
|
129
|
+
name: 'MetaHasRelation',
|
|
130
|
+
description: 'A has-one or has-many (reverse FK) relation',
|
|
131
|
+
fields: () => ({
|
|
132
|
+
fieldName: { type: graphql_1.GraphQLString },
|
|
133
|
+
isUnique: { type: nn(graphql_1.GraphQLBoolean) },
|
|
134
|
+
type: { type: graphql_1.GraphQLString },
|
|
135
|
+
keys: { type: nnList(MetaFieldType) },
|
|
136
|
+
referencedBy: { type: nn(MetaRefTableType) },
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
139
|
+
const MetaManyToManyRelationType = new graphql_1.GraphQLObjectType({
|
|
140
|
+
name: 'MetaManyToManyRelation',
|
|
141
|
+
description: 'A many-to-many relation via junction table',
|
|
142
|
+
fields: () => ({
|
|
143
|
+
fieldName: { type: graphql_1.GraphQLString },
|
|
144
|
+
type: { type: graphql_1.GraphQLString },
|
|
145
|
+
junctionTable: { type: nn(MetaRefTableType) },
|
|
146
|
+
junctionLeftConstraint: { type: nn(MetaForeignKeyConstraintType) },
|
|
147
|
+
junctionLeftKeyAttributes: { type: nnList(MetaFieldType) },
|
|
148
|
+
junctionRightConstraint: { type: nn(MetaForeignKeyConstraintType) },
|
|
149
|
+
junctionRightKeyAttributes: { type: nnList(MetaFieldType) },
|
|
150
|
+
leftKeyAttributes: { type: nnList(MetaFieldType) },
|
|
151
|
+
rightKeyAttributes: { type: nnList(MetaFieldType) },
|
|
152
|
+
rightTable: { type: nn(MetaRefTableType) },
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
155
|
+
const MetaRelationsType = new graphql_1.GraphQLObjectType({
|
|
156
|
+
name: 'MetaRelations',
|
|
157
|
+
description: 'Table relations',
|
|
158
|
+
fields: () => ({
|
|
159
|
+
belongsTo: { type: nnList(MetaBelongsToRelationType) },
|
|
160
|
+
has: { type: nnList(MetaHasRelationType) },
|
|
161
|
+
hasOne: { type: nnList(MetaHasRelationType) },
|
|
162
|
+
hasMany: { type: nnList(MetaHasRelationType) },
|
|
163
|
+
manyToMany: { type: nnList(MetaManyToManyRelationType) },
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
const MetaTableType = new graphql_1.GraphQLObjectType({
|
|
167
|
+
name: 'MetaTable',
|
|
168
|
+
description: 'Information about a database table',
|
|
169
|
+
fields: () => ({
|
|
170
|
+
name: { type: nn(graphql_1.GraphQLString) },
|
|
171
|
+
schemaName: { type: nn(graphql_1.GraphQLString) },
|
|
172
|
+
fields: { type: nnList(MetaFieldType) },
|
|
173
|
+
indexes: { type: nnList(MetaIndexType) },
|
|
174
|
+
constraints: { type: nn(MetaConstraintsType) },
|
|
175
|
+
foreignKeyConstraints: { type: nnList(MetaForeignKeyConstraintType) },
|
|
176
|
+
primaryKeyConstraints: { type: nnList(MetaPrimaryKeyConstraintType) },
|
|
177
|
+
uniqueConstraints: { type: nnList(MetaUniqueConstraintType) },
|
|
178
|
+
relations: { type: nn(MetaRelationsType) },
|
|
179
|
+
inflection: { type: nn(MetaInflectionType) },
|
|
180
|
+
query: { type: nn(MetaQueryType) },
|
|
181
|
+
}),
|
|
182
|
+
});
|
|
183
|
+
return new graphql_1.GraphQLObjectType({
|
|
184
|
+
name: 'MetaSchema',
|
|
185
|
+
description: 'Root meta schema type',
|
|
186
|
+
fields: () => ({
|
|
187
|
+
tables: { type: nnList(MetaTableType) },
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function extendQueryWithMetaField(fields, tablesMeta) {
|
|
192
|
+
const metaSchemaType = createMetaSchemaType();
|
|
193
|
+
const metaField = {
|
|
194
|
+
type: metaSchemaType,
|
|
195
|
+
description: 'Metadata about the database schema, including tables, fields, indexes, and constraints. Useful for code generation tools.',
|
|
196
|
+
resolve() {
|
|
197
|
+
return { tables: tablesMeta };
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
...fields,
|
|
202
|
+
_meta: metaField,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MetaInflection, PgCodec } from './types';
|
|
2
|
+
export declare function safeInflection<T>(fn: () => T, fallback: T): T;
|
|
3
|
+
export declare function createAttributeInflector(inflection: MetaInflection): (attrName: string, codec: PgCodec) => string;
|
|
4
|
+
export declare function fallbackTableType(codecName: string): string;
|