graphile-settings 4.30.2 → 4.31.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.
package/esm/index.d.ts CHANGED
@@ -29,7 +29,8 @@
29
29
  import { makePgService } from 'postgraphile/adaptors/pg';
30
30
  import 'postgraphile/grafserv';
31
31
  import 'graphile-build';
32
- export { ConstructivePreset } from './presets/constructive-preset';
32
+ export { ConstructivePreset, createConstructivePreset } from './presets/constructive-preset';
33
+ export type { ConstructivePresetOptions } from './presets/constructive-preset';
33
34
  export * from './plugins/index';
34
35
  export * from './presets/index';
35
36
  export { makePgService };
package/esm/index.js CHANGED
@@ -37,8 +37,8 @@ import 'graphile-build';
37
37
  // ============================================================================
38
38
  // Re-export all plugins and presets
39
39
  // ============================================================================
40
- // Main preset
41
- export { ConstructivePreset } from './presets/constructive-preset';
40
+ // Main preset + factory
41
+ export { ConstructivePreset, createConstructivePreset } from './presets/constructive-preset';
42
42
  // Re-export all plugins for convenience
43
43
  export * from './plugins/index';
44
44
  // Re-export presets
@@ -1,60 +1,81 @@
1
1
  import type { GraphileConfig } from 'graphile-config';
2
2
  /**
3
- * Constructive PostGraphile v5 Preset
4
- *
5
- * This is the main preset that combines all our custom plugins and configurations.
6
- * It provides a clean, opinionated GraphQL API built from PostgreSQL.
7
- *
8
- * FEATURES:
9
- * - No Node/Relay features (keeps `id` as `id`, no global object identification)
10
- * - Custom inflection using inflekt library
11
- * - Conflict detection for multi-schema setups
12
- * - Inflector logging for debugging (enable with INFLECTOR_LOG=1)
13
- * - Primary key only lookups (no *ByEmail, *ByUsername, etc.)
14
- * - Connection filter plugin with all columns filterable
15
- * - Many-to-many relationships (opt-in via @behavior +manyToMany)
16
- * - Meta schema plugin (_meta query for introspection of tables, fields, indexes)
17
- * - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
18
- * - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
19
- * - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
20
- * - Presigned URL plugin (requestUploadUrl mutation + downloadUrl computed field)
21
- * - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
22
- * CORS management, provisionBucket mutation for manual/retry)
23
- * - SQL expression validator (validates @sqlExpression columns in mutations)
24
- * - PG type mappings (maps custom types like email, url to GraphQL scalars)
25
- * - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
26
- * orderBy distance zero config)
27
- * - pg_textsearch BM25 search (auto-discovers BM25 indexes: filter fields, score computed fields,
28
- * orderBy score — zero config)
29
- * - pg_trgm fuzzy matching (similarTo/wordSimilarTo on text columns, similarity score fields,
30
- * orderBy similarity zero config, typo-tolerant)
31
- * - ltree support (auto-detects ltree columns, LTree scalar with file-path syntax,
32
- * containment/glob filters within, ancestorOf, glob)
33
- * - Aggregates (OPTIONAL not included by default; add PgAggregatesPreset to extends to enable.
34
- * Provides sum, avg, min, max, stddev, variance, distinctCount on connections,
35
- * groupedAggregates with groupBy + having, orderBy relational aggregates,
36
- * filter by relational aggregates — per-table opt-out via @behavior -aggregates)
37
- *
38
- * RELATION FILTERS:
39
- * - Enabled via connectionFilterRelations: true
40
- * - Forward: filter child by parent (e.g. allOrders(where: { clientByClientId: { name: { startsWith: "Acme" } } }))
41
- * - Backward: filter parent by children (e.g. allClients(where: { ordersByClientId: { some: { total: { greaterThan: 1000 } } } }))
3
+ * Feature flags that control which optional Graphile plugins are included
4
+ * in the preset. Mirrors the `database_settings` / `api_settings` cascade
5
+ * from the services DB.
6
+ *
7
+ * Every flag defaults to the value that matches the current production
8
+ * behavior so that `createConstructivePreset()` (no args) is identical to
9
+ * the previous static `ConstructivePreset`.
10
+ */
11
+ export interface ConstructivePresetOptions {
12
+ enableAggregates?: boolean;
13
+ enablePostgis?: boolean;
14
+ enableSearch?: boolean;
15
+ enableDirectUploads?: boolean;
16
+ enablePresignedUploads?: boolean;
17
+ enableManyToMany?: boolean;
18
+ enableConnectionFilter?: boolean;
19
+ enableLtree?: boolean;
20
+ enableLlm?: boolean;
21
+ }
22
+ /**
23
+ * Create a Constructive PostGraphile v5 Preset.
24
+ *
25
+ * Accepts optional feature flags (`ConstructivePresetOptions`) that map 1-to-1
26
+ * with the `database_settings` / `api_settings` tables. When a flag is `true`
27
+ * its corresponding plugin preset is included; when `false` it is omitted.
28
+ *
29
+ * Calling with no arguments produces the same preset as the previous static
30
+ * `ConstructivePreset` (everything on except aggregates and LLM).
31
+ *
32
+ * CORE PRESETS (always included):
33
+ * - MinimalPreset (PostGraphile without Node/Relay)
34
+ * - ConflictDetectorPreset (multi-schema conflict detection)
35
+ * - InflektPreset (custom inflection)
36
+ * - InflectorLoggerPreset (debugging, INFLECTOR_LOG=1)
37
+ * - NoUniqueLookupPreset (primary-key-only lookups)
38
+ * - MetaSchemaPreset (_meta introspection)
39
+ * - SqlExpressionValidatorPreset (@sqlExpression validation)
40
+ * - PgTypeMappingsPreset (email, url, etc.)
41
+ * - RequiredInputPreset (@requiredInput support)
42
+ *
43
+ * FLAG-CONTROLLED PRESETS:
44
+ * - enableConnectionFilter -> ConnectionFilterPreset, EnableAllFilterColumnsPreset
45
+ * - enableManyToMany -> ManyToManyOptInPreset
46
+ * - enableSearch -> UnifiedSearchPreset (tsvector, BM25, pg_trgm, pgvector)
47
+ * - enablePostgis -> GraphilePostgisPreset
48
+ * - enableLtree -> GraphileLtreePreset
49
+ * - enableDirectUploads -> UploadPreset
50
+ * - enablePresignedUploads -> PresignedUrlPreset, BucketProvisionerPreset
51
+ * - enableAggregates -> PgAggregatesPreset (off by default)
52
+ * - enableLlm -> (no plugin yet, reserved for future use)
53
+ *
54
+ * RELATION FILTERS (when enableConnectionFilter is true):
55
+ * - Forward: filter child by parent
56
+ * - Backward: filter parent by children
42
57
  *
43
58
  * USAGE:
44
59
  * ```typescript
45
- * import { ConstructivePreset } from 'graphile-settings/presets';
46
- * import { makePgService } from 'postgraphile/adaptors/pg';
47
- *
48
- * const preset: GraphileConfig.Preset = {
49
- * extends: [ConstructivePreset],
50
- * pgServices: [
51
- * makePgService({
52
- * connectionString: DATABASE_URL,
53
- * schemas: ['public'],
54
- * }),
55
- * ],
60
+ * import { createConstructivePreset, makePgService } from 'graphile-settings';
61
+ *
62
+ * // All defaults (same as previous static ConstructivePreset)
63
+ * const preset = {
64
+ * extends: [createConstructivePreset()],
65
+ * pgServices: [makePgService({ connectionString, schemas })],
66
+ * };
67
+ *
68
+ * // With database_settings feature flags
69
+ * const preset = {
70
+ * extends: [createConstructivePreset({ enableAggregates: true, enablePostgis: false })],
71
+ * pgServices: [makePgService({ connectionString, schemas })],
56
72
  * };
57
73
  * ```
58
74
  */
