graphile-settings 3.1.1 → 4.0.1

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.
Files changed (102) hide show
  1. package/README.md +170 -85
  2. package/esm/index.d.ts +37 -0
  3. package/esm/index.js +54 -103
  4. package/esm/plugins/conflict-detector.d.ts +7 -0
  5. package/esm/plugins/conflict-detector.js +67 -0
  6. package/esm/plugins/custom-inflector.d.ts +9 -0
  7. package/esm/plugins/custom-inflector.js +382 -0
  8. package/esm/plugins/enable-all-filter-columns.d.ts +60 -0
  9. package/esm/plugins/enable-all-filter-columns.js +85 -0
  10. package/esm/plugins/index.d.ts +19 -0
  11. package/esm/plugins/index.js +26 -0
  12. package/esm/plugins/inflector-logger.d.ts +7 -0
  13. package/esm/plugins/inflector-logger.js +215 -0
  14. package/esm/plugins/many-to-many-preset.d.ts +62 -0
  15. package/esm/plugins/many-to-many-preset.js +86 -0
  16. package/esm/plugins/meta-schema/cache.d.ts +4 -0
  17. package/esm/plugins/meta-schema/cache.js +7 -0
  18. package/esm/plugins/meta-schema/constraint-meta-builders.d.ts +13 -0
  19. package/esm/plugins/meta-schema/constraint-meta-builders.js +51 -0
  20. package/esm/plugins/meta-schema/graphql-meta-field.d.ts +4 -0
  21. package/esm/plugins/meta-schema/graphql-meta-field.js +201 -0
  22. package/esm/plugins/meta-schema/inflection-utils.d.ts +4 -0
  23. package/esm/plugins/meta-schema/inflection-utils.js +20 -0
  24. package/esm/plugins/meta-schema/name-meta-builders.d.ts +4 -0
  25. package/esm/plugins/meta-schema/name-meta-builders.js +38 -0
  26. package/esm/plugins/meta-schema/plugin.d.ts +2 -0
  27. package/esm/plugins/meta-schema/plugin.js +23 -0
  28. package/esm/plugins/meta-schema/relation-meta-builders.d.ts +8 -0
  29. package/esm/plugins/meta-schema/relation-meta-builders.js +115 -0
  30. package/esm/plugins/meta-schema/table-meta-builder.d.ts +2 -0
  31. package/esm/plugins/meta-schema/table-meta-builder.js +69 -0
  32. package/esm/plugins/meta-schema/table-meta-context.d.ts +13 -0
  33. package/esm/plugins/meta-schema/table-meta-context.js +11 -0
  34. package/esm/plugins/meta-schema/table-resource-utils.d.ts +12 -0
  35. package/esm/plugins/meta-schema/table-resource-utils.js +50 -0
  36. package/esm/plugins/meta-schema/type-mappings.d.ts +3 -0
  37. package/esm/plugins/meta-schema/type-mappings.js +75 -0
  38. package/esm/plugins/meta-schema/types.d.ts +206 -0
  39. package/esm/plugins/meta-schema/types.js +1 -0
  40. package/esm/plugins/meta-schema.d.ts +19 -0
  41. package/esm/plugins/meta-schema.js +20 -0
  42. package/esm/plugins/minimal-preset.d.ts +7 -0
  43. package/esm/plugins/minimal-preset.js +42 -0
  44. package/esm/plugins/pg-type-mappings.d.ts +41 -0
  45. package/esm/plugins/pg-type-mappings.js +122 -0
  46. package/esm/plugins/primary-key-only.d.ts +96 -0
  47. package/esm/plugins/primary-key-only.js +143 -0
  48. package/esm/presets/constructive-preset.d.ts +40 -0
  49. package/esm/presets/constructive-preset.js +137 -0
  50. package/esm/presets/index.d.ts +7 -0
  51. package/esm/presets/index.js +7 -0
  52. package/index.d.ts +37 -3
  53. package/index.js +56 -129
  54. package/package.json +16 -22
  55. package/plugins/conflict-detector.d.ts +7 -0
  56. package/plugins/conflict-detector.js +70 -0
  57. package/plugins/custom-inflector.d.ts +9 -0
  58. package/plugins/custom-inflector.js +385 -0
  59. package/plugins/enable-all-filter-columns.d.ts +60 -0
  60. package/plugins/enable-all-filter-columns.js +88 -0
  61. package/plugins/index.d.ts +19 -0
  62. package/plugins/index.js +56 -0
  63. package/plugins/inflector-logger.d.ts +7 -0
  64. package/plugins/inflector-logger.js +218 -0
  65. package/plugins/many-to-many-preset.d.ts +62 -0
  66. package/plugins/many-to-many-preset.js +89 -0
  67. package/plugins/meta-schema/cache.d.ts +4 -0
  68. package/plugins/meta-schema/cache.js +12 -0
  69. package/plugins/meta-schema/constraint-meta-builders.d.ts +13 -0
  70. package/plugins/meta-schema/constraint-meta-builders.js +58 -0
  71. package/plugins/meta-schema/graphql-meta-field.d.ts +4 -0
  72. package/plugins/meta-schema/graphql-meta-field.js +204 -0
  73. package/plugins/meta-schema/inflection-utils.d.ts +4 -0
  74. package/plugins/meta-schema/inflection-utils.js +25 -0
  75. package/plugins/meta-schema/name-meta-builders.d.ts +4 -0
  76. package/plugins/meta-schema/name-meta-builders.js +43 -0
  77. package/plugins/meta-schema/plugin.d.ts +2 -0
  78. package/plugins/meta-schema/plugin.js +26 -0
  79. package/plugins/meta-schema/relation-meta-builders.d.ts +8 -0
  80. package/plugins/meta-schema/relation-meta-builders.js +120 -0
  81. package/plugins/meta-schema/table-meta-builder.d.ts +2 -0
  82. package/plugins/meta-schema/table-meta-builder.js +72 -0
  83. package/plugins/meta-schema/table-meta-context.d.ts +13 -0
  84. package/plugins/meta-schema/table-meta-context.js +15 -0
  85. package/plugins/meta-schema/table-resource-utils.d.ts +12 -0
  86. package/plugins/meta-schema/table-resource-utils.js +60 -0
  87. package/plugins/meta-schema/type-mappings.d.ts +3 -0
  88. package/plugins/meta-schema/type-mappings.js +79 -0
  89. package/plugins/meta-schema/types.d.ts +206 -0
  90. package/plugins/meta-schema/types.js +2 -0
  91. package/plugins/meta-schema.d.ts +19 -0
  92. package/plugins/meta-schema.js +20 -0
  93. package/plugins/minimal-preset.d.ts +7 -0
  94. package/plugins/minimal-preset.js +45 -0
  95. package/plugins/pg-type-mappings.d.ts +41 -0
  96. package/plugins/pg-type-mappings.js +128 -0
  97. package/plugins/primary-key-only.d.ts +96 -0
  98. package/plugins/primary-key-only.js +147 -0
  99. package/presets/constructive-preset.d.ts +40 -0
  100. package/presets/constructive-preset.js +140 -0
  101. package/presets/index.d.ts +7 -0
  102. package/presets/index.js +11 -0