75
+ export declare function createConstructivePreset(options?: ConstructivePresetOptions): GraphileConfig.Preset;
76
+ /**
77
+ * Default Constructive preset -- everything enabled except aggregates and LLM.
78
+ * Backwards-compatible: identical to the previous static ConstructivePreset.
79
+ */
59
80
  export declare const ConstructivePreset: GraphileConfig.Preset;
60
81
  export default ConstructivePreset;
@@ -2,6 +2,7 @@ import { BucketProvisionerPreset } from 'graphile-bucket-provisioner-plugin';
2
2
  import { ConnectionFilterPreset } from 'graphile-connection-filter';
3
3
  import { createFolderOperatorFactory, GraphileLtreePreset } from 'graphile-ltree';
4
4
  import { createPostgisOperatorFactory, GraphilePostgisPreset } from 'graphile-postgis';
5
+ import { PgAggregatesPreset } from 'graphile-pg-aggregates';
5
6
  import { PresignedUrlPreset } from 'graphile-presigned-url-plugin';
6
7
  import { createMatchesOperatorFactory, createTrgmOperatorFactories, UnifiedSearchPreset } from 'graphile-search';
7
8
  import { SqlExpressionValidatorPreset } from 'graphile-sql-expression-validator';
@@ -10,159 +11,166 @@ import { getBucketProvisionerConnection } from '../bucket-provisioner-resolver';
10
11
  import { ConflictDetectorPreset, EnableAllFilterColumnsPreset, InflectorLoggerPreset, InflektPreset, ManyToManyOptInPreset, MetaSchemaPreset, MinimalPreset, NoUniqueLookupPreset, PgTypeMappingsPreset, RequiredInputPreset } from '../plugins';
11
12
  import { createBucketNameResolver, createEnsureBucketProvisioned, getAllowedOrigins, getPresignedUrlS3Config } from '../presigned-url-resolver';
12
13
  import { constructiveUploadFieldDefinitions } from '../upload-resolver';
14
+ const DEFAULTS = {
15
+ enableAggregates: false,
16
+ enablePostgis: true,
17
+ enableSearch: true,
18
+ enableDirectUploads: true,
19
+ enablePresignedUploads: true,
20
+ enableManyToMany: true,
21
+ enableConnectionFilter: true,
22
+ enableLtree: true,
23
+ enableLlm: false,
24
+ };
13
25
  /**
14
- * Constructive PostGraphile v5 Preset
26
+ * Create a Constructive PostGraphile v5 Preset.
27
+ *
28
+ * Accepts optional feature flags (`ConstructivePresetOptions`) that map 1-to-1
29
+ * with the `database_settings` / `api_settings` tables. When a flag is `true`
30
+ * its corresponding plugin preset is included; when `false` it is omitted.
31
+ *
32
+ * Calling with no arguments produces the same preset as the previous static
33
+ * `ConstructivePreset` (everything on except aggregates and LLM).
15
34
  *
16
- * This is the main preset that combines all our custom plugins and configurations.
17
- * It provides a clean, opinionated GraphQL API built from PostgreSQL.
35
+ * CORE PRESETS (always included):
36
+ * - MinimalPreset (PostGraphile without Node/Relay)
37
+ * - ConflictDetectorPreset (multi-schema conflict detection)
38
+ * - InflektPreset (custom inflection)
39
+ * - InflectorLoggerPreset (debugging, INFLECTOR_LOG=1)
40
+ * - NoUniqueLookupPreset (primary-key-only lookups)
41
+ * - MetaSchemaPreset (_meta introspection)
42
+ * - SqlExpressionValidatorPreset (@sqlExpression validation)
43
+ * - PgTypeMappingsPreset (email, url, etc.)
44
+ * - RequiredInputPreset (@requiredInput support)
18
45
  *
19
- * FEATURES:
20
- * - No Node/Relay features (keeps `id` as `id`, no global object identification)
21
- * - Custom inflection using inflekt library
22
- * - Conflict detection for multi-schema setups
23
- * - Inflector logging for debugging (enable with INFLECTOR_LOG=1)
24
- * - Primary key only lookups (no *ByEmail, *ByUsername, etc.)
25
- * - Connection filter plugin with all columns filterable
26
- * - Many-to-many relationships (opt-in via @behavior +manyToMany)
27
- * - Meta schema plugin (_meta query for introspection of tables, fields, indexes)
28
- * - PostGIS support (geometry/geography types, GeoJSON scalar auto-detects PostGIS extension)
29
- * - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
30
- * - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
31
- * - Presigned URL plugin (requestUploadUrl mutation + downloadUrl computed field)
32
- * - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
33
- * CORS management, provisionBucket mutation for manual/retry)
34
- * - SQL expression validator (validates @sqlExpression columns in mutations)
35
- * - PG type mappings (maps custom types like email, url to GraphQL scalars)
36
- * - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
37
- * orderBy distance — zero config)
38
- * - pg_textsearch BM25 search (auto-discovers BM25 indexes: filter fields, score computed fields,
39
- * orderBy score — zero config)
40
- * - pg_trgm fuzzy matching (similarTo/wordSimilarTo on text columns, similarity score fields,
41
- * orderBy similarity — zero config, typo-tolerant)
42
- * - ltree support (auto-detects ltree columns, LTree scalar with file-path syntax,
43
- * containment/glob filters — within, ancestorOf, glob)
44
- * - Aggregates (OPTIONAL — not included by default; add PgAggregatesPreset to extends to enable.
45
- * Provides sum, avg, min, max, stddev, variance, distinctCount on connections,
46
- * groupedAggregates with groupBy + having, orderBy relational aggregates,
47
- * filter by relational aggregates — per-table opt-out via @behavior -aggregates)
46
+ * FLAG-CONTROLLED PRESETS:
47
+ * - enableConnectionFilter -> ConnectionFilterPreset, EnableAllFilterColumnsPreset
48
+ * - enableManyToMany -> ManyToManyOptInPreset
49
+ * - enableSearch -> UnifiedSearchPreset (tsvector, BM25, pg_trgm, pgvector)
50
+ * - enablePostgis -> GraphilePostgisPreset
51
+ * - enableLtree -> GraphileLtreePreset
52
+ * - enableDirectUploads -> UploadPreset
53
+ * - enablePresignedUploads -> PresignedUrlPreset, BucketProvisionerPreset
54
+ * - enableAggregates -> PgAggregatesPreset (off by default)
55
+ * - enableLlm -> (no plugin yet, reserved for future use)
48
56
  *
49
- * RELATION FILTERS:
50
- * - Enabled via connectionFilterRelations: true
51
- * - Forward: filter child by parent (e.g. allOrders(where: { clientByClientId: { name: { startsWith: "Acme" } } }))
52
- * - Backward: filter parent by children (e.g. allClients(where: { ordersByClientId: { some: { total: { greaterThan: 1000 } } } }))
57
+ * RELATION FILTERS (when enableConnectionFilter is true):
58
+ * - Forward: filter child by parent
59
+ * - Backward: filter parent by children
53
60
  *
54
61
  * USAGE:
55
62
  * ```typescript
56
- * import { ConstructivePreset } from 'graphile-settings/presets';
57
- * import { makePgService } from 'postgraphile/adaptors/pg';
63
+ * import { createConstructivePreset, makePgService } from 'graphile-settings';
58
64
  *
59
- * const preset: GraphileConfig.Preset = {
60
- * extends: [ConstructivePreset],
61
- * pgServices: [
62
- * makePgService({
63
- * connectionString: DATABASE_URL,
64
- * schemas: ['public'],
65
- * }),
66
- * ],
65
+ * // All defaults (same as previous static ConstructivePreset)
66
+ * const preset = {
67
+ * extends: [createConstructivePreset()],
68
+ * pgServices: [makePgService({ connectionString, schemas })],
69
+ * };
70
+ *
71
+ * // With database_settings feature flags
72
+ * const preset = {
73
+ * extends: [createConstructivePreset({ enableAggregates: true, enablePostgis: false })],
74
+ * pgServices: [makePgService({ connectionString, schemas })],
67
75
  * };
68
76
  * ```
69
77
  */
70
- export const ConstructivePreset = {
71
- extends: [
78
+ export function createConstructivePreset(options) {
79
+ const opts = { ...DEFAULTS, ...options };
80
+ // ----- extends array -----
81
+ const presets = [
82
+ // Core (always on)
72
83
  MinimalPreset,
73
84
  ConflictDetectorPreset,
74
85
  InflektPreset,
75
86
  InflectorLoggerPreset,
76
87
  NoUniqueLookupPreset,
77
- ConnectionFilterPreset({ connectionFilterRelations: true }),
78
- EnableAllFilterColumnsPreset,
79
- ManyToManyOptInPreset,
80
88
  MetaSchemaPreset,
81
- UnifiedSearchPreset({ fullTextScalarName: 'FullText', tsConfig: 'english' }),
82
- GraphilePostgisPreset,
83
- GraphileLtreePreset,
84
- UploadPreset({
89
+ SqlExpressionValidatorPreset(),
90
+ PgTypeMappingsPreset,
91
+ RequiredInputPreset,
92
+ ];
93
+ if (opts.enableConnectionFilter) {
94
+ presets.push(ConnectionFilterPreset({ connectionFilterRelations: true }), EnableAllFilterColumnsPreset);
95
+ }
96
+ if (opts.enableManyToMany) {
97
+ presets.push(ManyToManyOptInPreset);
98
+ }
99
+ if (opts.enableSearch) {
100
+ presets.push(UnifiedSearchPreset({ fullTextScalarName: 'FullText', tsConfig: 'english' }));
101
+ }
102
+ if (opts.enablePostgis) {
103
+ presets.push(GraphilePostgisPreset);
104
+ }
105
+ if (opts.enableLtree) {
106
+ presets.push(GraphileLtreePreset);
107
+ }
108
+ if (opts.enableDirectUploads) {
109
+ presets.push(UploadPreset({
85
110
  uploadFieldDefinitions: constructiveUploadFieldDefinitions,
86
- maxFileSize: 10 * 1024 * 1024 // 10MB
87
- }),
88
- PresignedUrlPreset({
111
+ maxFileSize: 10 * 1024 * 1024, // 10MB
112
+ }));
113
+ }
114
+ if (opts.enablePresignedUploads) {
115
+ presets.push(PresignedUrlPreset({
89
116
  s3: getPresignedUrlS3Config,
90
117
  resolveBucketName: createBucketNameResolver(),
91
- ensureBucketProvisioned: createEnsureBucketProvisioned()
92
- }),
93
- BucketProvisionerPreset({
118
+ ensureBucketProvisioned: createEnsureBucketProvisioned(),
119
+ }), BucketProvisionerPreset({
94
120
  connection: getBucketProvisionerConnection,
95
- allowedOrigins: getAllowedOrigins()
96
- }),
97
- SqlExpressionValidatorPreset(),
98
- PgTypeMappingsPreset,
99
- RequiredInputPreset
100
- ],
101
- /**
102
- * Disable PostGraphile core's condition argument entirely.
103
- * All filtering now lives under the `where` argument via our v5-native
104
- * graphile-connection-filter plugin (which renames the default `filter`
105
- * argument to `where` via `connectionFilterArgumentName: 'where'`).
106
- * Search, BM25, pgvector, and PostGIS filter fields all hook into
107
- * `isPgConnectionFilter` instead of `isPgCondition`.
108
- */
109
- disablePlugins: [
110
- 'PgConditionArgumentPlugin',
111
- 'PgConditionCustomFieldsPlugin'
112
- ],
113
- /**
114
- * Connection Filter Plugin Configuration
115
- *
116
- * These options control what fields appear in the `where` argument on connections.
117
- * Our v5-native graphile-connection-filter plugin controls relation filters via the
118
- * `connectionFilterRelations` option passed to ConnectionFilterPreset().
119
- *
120
- * NOTE: By default, PostGraphile v5 only allows filtering on INDEXED columns.
121
- * We override this with EnableAllFilterColumnsPreset to allow filtering on ALL columns.
122
- * This gives developers flexibility but requires monitoring for slow queries on
123
- * non-indexed columns.
124
- */
125
- schema: {
126
- /**
127
- * connectionFilterComputedColumns: false
128
- * Disables filtering on computed columns (functions that return a value for a row).
129
- * Computed columns can be expensive to filter on since they may not be indexed.
130
- * To selectively enable, use `@filterable` smart tag on specific functions.
131
- */
132
- connectionFilterComputedColumns: false,
133
- /**
134
- * connectionFilterSetofFunctions: false
135
- * Disables filtering on functions that return `setof` (multiple rows).
136
- * These can be expensive operations. To selectively enable, use `@filterable` smart tag.
137
- */
138
- connectionFilterSetofFunctions: false,
139
- /**
140
- * connectionFilterLogicalOperators: true (default)
141
- * Keeps `and`, `or`, `not` operators for combining filter conditions.
142
- * Example: where: { or: [{ name: { eq: "foo" } }, { name: { eq: "bar" } }] }
143
- */
144
- connectionFilterLogicalOperators: true,
145
- /**
146
- * connectionFilterArrays: true (default)
147
- * Allows filtering on PostgreSQL array columns.
148
- * Example: where: { tags: { contains: ["important"] } }
149
- */
150
- connectionFilterArrays: true,
151
- /**
152
- * connectionFilterOperatorFactories
153
- * Aggregates all satellite plugin operator factories into a single array.
154
- * graphile-config replaces (not concatenates) arrays when merging presets,
155
- * so we must explicitly collect all factories here at the top level.
156
- */
157
- connectionFilterOperatorFactories: [
158
- createMatchesOperatorFactory('FullText', 'english'),
159
- createTrgmOperatorFactories(),
160
- createPostgisOperatorFactory(),
161
- createFolderOperatorFactory()
162
- ]
163
- // NOTE: The UnifiedSearchPreset also registers matches + trgm operator factories.
164
- // graphile-config merges arrays from presets, so having them here as well is fine
165
- // and ensures they're present even if the preset order changes.
121
+ allowedOrigins: getAllowedOrigins(),
122
+ }));
166
123
  }
167
- };
124
+ if (opts.enableAggregates) {
125
+ presets.push(PgAggregatesPreset);
126
+ }
127
+ // ----- connectionFilterOperatorFactories -----
128
+ // Only include operator factories for features that are actually enabled.
129
+ // graphile-config replaces (not concatenates) arrays when merging presets,
130
+ // so we collect all active factories into a single top-level array.
131
+ const operatorFactories = [];
132
+ if (opts.enableConnectionFilter) {
133
+ if (opts.enableSearch) {
134
+ operatorFactories.push(createMatchesOperatorFactory('FullText', 'english'), createTrgmOperatorFactories());
135
+ }
136
+ if (opts.enablePostgis) {
137
+ operatorFactories.push(createPostgisOperatorFactory());
138
+ }
139
+ if (opts.enableLtree) {
140
+ operatorFactories.push(createFolderOperatorFactory());
141
+ }
142
+ }
143
+ // ----- disablePlugins -----
144
+ // When connection filter is enabled it replaces the built-in condition arg.
145
+ const disablePlugins = [];
146
+ if (opts.enableConnectionFilter) {
147
+ disablePlugins.push('PgConditionArgumentPlugin', 'PgConditionCustomFieldsPlugin');
148
+ }
149
+ // ----- schema options -----
150
+ const schema = {};
151
+ if (opts.enableConnectionFilter) {
152
+ schema.connectionFilterComputedColumns = false;
153
+ schema.connectionFilterSetofFunctions = false;
154
+ schema.connectionFilterLogicalOperators = true;
155
+ schema.connectionFilterArrays = true;
156
+ if (operatorFactories.length > 0) {
157
+ schema.connectionFilterOperatorFactories = operatorFactories;
158
+ }
159
+ }
160
+ const preset = {
161
+ extends: presets,
162
+ };
163
+ if (disablePlugins.length > 0) {
164
+ preset.disablePlugins = disablePlugins;
165
+ }
166
+ if (Object.keys(schema).length > 0) {
167
+ preset.schema = schema;
168
+ }
169
+ return preset;
170
+ }
171
+ /**
172
+ * Default Constructive preset -- everything enabled except aggregates and LLM.
173
+ * Backwards-compatible: identical to the previous static ConstructivePreset.
174
+ */
175
+ export const ConstructivePreset = createConstructivePreset();
168
176
  export default ConstructivePreset;
@@ -4,4 +4,5 @@
4
4
  * This module exports pre-configured presets that combine multiple plugins
5
5
  * for common use cases.
6
6
  */
7
- export { ConstructivePreset } from './constructive-preset';
7
+ export { ConstructivePreset, createConstructivePreset } from './constructive-preset';
8
+ export type { ConstructivePresetOptions } from './constructive-preset';
@@ -4,4 +4,4 @@
4
4
  * This module exports pre-configured presets that combine multiple plugins
5
5
  * for common use cases.
6
6
  */
7
- export { ConstructivePreset } from './constructive-preset';
7
+ export { ConstructivePreset, createConstructivePreset } from './constructive-preset';
package/index.d.ts CHANGED
@@ -29,7 +29,8 @@
29
29
  import { makePgService } from 'postgraphile/adaptors/pg';
30
30
  import 'postgraphile/grafserv';
31
31
  import 'graphile-build';
32
- export { ConstructivePreset } from './presets/constructive-preset';
32
+ export { ConstructivePreset, createConstructivePreset } from './presets/constructive-preset';
33
+ export type { ConstructivePresetOptions } from './presets/constructive-preset';
33
34
  export * from './plugins/index';
34
35
  export * from './presets/index';
35
36
  export { makePgService };
package/index.js CHANGED
@@ -42,7 +42,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
42
42
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.getBucketProvisionerConnection = exports.getPresignedUrlS3Config = exports.streamToStorage = exports.makePgService = exports.ConstructivePreset = void 0;
45
+ exports.getBucketProvisionerConnection = exports.getPresignedUrlS3Config = exports.streamToStorage = exports.makePgService = exports.createConstructivePreset = exports.ConstructivePreset = void 0;
46
46
  const pg_1 = require("postgraphile/adaptors/pg");
47
47
  Object.defineProperty(exports, "makePgService", { enumerable: true, get: function () { return pg_1.makePgService; } });
48
48
  // Import modules for type augmentation
@@ -55,9 +55,10 @@ require("graphile-build");
55
55
  // ============================================================================
56
56
  // Re-export all plugins and presets
57
57
  // ============================================================================
58
- // Main preset
58
+ // Main preset + factory
59
59
  var constructive_preset_1 = require("./presets/constructive-preset");
60
60
  Object.defineProperty(exports, "ConstructivePreset", { enumerable: true, get: function () { return constructive_preset_1.ConstructivePreset; } });
61
+ Object.defineProperty(exports, "createConstructivePreset", { enumerable: true, get: function () { return constructive_preset_1.createConstructivePreset; } });
61
62
  // Re-export all plugins for convenience
62
63
  __exportStar(require("./plugins/index"), exports);
63
64
  // Re-export presets
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "graphile-settings",
3
- "version": "4.30.2",
3
+ "version": "4.31.1",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "graphile settings",
6
6
  "main": "index.js",
@@ -50,12 +50,12 @@
50
50
  "graphile-build": "5.0.0",
51
51
  "graphile-build-pg": "5.0.0",
52
52
  "graphile-config": "1.0.0",
53
- "graphile-connection-filter": "^1.8.1",
54
- "graphile-ltree": "^1.5.1",
55
- "graphile-pg-aggregates": "^1.1.1",
56
- "graphile-postgis": "^2.14.1",
53
+ "graphile-connection-filter": "^1.8.2",
54
+ "graphile-ltree": "^1.5.2",
55
+ "graphile-pg-aggregates": "^1.1.2",
56
+ "graphile-postgis": "^2.14.2",
57
57
  "graphile-presigned-url-plugin": "^0.16.1",
58
- "graphile-search": "^1.10.1",
58
+ "graphile-search": "^1.10.2",
59
59
  "graphile-sql-expression-validator": "^2.10.0",
60
60
  "graphile-upload-plugin": "^2.9.0",
61
61
  "graphile-utils": "5.0.0",
@@ -74,7 +74,7 @@
74
74
  "@types/express": "^5.0.6",
75
75
  "@types/pg": "^8.18.0",
76
76
  "@types/request-ip": "^0.0.41",
77
- "graphile-test": "^4.12.1",
77
+ "graphile-test": "^4.13.0",
78
78
  "makage": "^0.3.0",
79
79
  "nodemon": "^3.1.14",
80
80
  "ts-node": "^10.9.2"
@@ -86,5 +86,5 @@
86
86
  "constructive",
87
87
  "graphql"
88
88
  ],