package/README.md CHANGED
@@ -16,118 +16,203 @@
16
16
  </a>
17
17
  </p>
18
18
 
19
- **`graphile-settings`** is a batteries-included configuration builder for [PostGraphile](https://www.graphile.org/postgraphile/), purpose-built for the Constructive ecosystem. It centralizes plugin setup, schema wiring, and feature flags into a single, composable interface — enabling consistent, high-performance GraphQL APIs across projects.
19
+ A batteries-included configuration builder for [PostGraphile v5](https://www.graphile.org/postgraphile/), purpose-built for the Constructive ecosystem. It centralizes plugin setup, schema wiring, and feature flags into a single, composable interface — enabling consistent, high-performance GraphQL APIs across projects.
20
20
 
21
- ## 🚀 Installation
21
+ ## Installation
22
22
 
23
23
  ```bash
24
24
  npm install graphile-settings
25
25
  ```
26
26
 
27
- ## Features
27
+ ## Quick Start
28
28
 
29
- * Built-in support for:
30
-
31
- * ✅ Connection filters
32
- * 🔍 Full-text search
33
- * 🌍 PostGIS support (with filters)
34
- * 🧩 Many-to-many helpers
35
- * 🆎 Simplified inflectors
36
- * 🗂 Upload field support (S3/MinIO)
37
- * 🌐 i18n support via `graphile-i18n`
38
- * 🧠 Meta schema plugin
39
- * 🔎 Graphile search plugin
40
- * Smart schema and plugin configuration via environment or options
41
- * Express-compatible with support for request-aware context
42
-
43
- ## 📦 Usage
44
-
45
- ```ts
46
- import { getGraphileSettings } from 'graphile-settings';
29
+ ```typescript
30
+ import { ConstructivePreset, makePgService } from 'graphile-settings';
47
31
  import { postgraphile } from 'postgraphile';
32
+ import { grafserv } from 'grafserv/express/v4';
48
33
  import express from 'express';
49
34
 
50
35
  const app = express();
51
36
 
52
- const settings = getGraphileSettings({
53
- server: {
54
- port: 5000,
55
- host: '0.0.0.0',
56
- strictAuth: true,
57
- },
58
- graphile: {
59
- schema: ['app_public'],
60
- metaSchemas: ['metaschema_public', 'services_public', 'metaschema_modules_public'],
61
- },
62
- features: {
63
- postgis: true,
64
- simpleInflection: true,
65
- oppositeBaseNames: true,
66
- },
67
- cdn: {
68
- bucketName: 'media-bucket',
69
- awsRegion: 'us-west-1',
70
- awsAccessKey: 'AKIA...',
71
- awsSecretKey: 'secret',
72
- minioEndpoint: 'http://localhost:9000'
73
- }
74
- });
37
+ const preset = {
38
+ extends: [ConstructivePreset],
39
+ pgServices: [
40
+ makePgService({
41
+ connectionString: 'postgres://user:pass@localhost/mydb',
42
+ schemas: ['app_public'],
43
+ }),
44
+ ],
45
+ };
46
+
47
+ const pgl = postgraphile(preset);
48
+ const serv = pgl.createServ(grafserv);
49
+
50
+ const httpServer = require('http').createServer(app);
51
+ serv.addTo(app, httpServer);
52
+ httpServer.listen(5000);
53
+ ```
54
+
55
+ ## Features
56
+
57
+ The `ConstructivePreset` combines multiple plugins and configurations to provide a clean, opinionated GraphQL API. Below is a detailed breakdown of each feature.
58
+
59
+ ### No Node/Relay Features (MinimalPreset)
60
+
61
+ PostGraphile v5 includes Relay Global Object Identification by default, which adds a global `id` field to types and renames actual `id` columns to `rowId`. Since Constructive uses UUIDs, we disable all Node/Relay plugins to keep `id` columns as `id`.
62
+
63
+ Disabled plugins: `NodePlugin`, `AddNodeInterfaceToSuitableTypesPlugin`, `NodeIdCodecBase64JSONPlugin`, `NodeIdCodecPipeStringPlugin`, `RegisterQueryNodePlugin`, `NodeAccessorPlugin`, `PgNodeIdAttributesPlugin`, `PgTableNodePlugin`
64
+
65
+ ### Custom Inflection (InflektPreset)
66
+
67
+ Uses the `inflekt` library for consistent naming conventions with proper Latin plural handling (e.g., "schemata" → "schema" instead of "schematum"). Key simplifications include simplified root query fields (`allUsers` → `users`), simplified relation fields (`userByAuthorId` → `author`, `postsByAuthorId` → `posts`), simplified many-to-many fields (`tagsByPostTagPostIdAndTagId` → `tags`), and shortened mutation names (`updateUserById` → `updateUser`).
75
68
 
76
- app.use(postgraphile({
77
- ...settings,
78
- pgPool: myPool // your initialized pg.Pool
79
- }));
69
+ The many-to-many inflector includes conflict detection — if a direct relation to the same target table exists or there are multiple many-to-many relations to the same target, it falls back to verbose naming to avoid conflicts.
80
70
 
81
- app.listen(settings.port);
71
+ ### Connection Filter Plugin
72
+
73
+ Adds powerful filtering capabilities to connections with operators like `eq`, `ne`, `lt`, `gt`, `contains`, `startsWith`, etc. Configuration includes logical operators (`and`, `or`, `not`) enabled for combining conditions, array filtering enabled for PostgreSQL array columns, computed column filtering disabled by default (enable with `@filterable` smart tag), setof function filtering disabled by default, and relation filtering disabled to keep the API surface clean.
74
+
75
+ ### Filter All Columns (EnableAllFilterColumnsPreset)
76
+
77
+ By default, PostGraphile v5 only allows filtering on indexed columns. This preset enables filtering on ALL columns, giving developers flexibility while leaving index optimization to DBAs. Monitor query performance and add indexes as needed for frequently filtered columns.
78
+
79
+ ### Many-to-Many Relationships (ManyToManyOptInPreset)
80
+
81
+ Uses `@graphile-contrib/pg-many-to-many` with opt-in behavior. By default, no many-to-many fields are generated. To enable for a specific junction table:
82
+
83
+ ```sql
84
+ COMMENT ON TABLE post_tags IS E'@behavior +manyToMany';
82
85
  ```
83
86
 
84
- ## 🧰 Configuration Options
87
+ This prevents API bloat from unused junction table fields.
85
88
 
86
- ### `ConstructiveOptions`
89
+ ### Primary Key Only Lookups (NoUniqueLookupPreset)
87
90
 
88
- #### `server`
91
+ Disables non-primary-key unique constraint lookups for both queries and mutations. Instead of generating `user(id)`, `userByEmail(email)`, `userByUsername(username)`, only `user(id)` is generated. The same operations can be done using filters, reducing API surface and generated code complexity.
92
+
93
+ ### Meta Schema Plugin (MetaSchemaPreset)
94
+
95
+ Exposes a `_meta` GraphQL query for database schema introspection:
96
+
97
+ ```graphql
98
+ query {
99
+ _meta {
100
+ tables {
101
+ name
102
+ schemaName
103
+ fields { name, type { pgType, gqlType, isArray }, isNotNull, hasDefault }
104
+ indexes { name, isUnique, isPrimary, columns }
105
+ constraints { primaryKey, unique, foreignKey }
106
+ inflection { tableType, allRows, connection, edge }
107
+ query { all, one, create, update, delete }
108
+ }
109
+ }
110
+ }
111
+ ```
89
112
 
90
- * `port` (number) Port to use
91
- * `host` — (string) Hostname
92
- * `trustProxy` — (boolean) Whether to trust proxy headers (e.g. for real IPs)
93
- * `origin` — (string) Origin for CORS/auth logic
94
- * `strictAuth` — (boolean) Whether to enforce strict auth
113
+ Useful for code generation tools that need to understand the database structure.
95
114
 
96
- #### `graphile`
115
+ Testing strategy:
116
+ - Metadata behavior is tested in-process with mocked PostGraphile build resources (no live DB required).
117
+ - Snapshot coverage captures full multi-table metadata scenarios and query contract shape.
118
+ - Run: `pnpm --filter graphile-settings exec jest --runInBand`
97
119
 
98
- * `schema` (string or string\[]) Required list of main GraphQL schemas
99
- * `metaSchemas` — (string\[]) Optional list of meta/introspection schemas
100
- * `isPublic` — (boolean) Flag for public GraphQL instance
101
- * `appendPlugins` — (Plugin\[]) Additional Graphile plugins
102
- * `graphileBuildOptions` — (PostGraphileOptions.graphileBuildOptions) Extra build options
103
- * `overrideSettings` — (Partial<PostGraphileOptions>) Manual overrides of generated config
120
+ ### Tsvector Codec (TsvectorCodecPreset)
104
121
 
105
- #### `features`
122
+ Adds support for PostgreSQL's `tsvector` and `tsquery` types used in full-text search. These types are represented as strings in GraphQL.
106
123
 
107
- * `simpleInflection` Use simplified inflection (e.g. `fooByBarId`)
108
- * `oppositeBaseNames` — Enable smart reverse relation names
109
- * `postgis` Enable PostGIS and filter plugin
124
+ ### Conflict Detector (ConflictDetectorPreset)
125
+
126
+ Detects naming conflicts between tables in different schemas. When two tables would have the same GraphQL type name, logs a warning with resolution options (smart tags, rename, or omit).
127
+
128
+ ### Inflector Logger (InflectorLoggerPreset)
129
+
130
+ Logs inflector calls during schema build for debugging. Enable with `INFLECTOR_LOG=1` environment variable. Only runs at build time, not on every request.
131
+
132
+ ## Presets
133
+
134
+ | Preset | Description |
135
+ |--------|-------------|
136
+ | `ConstructivePreset` | Main preset combining all features (recommended) |
137
+ | `MinimalPreset` | PostGraphile without Node/Relay features |
138
+ | `InflektPreset` | Custom inflection using inflekt library |
139
+ | `ConflictDetectorPreset` | Warns about naming conflicts between schemas |
140
+ | `InflectorLoggerPreset` | Debug logging for inflector calls |
141
+ | `EnableAllFilterColumnsPreset` | Allow filtering on all columns |
142
+ | `ManyToManyOptInPreset` | Many-to-many with opt-in behavior |
143
+ | `NoUniqueLookupPreset` | Disable non-primary-key lookups |
144
+ | `MetaSchemaPreset` | `_meta` query for schema introspection |
145
+ | `TsvectorCodecPreset` | Support for tsvector/tsquery types |
146
+
147
+ ## Plugins
148
+
149
+ Each preset includes one or more plugins that can be used individually:
150
+
151
+ | Plugin | Description |
152
+ |--------|-------------|
153
+ | `InflektPlugin` | Custom inflection rules |
154
+ | `ConflictDetectorPlugin` | Naming conflict detection |
155
+ | `InflectorLoggerPlugin` | Debug logging |
156
+ | `EnableAllFilterColumnsPlugin` | Enable all column filters |
157
+ | `ManyToManyOptInPlugin` | Opt-in many-to-many behavior |
158
+ | `PrimaryKeyOnlyPlugin` | Keep only primary key lookups |
159
+ | `NoUniqueLookupPlugin` | Disable all unique lookups |
160
+ | `MetaSchemaPlugin` | Schema introspection |
161
+ | `TsvectorCodecPlugin` | Tsvector type support |
162
+
163
+ ## Building Schema Directly
164
+
165
+ For codegen, testing, or other use cases where you need the schema without a server:
166
+
167
+ ```typescript
168
+ import { ConstructivePreset, makePgService } from 'graphile-settings';
169
+ import { makeSchema } from 'graphile-build';
170
+ import { printSchema } from 'graphql';
171
+
172
+ const preset = {
173
+ extends: [ConstructivePreset],
174
+ pgServices: [
175
+ makePgService({
176
+ connectionString: 'postgres://user:pass@localhost/mydb',
177
+ schemas: ['app_public'],
178
+ }),
179
+ ],
180
+ };
181
+
182
+ const { schema } = await makeSchema(preset);
183
+ const sdl = printSchema(schema);
184
+ ```
185
+
186
+ ## Smart Tags Reference
187
+
188
+ Control schema generation with PostgreSQL comments:
189
+
190
+ ```sql
191
+ -- Enable many-to-many on a junction table
192
+ COMMENT ON TABLE post_tags IS E'@behavior +manyToMany';
193
+
194
+ -- Customize many-to-many field name
195
+ COMMENT ON CONSTRAINT post_tags_tag_id_fkey ON post_tags IS E'@manyToManyFieldName tags';
196
+
197
+ -- Rename a type
198
+ COMMENT ON TABLE users IS E'@name Person';
199
+
200
+ -- Omit a table from the schema
201
+ COMMENT ON TABLE internal_logs IS E'@omit';
202
+
203
+ -- Make a computed column filterable
204
+ COMMENT ON FUNCTION full_name(users) IS E'@filterable';
205
+ ```
110
206
 
111
- #### `cdn`
207
+ ## Environment Variables
112
208
 
113
- * `bucketName` Required for upload plugin (S3 or MinIO)
114
- * `awsRegion` — AWS region
115
- * `awsAccessKey` Access key for upload
116
- * `awsSecretKey` — Secret key
117
- * `minioEndpoint` — Optional override for MinIO compatibility
209
+ | Variable | Description |
210
+ |----------|-------------|
211
+ | `INFLECTOR_LOG=1` | Enable inflector debug logging |
118
212
 
119
- ## 🔌 Included Plugins
213
+ ## License
120
214
 
121
- * `graphile-plugin-connection-filter`
122
- * `graphile-plugin-fulltext-filter`
123
- * `graphile-postgis`
124
- * `graphile-plugin-connection-filter-postgis`
125
- * `graphile-simple-inflector`
126
- * `graphile-i18n`
127
- * `graphile-meta-schema`
128
- * `@graphile-contrib/pg-many-to-many`
129
- * `graphile-search-plugin`
130
- * `graphile-pg-type-mappings`
215
+ MIT
131
216
 
132
217
  ---
133
218
 
package/esm/index.d.ts ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * graphile-settings
3
+ *
4
+ * Shared PostGraphile v5 settings, presets, and plugins for Constructive.
5
+ *
6
+ * This package provides:
7
+ * - Custom plugins for PostGraphile v5
8
+ * - Pre-configured presets combining multiple plugins
9
+ *
10
+ * USAGE:
11
+ *
12
+ * 1. Use the main preset:
13
+ * ```typescript
14
+ * import { ConstructivePreset, makePgService } from 'graphile-settings';
15
+ * import { makeSchema } from 'graphile-build';
16
+ *
17
+ * const preset = {
18
+ * extends: [ConstructivePreset],
19
+ * pgServices: [makePgService({ connectionString, schemas })],
20
+ * };
21
+ * const { schema } = await makeSchema(preset);
22
+ * ```
23
+ *
24
+ * 2. Use individual plugins:
25
+ * ```typescript
26
+ * import { MinimalPreset, InflektPreset } from 'graphile-settings/plugins';
27
+ * ```
28
+ */
29
+ import { makePgService } from 'postgraphile/adaptors/pg';
30
+ import 'postgraphile/grafserv';
31
+ import 'graphile-build';
32
+ export { ConstructivePreset } from './presets/constructive-preset';
33
+ export * from './plugins/index';
34
+ export * from './presets/index';
35
+ import { MinimalPreset } from './plugins/minimal-preset';
36
+ export { MinimalPreset };
37
+ export { makePgService };
package/esm/index.js CHANGED
@@ -1,103 +1,54 @@
1
- import PgManyToMany from '@graphile-contrib/pg-many-to-many';
2
- import { getEnvOptions } from '@constructive-io/graphql-env';
3
- import PgPostgis from 'graphile-postgis';
4
- import FulltextFilterPlugin from 'graphile-plugin-fulltext-filter';
5
- import { NodePlugin } from 'graphile-build';
6
- import { additionalGraphQLContextFromRequest as langAdditional, LangPlugin } from 'graphile-i18n';
7
- import PgMetaschema from 'graphile-meta-schema';
8
- import PgSearch from 'graphile-search-plugin';
9
- import PgSimpleInflector from 'graphile-simple-inflector';
10
- import ConnectionFilterPlugin from 'graphile-plugin-connection-filter';
11
- import PgPostgisFilter from 'graphile-plugin-connection-filter-postgis';
12
- import CustomPgTypeMappingsPlugin from 'graphile-pg-type-mappings';
13
- import UploadPostGraphilePlugin, { Uploader } from 'graphile-upload-plugin';
14
- export const getGraphileSettings = (rawOpts) => {
15
- const opts = getEnvOptions(rawOpts);
16
- const { server, graphile, features, cdn } = opts;
17
- // Instantiate uploader with merged cdn opts
18
- const uploader = new Uploader({
19
- bucketName: cdn.bucketName,
20
- awsRegion: cdn.awsRegion,
21
- awsAccessKey: cdn.awsAccessKey,
22
- awsSecretKey: cdn.awsSecretKey,
23
- minioEndpoint: cdn.minioEndpoint,
24
- provider: cdn.provider,
25
- });
26
- const resolveUpload = uploader.resolveUpload.bind(uploader);
27
- const plugins = [
28
- ConnectionFilterPlugin,
29
- FulltextFilterPlugin,
30
- CustomPgTypeMappingsPlugin,
31
- UploadPostGraphilePlugin,
32
- PgMetaschema,
33
- PgManyToMany,
34
- PgSearch,
35
- ];
36
- if (features?.postgis) {
37
- plugins.push(PgPostgis, PgPostgisFilter);
38
- }
39
- if (features?.simpleInflection) {
40
- plugins.push(PgSimpleInflector);
41
- }
42
- plugins.push(LangPlugin);
43
- return {
44
- graphileBuildOptions: {
45
- uploadFieldDefinitions: [
46
- {
47
- name: 'upload',
48
- namespaceName: 'public',
49
- type: 'JSON',
50
- resolve: resolveUpload,
51
- },
52
- {
53
- name: 'attachment',
54
- namespaceName: 'public',
55
- type: 'String',
56
- resolve: resolveUpload,
57
- },
58
- {
59
- name: 'image',
60
- namespaceName: 'public',
61
- type: 'JSON',
62
- resolve: resolveUpload,
63
- },
64
- {
65
- tag: 'upload',
66
- resolve: resolveUpload,
67
- },
68
- ],
69
- pgSimplifyOppositeBaseNames: features?.oppositeBaseNames,
70
- connectionFilterComputedColumns: false,
71
- },
72
- appendPlugins: plugins,
73
- skipPlugins: [NodePlugin],
74
- dynamicJson: true,
75
- disableGraphiql: false,
76
- enhanceGraphiql: true,
77
- enableQueryBatching: true,
78
- graphiql: true,
79
- watch: false,
80
- port: server?.port,
81
- host: server?.host,
82
- schema: graphile?.schema,
83
- ignoreRBAC: false,
84
- legacyRelations: 'omit',
85
- showErrorStack: false,
86
- // @ts-ignore
87
- extendedErrors: false,
88
- disableQueryLog: false,
89
- includeExtensionResources: true,
90
- setofFunctionsContainNulls: false,
91
- retryOnInitFail: async (_error) => {
92
- return false;
93
- },
94
- additionalGraphQLContextFromRequest: async (req, res) => {
95
- const langContext = await langAdditional(req, res);
96
- return {
97
- ...langContext,
98
- req,
99
- res,
100
- };
101
- },
102
- };
103
- };
1
+ /**
2
+ * graphile-settings
3
+ *
4
+ * Shared PostGraphile v5 settings, presets, and plugins for Constructive.
5
+ *
6
+ * This package provides:
7
+ * - Custom plugins for PostGraphile v5
8
+ * - Pre-configured presets combining multiple plugins
9
+ *
10
+ * USAGE:
11
+ *
12
+ * 1. Use the main preset:
13
+ * ```typescript
14
+ * import { ConstructivePreset, makePgService } from 'graphile-settings';
15
+ * import { makeSchema } from 'graphile-build';
16
+ *
17
+ * const preset = {
18
+ * extends: [ConstructivePreset],
19
+ * pgServices: [makePgService({ connectionString, schemas })],
20
+ * };
21
+ * const { schema } = await makeSchema(preset);
22
+ * ```
23
+ *
24
+ * 2. Use individual plugins:
25
+ * ```typescript
26
+ * import { MinimalPreset, InflektPreset } from 'graphile-settings/plugins';
27
+ * ```
28
+ */
29
+ import { makePgService } from 'postgraphile/adaptors/pg';
30
+ // Import modules for type augmentation
31
+ // These add properties to the GraphileConfig.Preset interface:
32
+ // - grafserv: adds 'grafserv' property
33
+ // - graphile-build: adds 'schema' property (typed as GraphileBuild.SchemaOptions)
34
+ // - postgraphile-plugin-connection-filter: augments SchemaOptions with connectionFilter* options
35
+ import 'postgraphile/grafserv';
36
+ import 'graphile-build';
37
+ // ============================================================================
38
+ // Re-export all plugins and presets
39
+ // ============================================================================
40
+ // Main preset
41
+ export { ConstructivePreset } from './presets/constructive-preset';
42
+ // Re-export all plugins for convenience
43
+ export * from './plugins/index';
44
+ // Re-export presets
45
+ export * from './presets/index';
46
+ // ============================================================================
47
+ // Utilities
48
+ // ============================================================================
49
+ // Import the new MinimalPreset from plugins
50
+ import { MinimalPreset } from './plugins/minimal-preset';
51
+ // Re-export MinimalPreset for backward compatibility
52
+ export { MinimalPreset };
53
+ // Re-export makePgService for convenience
54
+ export { makePgService };
@@ -0,0 +1,7 @@
1
+ import type { GraphileConfig } from 'graphile-config';
2
+ export declare const ConflictDetectorPlugin: GraphileConfig.Plugin;
3
+ /**
4
+ * Preset that includes the conflict detector plugin.
5
+ */
6
+ export declare const ConflictDetectorPreset: GraphileConfig.Preset;
7
+ export default ConflictDetectorPlugin;
@@ -0,0 +1,67 @@
1
+ export const ConflictDetectorPlugin = {
2
+ name: 'ConflictDetectorPlugin',
3
+ version: '1.0.0',
4
+ schema: {
5
+ hooks: {
6
+ build(build) {
7
+ // Track codecs by their GraphQL name to detect conflicts
8
+ const codecsByName = new Map();
9
+ // Get configured schemas from pgServices to only check relevant codecs
10
+ const configuredSchemas = new Set();
11
+ const pgServices = build.resolvedPreset?.pgServices ?? [];
12
+ for (const service of pgServices) {
13
+ for (const schema of service.schemas ?? ['public']) {
14
+ configuredSchemas.add(schema);
15
+ }
16
+ }
17
+ // Iterate through all codecs to find tables
18
+ for (const codec of Object.values(build.input.pgRegistry.pgCodecs)) {
19
+ // Skip non-table codecs (those without attributes or anonymous ones)
20
+ if (!codec.attributes || codec.isAnonymous)
21
+ continue;
22
+ // Get the schema name from the codec's extensions
23
+ const pgExtensions = codec.extensions?.pg;
24
+ const schemaName = pgExtensions?.schemaName || 'unknown';
25
+ const tableName = codec.name;
26
+ // Skip codecs from schemas not in the configured list
27
+ if (configuredSchemas.size > 0 && !configuredSchemas.has(schemaName)) {
28
+ continue;
29
+ }
30
+ // Get the GraphQL name that would be generated
31
+ const graphqlName = build.inflection.tableType(codec);
32
+ const info = {
33
+ name: graphqlName,
34
+ schemaName,
35
+ tableName,
36
+ };
37
+ if (!codecsByName.has(graphqlName)) {
38
+ codecsByName.set(graphqlName, []);
39
+ }
40
+ codecsByName.get(graphqlName).push(info);
41
+ }
42
+ // Check for conflicts and log warnings
43
+ for (const [graphqlName, codecs] of codecsByName) {
44
+ if (codecs.length > 1) {
45
+ const locations = codecs
46
+ .map((c) => `${c.schemaName}.${c.tableName}`)
47
+ .join(', ');
48
+ console.warn(`\nNAMING CONFLICT DETECTED: GraphQL type "${graphqlName}" would be generated from multiple tables:\n` +
49
+ ` Tables: ${locations}\n` +
50
+ ` Resolution options:\n` +
51
+ ` 1. Add @name smart tag to one table: COMMENT ON TABLE schema.table IS E'@name UniqueTypeName';\n` +
52
+ ` 2. Rename one of the tables in the database\n` +
53
+ ` 3. Exclude one table from the schema using @omit smart tag\n`);
54
+ }
55
+ }
56
+ return build;
57
+ },
58
+ },
59
+ },
60
+ };
61
+ /**
62
+ * Preset that includes the conflict detector plugin.
63
+ */
64
+ export const ConflictDetectorPreset = {
65
+ plugins: [ConflictDetectorPlugin],
66
+ };
67
+ export default ConflictDetectorPlugin;
@@ -0,0 +1,9 @@
1
+ import type { GraphileConfig } from 'graphile-config';
2
+ export declare const InflektPlugin: GraphileConfig.Plugin;
3
+ /**
4
+ * Preset that includes the inflekt-based inflector plugin.
5
+ * Use this in your main preset's `extends` array.
6
+ */
7
+ export declare const InflektPreset: GraphileConfig.Preset;
8
+ export declare const CustomInflectorPlugin: GraphileConfig.Plugin;
9
+ export declare const CustomInflectorPreset: GraphileConfig.Preset;