89
- "gitHead": "0fcb26c8f3379de5c2bf486e7ad78bb61a76e497"
89
+ "gitHead": "90016935b53d6fb84e0b83879377f0c2eb9abce6"
90
90
  }
@@ -1,60 +1,81 @@
1
1
  import type { GraphileConfig } from 'graphile-config';
2
2
  /**
3
- * Constructive PostGraphile v5 Preset
4
- *
5
- * This is the main preset that combines all our custom plugins and configurations.
6
- * It provides a clean, opinionated GraphQL API built from PostgreSQL.
7
- *
8
- * FEATURES:
9
- * - No Node/Relay features (keeps `id` as `id`, no global object identification)
10
- * - Custom inflection using inflekt library
11
- * - Conflict detection for multi-schema setups
12
- * - Inflector logging for debugging (enable with INFLECTOR_LOG=1)
13
- * - Primary key only lookups (no *ByEmail, *ByUsername, etc.)
14
- * - Connection filter plugin with all columns filterable
15
- * - Many-to-many relationships (opt-in via @behavior +manyToMany)
16
- * - Meta schema plugin (_meta query for introspection of tables, fields, indexes)
17
- * - PostGIS support (geometry/geography types, GeoJSON scalar — auto-detects PostGIS extension)
18
- * - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
19
- * - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
20
- * - Presigned URL plugin (requestUploadUrl mutation + downloadUrl computed field)
21
- * - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
22
- * CORS management, provisionBucket mutation for manual/retry)
23
- * - SQL expression validator (validates @sqlExpression columns in mutations)
24
- * - PG type mappings (maps custom types like email, url to GraphQL scalars)
25
- * - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
26
- * orderBy distance zero config)
27
- * - pg_textsearch BM25 search (auto-discovers BM25 indexes: filter fields, score computed fields,
28
- * orderBy score — zero config)
29
- * - pg_trgm fuzzy matching (similarTo/wordSimilarTo on text columns, similarity score fields,
30
- * orderBy similarity zero config, typo-tolerant)
31
- * - ltree support (auto-detects ltree columns, LTree scalar with file-path syntax,
32
- * containment/glob filters within, ancestorOf, glob)
33
- * - Aggregates (OPTIONAL not included by default; add PgAggregatesPreset to extends to enable.
34
- * Provides sum, avg, min, max, stddev, variance, distinctCount on connections,
35
- * groupedAggregates with groupBy + having, orderBy relational aggregates,
36
- * filter by relational aggregates — per-table opt-out via @behavior -aggregates)
37
- *
38
- * RELATION FILTERS:
39
- * - Enabled via connectionFilterRelations: true
40
- * - Forward: filter child by parent (e.g. allOrders(where: { clientByClientId: { name: { startsWith: "Acme" } } }))
41
- * - Backward: filter parent by children (e.g. allClients(where: { ordersByClientId: { some: { total: { greaterThan: 1000 } } } }))
3
+ * Feature flags that control which optional Graphile plugins are included
4
+ * in the preset. Mirrors the `database_settings` / `api_settings` cascade
5
+ * from the services DB.
6
+ *
7
+ * Every flag defaults to the value that matches the current production
8
+ * behavior so that `createConstructivePreset()` (no args) is identical to
9
+ * the previous static `ConstructivePreset`.
10
+ */
11
+ export interface ConstructivePresetOptions {
12
+ enableAggregates?: boolean;
13
+ enablePostgis?: boolean;
14
+ enableSearch?: boolean;
15
+ enableDirectUploads?: boolean;
16
+ enablePresignedUploads?: boolean;
17
+ enableManyToMany?: boolean;
18
+ enableConnectionFilter?: boolean;
19
+ enableLtree?: boolean;
20
+ enableLlm?: boolean;
21
+ }
22
+ /**
23
+ * Create a Constructive PostGraphile v5 Preset.
24
+ *
25
+ * Accepts optional feature flags (`ConstructivePresetOptions`) that map 1-to-1
26
+ * with the `database_settings` / `api_settings` tables. When a flag is `true`
27
+ * its corresponding plugin preset is included; when `false` it is omitted.
28
+ *
29
+ * Calling with no arguments produces the same preset as the previous static
30
+ * `ConstructivePreset` (everything on except aggregates and LLM).
31
+ *
32
+ * CORE PRESETS (always included):
33
+ * - MinimalPreset (PostGraphile without Node/Relay)
34
+ * - ConflictDetectorPreset (multi-schema conflict detection)
35
+ * - InflektPreset (custom inflection)
36
+ * - InflectorLoggerPreset (debugging, INFLECTOR_LOG=1)
37
+ * - NoUniqueLookupPreset (primary-key-only lookups)
38
+ * - MetaSchemaPreset (_meta introspection)
39
+ * - SqlExpressionValidatorPreset (@sqlExpression validation)
40
+ * - PgTypeMappingsPreset (email, url, etc.)
41
+ * - RequiredInputPreset (@requiredInput support)
42
+ *
43
+ * FLAG-CONTROLLED PRESETS:
44
+ * - enableConnectionFilter -> ConnectionFilterPreset, EnableAllFilterColumnsPreset
45
+ * - enableManyToMany -> ManyToManyOptInPreset
46
+ * - enableSearch -> UnifiedSearchPreset (tsvector, BM25, pg_trgm, pgvector)
47
+ * - enablePostgis -> GraphilePostgisPreset
48
+ * - enableLtree -> GraphileLtreePreset
49
+ * - enableDirectUploads -> UploadPreset
50
+ * - enablePresignedUploads -> PresignedUrlPreset, BucketProvisionerPreset
51
+ * - enableAggregates -> PgAggregatesPreset (off by default)
52
+ * - enableLlm -> (no plugin yet, reserved for future use)
53
+ *
54
+ * RELATION FILTERS (when enableConnectionFilter is true):
55
+ * - Forward: filter child by parent
56
+ * - Backward: filter parent by children
42
57
  *
43
58
  * USAGE:
44
59
  * ```typescript
45
- * import { ConstructivePreset } from 'graphile-settings/presets';
46
- * import { makePgService } from 'postgraphile/adaptors/pg';
47
- *
48
- * const preset: GraphileConfig.Preset = {
49
- * extends: [ConstructivePreset],
50
- * pgServices: [
51
- * makePgService({
52
- * connectionString: DATABASE_URL,
53
- * schemas: ['public'],
54
- * }),
55
- * ],
60
+ * import { createConstructivePreset, makePgService } from 'graphile-settings';
61
+ *
62
+ * // All defaults (same as previous static ConstructivePreset)
63
+ * const preset = {
64
+ * extends: [createConstructivePreset()],
65
+ * pgServices: [makePgService({ connectionString, schemas })],
66
+ * };
67
+ *
68
+ * // With database_settings feature flags
69
+ * const preset = {
70
+ * extends: [createConstructivePreset({ enableAggregates: true, enablePostgis: false })],
71
+ * pgServices: [makePgService({ connectionString, schemas })],
56
72
  * };
57
73
  * ```
58
74
  */
75
+ export declare function createConstructivePreset(options?: ConstructivePresetOptions): GraphileConfig.Preset;
76
+ /**
77
+ * Default Constructive preset -- everything enabled except aggregates and LLM.
78
+ * Backwards-compatible: identical to the previous static ConstructivePreset.
79
+ */
59
80
  export declare const ConstructivePreset: GraphileConfig.Preset;
60
81
  export default ConstructivePreset;
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ConstructivePreset = void 0;
4
+ exports.createConstructivePreset = createConstructivePreset;
4
5
  const graphile_bucket_provisioner_plugin_1 = require("graphile-bucket-provisioner-plugin");
5
6
  const graphile_connection_filter_1 = require("graphile-connection-filter");
6
7
  const graphile_ltree_1 = require("graphile-ltree");
7
8
  const graphile_postgis_1 = require("graphile-postgis");
9
+ const graphile_pg_aggregates_1 = require("graphile-pg-aggregates");
8
10
  const graphile_presigned_url_plugin_1 = require("graphile-presigned-url-plugin");
9
11
  const graphile_search_1 = require("graphile-search");
10
12
  const graphile_sql_expression_validator_1 = require("graphile-sql-expression-validator");
@@ -13,159 +15,166 @@ const bucket_provisioner_resolver_1 = require("../bucket-provisioner-resolver");
13
15
  const plugins_1 = require("../plugins");
14
16
  const presigned_url_resolver_1 = require("../presigned-url-resolver");
15
17
  const upload_resolver_1 = require("../upload-resolver");
18
+ const DEFAULTS = {
19
+ enableAggregates: false,
20
+ enablePostgis: true,
21
+ enableSearch: true,
22
+ enableDirectUploads: true,
23
+ enablePresignedUploads: true,
24
+ enableManyToMany: true,
25
+ enableConnectionFilter: true,
26
+ enableLtree: true,
27
+ enableLlm: false,
28
+ };
16
29
  /**
17
- * Constructive PostGraphile v5 Preset
30
+ * Create a Constructive PostGraphile v5 Preset.
31
+ *
32
+ * Accepts optional feature flags (`ConstructivePresetOptions`) that map 1-to-1
33
+ * with the `database_settings` / `api_settings` tables. When a flag is `true`
34
+ * its corresponding plugin preset is included; when `false` it is omitted.
35
+ *
36
+ * Calling with no arguments produces the same preset as the previous static
37
+ * `ConstructivePreset` (everything on except aggregates and LLM).
18
38
  *
19
- * This is the main preset that combines all our custom plugins and configurations.
20
- * It provides a clean, opinionated GraphQL API built from PostgreSQL.
39
+ * CORE PRESETS (always included):
40
+ * - MinimalPreset (PostGraphile without Node/Relay)
41
+ * - ConflictDetectorPreset (multi-schema conflict detection)
42
+ * - InflektPreset (custom inflection)
43
+ * - InflectorLoggerPreset (debugging, INFLECTOR_LOG=1)
44
+ * - NoUniqueLookupPreset (primary-key-only lookups)
45
+ * - MetaSchemaPreset (_meta introspection)
46
+ * - SqlExpressionValidatorPreset (@sqlExpression validation)
47
+ * - PgTypeMappingsPreset (email, url, etc.)
48
+ * - RequiredInputPreset (@requiredInput support)
21
49
  *
22
- * FEATURES:
23
- * - No Node/Relay features (keeps `id` as `id`, no global object identification)
24
- * - Custom inflection using inflekt library
25
- * - Conflict detection for multi-schema setups
26
- * - Inflector logging for debugging (enable with INFLECTOR_LOG=1)
27
- * - Primary key only lookups (no *ByEmail, *ByUsername, etc.)
28
- * - Connection filter plugin with all columns filterable
29
- * - Many-to-many relationships (opt-in via @behavior +manyToMany)
30
- * - Meta schema plugin (_meta query for introspection of tables, fields, indexes)
31
- * - PostGIS support (geometry/geography types, GeoJSON scalar auto-detects PostGIS extension)
32
- * - PostGIS connection filter operators (spatial filtering on geometry/geography columns)
33
- * - Upload plugin (file upload to S3/MinIO for image, upload, attachment domain columns)
34
- * - Presigned URL plugin (requestUploadUrl mutation + downloadUrl computed field)
35
- * - Bucket provisioner plugin (auto-provisions S3 buckets on @storageBuckets table mutations,
36
- * CORS management, provisionBucket mutation for manual/retry)
37
- * - SQL expression validator (validates @sqlExpression columns in mutations)
38
- * - PG type mappings (maps custom types like email, url to GraphQL scalars)
39
- * - pgvector search (auto-discovers vector columns: filter fields, distance computed fields,
40
- * orderBy distance — zero config)
41
- * - pg_textsearch BM25 search (auto-discovers BM25 indexes: filter fields, score computed fields,
42
- * orderBy score — zero config)
43
- * - pg_trgm fuzzy matching (similarTo/wordSimilarTo on text columns, similarity score fields,
44
- * orderBy similarity — zero config, typo-tolerant)
45
- * - ltree support (auto-detects ltree columns, LTree scalar with file-path syntax,
46
- * containment/glob filters — within, ancestorOf, glob)
47
- * - Aggregates (OPTIONAL — not included by default; add PgAggregatesPreset to extends to enable.
48
- * Provides sum, avg, min, max, stddev, variance, distinctCount on connections,
49
- * groupedAggregates with groupBy + having, orderBy relational aggregates,
50
- * filter by relational aggregates — per-table opt-out via @behavior -aggregates)
50
+ * FLAG-CONTROLLED PRESETS:
51
+ * - enableConnectionFilter -> ConnectionFilterPreset, EnableAllFilterColumnsPreset
52
+ * - enableManyToMany -> ManyToManyOptInPreset
53
+ * - enableSearch -> UnifiedSearchPreset (tsvector, BM25, pg_trgm, pgvector)
54
+ * - enablePostgis -> GraphilePostgisPreset
55
+ * - enableLtree -> GraphileLtreePreset
56
+ * - enableDirectUploads -> UploadPreset
57
+ * - enablePresignedUploads -> PresignedUrlPreset, BucketProvisionerPreset
58
+ * - enableAggregates -> PgAggregatesPreset (off by default)
59
+ * - enableLlm -> (no plugin yet, reserved for future use)
51
60
  *
52
- * RELATION FILTERS:
53
- * - Enabled via connectionFilterRelations: true
54
- * - Forward: filter child by parent (e.g. allOrders(where: { clientByClientId: { name: { startsWith: "Acme" } } }))
55
- * - Backward: filter parent by children (e.g. allClients(where: { ordersByClientId: { some: { total: { greaterThan: 1000 } } } }))
61
+ * RELATION FILTERS (when enableConnectionFilter is true):
62
+ * - Forward: filter child by parent
63
+ * - Backward: filter parent by children
56
64
  *
57
65
  * USAGE:
58
66
  * ```typescript
59
- * import { ConstructivePreset } from 'graphile-settings/presets';
60
- * import { makePgService } from 'postgraphile/adaptors/pg';
67
+ * import { createConstructivePreset, makePgService } from 'graphile-settings';
61
68
  *
62
- * const preset: GraphileConfig.Preset = {
63
- * extends: [ConstructivePreset],
64
- * pgServices: [
65
- * makePgService({
66
- * connectionString: DATABASE_URL,
67
- * schemas: ['public'],
68
- * }),
69
- * ],
69
+ * // All defaults (same as previous static ConstructivePreset)
70
+ * const preset = {
71
+ * extends: [createConstructivePreset()],
72
+ * pgServices: [makePgService({ connectionString, schemas })],
73
+ * };
74
+ *
75
+ * // With database_settings feature flags
76
+ * const preset = {
77
+ * extends: [createConstructivePreset({ enableAggregates: true, enablePostgis: false })],
78
+ * pgServices: [makePgService({ connectionString, schemas })],
70
79
  * };
71
80
  * ```
72
81
  */
73
- exports.ConstructivePreset = {
74
- extends: [
82
+ function createConstructivePreset(options) {
83
+ const opts = { ...DEFAULTS, ...options };
84
+ // ----- extends array -----
85
+ const presets = [
86
+ // Core (always on)
75
87
  plugins_1.MinimalPreset,
76
88
  plugins_1.ConflictDetectorPreset,
77
89
  plugins_1.InflektPreset,
78
90
  plugins_1.InflectorLoggerPreset,
79
91
  plugins_1.NoUniqueLookupPreset,
80
- (0, graphile_connection_filter_1.ConnectionFilterPreset)({ connectionFilterRelations: true }),
81
- plugins_1.EnableAllFilterColumnsPreset,
82
- plugins_1.ManyToManyOptInPreset,
83
92
  plugins_1.MetaSchemaPreset,
84
- (0, graphile_search_1.UnifiedSearchPreset)({ fullTextScalarName: 'FullText', tsConfig: 'english' }),
85
- graphile_postgis_1.GraphilePostgisPreset,
86
- graphile_ltree_1.GraphileLtreePreset,
87
- (0, graphile_upload_plugin_1.UploadPreset)({
93
+ (0, graphile_sql_expression_validator_1.SqlExpressionValidatorPreset)(),
94
+ plugins_1.PgTypeMappingsPreset,
95
+ plugins_1.RequiredInputPreset,
96
+ ];
97
+ if (opts.enableConnectionFilter) {
98
+ presets.push((0, graphile_connection_filter_1.ConnectionFilterPreset)({ connectionFilterRelations: true }), plugins_1.EnableAllFilterColumnsPreset);
99
+ }
100
+ if (opts.enableManyToMany) {
101
+ presets.push(plugins_1.ManyToManyOptInPreset);
102
+ }
103
+ if (opts.enableSearch) {
104
+ presets.push((0, graphile_search_1.UnifiedSearchPreset)({ fullTextScalarName: 'FullText', tsConfig: 'english' }));
105
+ }
106
+ if (opts.enablePostgis) {
107
+ presets.push(graphile_postgis_1.GraphilePostgisPreset);
108
+ }
109
+ if (opts.enableLtree) {
110
+ presets.push(graphile_ltree_1.GraphileLtreePreset);
111
+ }
112
+ if (opts.enableDirectUploads) {
113
+ presets.push((0, graphile_upload_plugin_1.UploadPreset)({
88
114
  uploadFieldDefinitions: upload_resolver_1.constructiveUploadFieldDefinitions,
89
- maxFileSize: 10 * 1024 * 1024 // 10MB
90
- }),
91
- (0, graphile_presigned_url_plugin_1.PresignedUrlPreset)({
115
+ maxFileSize: 10 * 1024 * 1024, // 10MB
116
+ }));
117
+ }
118
+ if (opts.enablePresignedUploads) {
119
+ presets.push((0, graphile_presigned_url_plugin_1.PresignedUrlPreset)({
92
120
  s3: presigned_url_resolver_1.getPresignedUrlS3Config,
93
121
  resolveBucketName: (0, presigned_url_resolver_1.createBucketNameResolver)(),
94
- ensureBucketProvisioned: (0, presigned_url_resolver_1.createEnsureBucketProvisioned)()
95
- }),
96
- (0, graphile_bucket_provisioner_plugin_1.BucketProvisionerPreset)({
122
+ ensureBucketProvisioned: (0, presigned_url_resolver_1.createEnsureBucketProvisioned)(),
123
+ }), (0, graphile_bucket_provisioner_plugin_1.BucketProvisionerPreset)({
97
124
  connection: bucket_provisioner_resolver_1.getBucketProvisionerConnection,
98
- allowedOrigins: (0, presigned_url_resolver_1.getAllowedOrigins)()
99
- }),
100
- (0, graphile_sql_expression_validator_1.SqlExpressionValidatorPreset)(),
101
- plugins_1.PgTypeMappingsPreset,
102
- plugins_1.RequiredInputPreset
103
- ],
104
- /**
105
- * Disable PostGraphile core's condition argument entirely.
106
- * All filtering now lives under the `where` argument via our v5-native
107
- * graphile-connection-filter plugin (which renames the default `filter`
108
- * argument to `where` via `connectionFilterArgumentName: 'where'`).
109
- * Search, BM25, pgvector, and PostGIS filter fields all hook into
110
- * `isPgConnectionFilter` instead of `isPgCondition`.
111
- */
112
- disablePlugins: [
113
- 'PgConditionArgumentPlugin',
114
- 'PgConditionCustomFieldsPlugin'
115
- ],
116
- /**
117
- * Connection Filter Plugin Configuration
118
- *
119
- * These options control what fields appear in the `where` argument on connections.
120
- * Our v5-native graphile-connection-filter plugin controls relation filters via the
121
- * `connectionFilterRelations` option passed to ConnectionFilterPreset().
122
- *
123
- * NOTE: By default, PostGraphile v5 only allows filtering on INDEXED columns.
124
- * We override this with EnableAllFilterColumnsPreset to allow filtering on ALL columns.
125
- * This gives developers flexibility but requires monitoring for slow queries on
126
- * non-indexed columns.
127
- */
128
- schema: {
129
- /**
130
- * connectionFilterComputedColumns: false
131
- * Disables filtering on computed columns (functions that return a value for a row).
132
- * Computed columns can be expensive to filter on since they may not be indexed.
133
- * To selectively enable, use `@filterable` smart tag on specific functions.
134
- */
135
- connectionFilterComputedColumns: false,
136
- /**
137
- * connectionFilterSetofFunctions: false
138
- * Disables filtering on functions that return `setof` (multiple rows).
139
- * These can be expensive operations. To selectively enable, use `@filterable` smart tag.
140
- */
141
- connectionFilterSetofFunctions: false,
142
- /**
143
- * connectionFilterLogicalOperators: true (default)
144
- * Keeps `and`, `or`, `not` operators for combining filter conditions.
145
- * Example: where: { or: [{ name: { eq: "foo" } }, { name: { eq: "bar" } }] }
146
- */
147
- connectionFilterLogicalOperators: true,
148
- /**
149
- * connectionFilterArrays: true (default)
150
- * Allows filtering on PostgreSQL array columns.
151
- * Example: where: { tags: { contains: ["important"] } }
152
- */
153
- connectionFilterArrays: true,
154
- /**
155
- * connectionFilterOperatorFactories
156
- * Aggregates all satellite plugin operator factories into a single array.
157
- * graphile-config replaces (not concatenates) arrays when merging presets,
158
- * so we must explicitly collect all factories here at the top level.
159
- */
160
- connectionFilterOperatorFactories: [
161
- (0, graphile_search_1.createMatchesOperatorFactory)('FullText', 'english'),
162
- (0, graphile_search_1.createTrgmOperatorFactories)(),
163
- (0, graphile_postgis_1.createPostgisOperatorFactory)(),
164
- (0, graphile_ltree_1.createFolderOperatorFactory)()
165
- ]
166
- // NOTE: The UnifiedSearchPreset also registers matches + trgm operator factories.
167
- // graphile-config merges arrays from presets, so having them here as well is fine
168
- // and ensures they're present even if the preset order changes.
125
+ allowedOrigins: (0, presigned_url_resolver_1.getAllowedOrigins)(),
126
+ }));
169
127
  }
170
- };
128
+ if (opts.enableAggregates) {
129
+ presets.push(graphile_pg_aggregates_1.PgAggregatesPreset);
130
+ }
131
+ // ----- connectionFilterOperatorFactories -----
132
+ // Only include operator factories for features that are actually enabled.
133
+ // graphile-config replaces (not concatenates) arrays when merging presets,
134
+ // so we collect all active factories into a single top-level array.
135
+ const operatorFactories = [];
136
+ if (opts.enableConnectionFilter) {
137
+ if (opts.enableSearch) {
138
+ operatorFactories.push((0, graphile_search_1.createMatchesOperatorFactory)('FullText', 'english'), (0, graphile_search_1.createTrgmOperatorFactories)());
139
+ }
140
+ if (opts.enablePostgis) {
141
+ operatorFactories.push((0, graphile_postgis_1.createPostgisOperatorFactory)());
142
+ }
143
+ if (opts.enableLtree) {
144
+ operatorFactories.push((0, graphile_ltree_1.createFolderOperatorFactory)());
145
+ }
146
+ }
147
+ // ----- disablePlugins -----
148
+ // When connection filter is enabled it replaces the built-in condition arg.
149
+ const disablePlugins = [];
150
+ if (opts.enableConnectionFilter) {
151
+ disablePlugins.push('PgConditionArgumentPlugin', 'PgConditionCustomFieldsPlugin');
152
+ }
153
+ // ----- schema options -----
154
+ const schema = {};
155
+ if (opts.enableConnectionFilter) {
156
+ schema.connectionFilterComputedColumns = false;
157
+ schema.connectionFilterSetofFunctions = false;
158
+ schema.connectionFilterLogicalOperators = true;
159
+ schema.connectionFilterArrays = true;
160
+ if (operatorFactories.length > 0) {
161
+ schema.connectionFilterOperatorFactories = operatorFactories;
162
+ }
163
+ }
164
+ const preset = {
165
+ extends: presets,
166
+ };
167
+ if (disablePlugins.length > 0) {
168
+ preset.disablePlugins = disablePlugins;
169
+ }
170
+ if (Object.keys(schema).length > 0) {
171
+ preset.schema = schema;
172
+ }
173
+ return preset;
174
+ }
175
+ /**
176
+ * Default Constructive preset -- everything enabled except aggregates and LLM.
177
+ * Backwards-compatible: identical to the previous static ConstructivePreset.
178
+ */
179
+ exports.ConstructivePreset = createConstructivePreset();
171
180
  exports.default = exports.ConstructivePreset;
@@ -4,4 +4,5 @@
4
4
  * This module exports pre-configured presets that combine multiple plugins
5
5
  * for common use cases.
6
6
  */
7
- export { ConstructivePreset } from './constructive-preset';
7
+ export { ConstructivePreset, createConstructivePreset } from './constructive-preset';
8
+ export type { ConstructivePresetOptions } from './constructive-preset';
package/presets/index.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * for common use cases.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.ConstructivePreset = void 0;
9
+ exports.createConstructivePreset = exports.ConstructivePreset = void 0;
10
10
  var constructive_preset_1 = require("./constructive-preset");
11
11
  Object.defineProperty(exports, "ConstructivePreset", { enumerable: true, get: function () { return constructive_preset_1.ConstructivePreset; } });
12
+ Object.defineProperty(exports, "createConstructivePreset", { enumerable: true, get: function () { return constructive_preset_1.createConstructivePreset; } });