graphile-connection-filter 1.1.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.
Files changed (71) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +107 -0
  3. package/augmentations.d.ts +104 -0
  4. package/augmentations.js +11 -0
  5. package/esm/augmentations.d.ts +104 -0
  6. package/esm/augmentations.js +9 -0
  7. package/esm/index.d.ts +55 -0
  8. package/esm/index.js +56 -0
  9. package/esm/plugins/ConnectionFilterArgPlugin.d.ts +13 -0
  10. package/esm/plugins/ConnectionFilterArgPlugin.js +96 -0
  11. package/esm/plugins/ConnectionFilterAttributesPlugin.d.ts +14 -0
  12. package/esm/plugins/ConnectionFilterAttributesPlugin.js +79 -0
  13. package/esm/plugins/ConnectionFilterBackwardRelationsPlugin.d.ts +33 -0
  14. package/esm/plugins/ConnectionFilterBackwardRelationsPlugin.js +398 -0
  15. package/esm/plugins/ConnectionFilterComputedAttributesPlugin.d.ts +19 -0
  16. package/esm/plugins/ConnectionFilterComputedAttributesPlugin.js +133 -0
  17. package/esm/plugins/ConnectionFilterCustomOperatorsPlugin.d.ts +35 -0
  18. package/esm/plugins/ConnectionFilterCustomOperatorsPlugin.js +129 -0
  19. package/esm/plugins/ConnectionFilterForwardRelationsPlugin.d.ts +28 -0
  20. package/esm/plugins/ConnectionFilterForwardRelationsPlugin.js +168 -0
  21. package/esm/plugins/ConnectionFilterInflectionPlugin.d.ts +11 -0
  22. package/esm/plugins/ConnectionFilterInflectionPlugin.js +27 -0
  23. package/esm/plugins/ConnectionFilterLogicalOperatorsPlugin.d.ts +15 -0
  24. package/esm/plugins/ConnectionFilterLogicalOperatorsPlugin.js +86 -0
  25. package/esm/plugins/ConnectionFilterOperatorsPlugin.d.ts +21 -0
  26. package/esm/plugins/ConnectionFilterOperatorsPlugin.js +677 -0
  27. package/esm/plugins/ConnectionFilterTypesPlugin.d.ts +12 -0
  28. package/esm/plugins/ConnectionFilterTypesPlugin.js +225 -0
  29. package/esm/plugins/index.d.ts +11 -0
  30. package/esm/plugins/index.js +11 -0
  31. package/esm/plugins/operatorApply.d.ts +11 -0
  32. package/esm/plugins/operatorApply.js +70 -0
  33. package/esm/preset.d.ts +35 -0
  34. package/esm/preset.js +72 -0
  35. package/esm/types.d.ts +146 -0
  36. package/esm/types.js +4 -0
  37. package/esm/utils.d.ts +44 -0
  38. package/esm/utils.js +112 -0
  39. package/index.d.ts +55 -0
  40. package/index.js +77 -0
  41. package/package.json +58 -0
  42. package/plugins/ConnectionFilterArgPlugin.d.ts +13 -0
  43. package/plugins/ConnectionFilterArgPlugin.js +99 -0
  44. package/plugins/ConnectionFilterAttributesPlugin.d.ts +14 -0
  45. package/plugins/ConnectionFilterAttributesPlugin.js +82 -0
  46. package/plugins/ConnectionFilterBackwardRelationsPlugin.d.ts +33 -0
  47. package/plugins/ConnectionFilterBackwardRelationsPlugin.js +401 -0
  48. package/plugins/ConnectionFilterComputedAttributesPlugin.d.ts +19 -0
  49. package/plugins/ConnectionFilterComputedAttributesPlugin.js +136 -0
  50. package/plugins/ConnectionFilterCustomOperatorsPlugin.d.ts +35 -0
  51. package/plugins/ConnectionFilterCustomOperatorsPlugin.js +132 -0
  52. package/plugins/ConnectionFilterForwardRelationsPlugin.d.ts +28 -0
  53. package/plugins/ConnectionFilterForwardRelationsPlugin.js +171 -0
  54. package/plugins/ConnectionFilterInflectionPlugin.d.ts +11 -0
  55. package/plugins/ConnectionFilterInflectionPlugin.js +30 -0
  56. package/plugins/ConnectionFilterLogicalOperatorsPlugin.d.ts +15 -0
  57. package/plugins/ConnectionFilterLogicalOperatorsPlugin.js +89 -0
  58. package/plugins/ConnectionFilterOperatorsPlugin.d.ts +21 -0
  59. package/plugins/ConnectionFilterOperatorsPlugin.js +680 -0
  60. package/plugins/ConnectionFilterTypesPlugin.d.ts +12 -0
  61. package/plugins/ConnectionFilterTypesPlugin.js +228 -0
  62. package/plugins/index.d.ts +11 -0
  63. package/plugins/index.js +25 -0
  64. package/plugins/operatorApply.d.ts +11 -0
  65. package/plugins/operatorApply.js +73 -0
  66. package/preset.d.ts +35 -0
  67. package/preset.js +75 -0
  68. package/types.d.ts +146 -0
  69. package/types.js +7 -0
  70. package/utils.d.ts +44 -0
  71. package/utils.js +119 -0
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dan Lynch <pyramation@gmail.com>
4
+ Copyright (c) 2025 Constructive <developers@constructive.io>
5
+ Copyright (c) 2020-present, Interweb, Inc.
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # graphile-connection-filter
2
+
3
+ A PostGraphile v5 native connection filter plugin for the Constructive monorepo.
4
+
5
+ Adds advanced filtering capabilities to connection and list fields, including:
6
+
7
+ - Per-table filter types (e.g. `UserFilter`)
8
+ - Per-scalar operator types (e.g. `StringFilter`, `IntFilter`)
9
+ - Standard operators: `equalTo`, `notEqualTo`, `isNull`, `in`, `notIn`, etc.
10
+ - Sort operators: `lessThan`, `greaterThan`, etc.
11
+ - Pattern matching: `includes`, `startsWith`, `endsWith`, `like` + case-insensitive variants
12
+ - Type-specific operators: JSONB, hstore, inet, array, range
13
+ - Logical operators: `and`, `or`, `not`
14
+ - Declarative custom operator API: `connectionFilterOperatorFactories` for satellite plugins
15
+
16
+ ## Usage
17
+
18
+ ```typescript
19
+ import { ConnectionFilterPreset } from 'graphile-connection-filter';
20
+
21
+ const preset: GraphileConfig.Preset = {
22
+ extends: [
23
+ ConnectionFilterPreset(),
24
+ ],
25
+ };
26
+ ```
27
+
28
+ ## Custom Operators
29
+
30
+ Satellite plugins declare custom operators via `connectionFilterOperatorFactories` in their preset's schema options. Each factory is a function that receives the `build` object and returns an array of operator registrations:
31
+
32
+ ```typescript
33
+ import type { ConnectionFilterOperatorFactory } from 'graphile-connection-filter';
34
+
35
+ const myOperatorFactory: ConnectionFilterOperatorFactory = (build) => [{
36
+ typeNames: 'MyType',
37
+ operatorName: 'myOperator',
38
+ spec: {
39
+ description: 'My custom operator',
40
+ resolve: (sqlIdentifier, sqlValue) => build.sql`${sqlIdentifier} OP ${sqlValue}`,
41
+ },
42
+ }];
43
+
44
+ const MyPreset: GraphileConfig.Preset = {
45
+ schema: {
46
+ connectionFilterOperatorFactories: [myOperatorFactory],
47
+ },
48
+ };
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Education and Tutorials
54
+
55
+ 1. 🚀 [Quickstart: Getting Up and Running](https://constructive.io/learn/quickstart)
56
+ Get started with modular databases in minutes. Install prerequisites and deploy your first module.
57
+
58
+ 2. 📦 [Modular PostgreSQL Development with Database Packages](https://constructive.io/learn/modular-postgres)
59
+ Learn to organize PostgreSQL projects with pgpm workspaces and reusable database modules.
60
+
61
+ 3. ✏️ [Authoring Database Changes](https://constructive.io/learn/authoring-database-changes)
62
+ Master the workflow for adding, organizing, and managing database changes with pgpm.
63
+
64
+ 4. 🧪 [End-to-End PostgreSQL Testing with TypeScript](https://constructive.io/learn/e2e-postgres-testing)
65
+ Master end-to-end PostgreSQL testing with ephemeral databases, RLS testing, and CI/CD automation.
66
+
67
+ 5. ⚡ [Supabase Testing](https://constructive.io/learn/supabase)
68
+ Use TypeScript-first tools to test Supabase projects with realistic RLS, policies, and auth contexts.
69
+
70
+ 6. 💧 [Drizzle ORM Testing](https://constructive.io/learn/drizzle-testing)
71
+ Run full-stack tests with Drizzle ORM, including database setup, teardown, and RLS enforcement.
72
+
73
+ 7. 🔧 [Troubleshooting](https://constructive.io/learn/troubleshooting)
74
+ Common issues and solutions for pgpm, PostgreSQL, and testing.
75
+
76
+ ## Related Constructive Tooling
77
+
78
+ ### 📦 Package Management
79
+
80
+ * [pgpm](https://github.com/constructive-io/constructive/tree/main/pgpm/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
81
+
82
+ ### 🧪 Testing
83
+
84
+ * [pgsql-test](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
85
+ * [pgsql-seed](https://github.com/constructive-io/constructive/tree/main/postgres/pgsql-seed): **🌱 PostgreSQL seeding utilities** for CSV, JSON, SQL data loading, and pgpm deployment.
86
+ * [supabase-test](https://github.com/constructive-io/constructive/tree/main/postgres/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
87
+ * [graphile-test](https://github.com/constructive-io/constructive/tree/main/graphile/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
88
+ * [pg-query-context](https://github.com/constructive-io/constructive/tree/main/postgres/pg-query-context): **🔒 Session context injection** to add session-local context (e.g., `SET LOCAL`) into queries—ideal for setting `role`, `jwt.claims`, and other session settings.
89
+
90
+ ### 🧠 Parsing & AST
91
+
92
+ * [pgsql-parser](https://www.npmjs.com/package/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
93
+ * [libpg-query-node](https://www.npmjs.com/package/libpg-query): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
94
+ * [pg-proto-parser](https://www.npmjs.com/package/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
95
+ * [@pgsql/enums](https://www.npmjs.com/package/@pgsql/enums): **🏷️ TypeScript enums** for PostgreSQL AST for safe and ergonomic parsing logic.
96
+ * [@pgsql/types](https://www.npmjs.com/package/@pgsql/types): **📝 Type definitions** for PostgreSQL AST nodes in TypeScript.
97
+ * [@pgsql/utils](https://www.npmjs.com/package/@pgsql/utils): **🛠️ AST utilities** for constructing and transforming PostgreSQL syntax trees.
98
+
99
+ ## Credits
100
+
101
+ **🛠 Built by the [Constructive](https://constructive.io) team — creators of modular Postgres tooling for secure, composable backends. If you like our work, contribute on [GitHub](https://github.com/constructive-io).**
102
+
103
+ ## Disclaimer
104
+
105
+ AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
106
+
107
+ No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
@@ -0,0 +1,104 @@
1
+ /**
2
+ * TypeScript namespace augmentations for graphile-connection-filter.
3
+ *
4
+ * These extend the Graphile type system so that our custom inflection methods,
5
+ * build properties, scope properties, schema options, and behaviors are
6
+ * recognized by the TypeScript compiler.
7
+ */
8
+ import 'graphile-build';
9
+ import 'graphile-build-pg';
10
+ import type { ConnectionFilterOperatorFactory, ConnectionFilterOperatorsDigest, PgConnectionFilterOperatorsScope } from './types';
11
+ declare global {
12
+ namespace GraphileBuild {
13
+ interface Inflection {
14
+ /** Filter type name for a table, e.g. "UserFilter" */
15
+ filterType(this: Inflection, typeName: string): string;
16
+ /** Filter field type name for a scalar, e.g. "StringFilter" */
17
+ filterFieldType(this: Inflection, typeName: string): string;
18
+ /** Filter field list type name for an array scalar, e.g. "StringListFilter" */
19
+ filterFieldListType(this: Inflection, typeName: string): string;
20
+ /** Forward relation field name (passthrough) */
21
+ filterSingleRelationFieldName(this: Inflection, fieldName: string): string;
22
+ /** Forward relation exists field name, e.g. "clientByClientIdExists" */
23
+ filterForwardRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
24
+ /** Backward single relation field name (passthrough) */
25
+ filterSingleRelationByKeysBackwardsFieldName(this: Inflection, fieldName: string): string;
26
+ /** Backward single relation exists field name */
27
+ filterBackwardSingleRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
28
+ /** Backward many relation field name (passthrough) */
29
+ filterManyRelationByKeysFieldName(this: Inflection, fieldName: string): string;
30
+ /** Backward many relation exists field name */
31
+ filterBackwardManyRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
32
+ /** Many filter type name, e.g. "ClientToManyOrderFilter" */
33
+ filterManyType(this: Inflection, table: any, foreignTable: any): string;
34
+ }
35
+ interface Build {
36
+ /** Returns the operator digest for a given codec, or null if not filterable */
37
+ connectionFilterOperatorsDigest(codec: any): ConnectionFilterOperatorsDigest | null;
38
+ /** Escapes LIKE wildcard characters (% and _) */
39
+ escapeLikeWildcards(input: unknown): string;
40
+ /** Internal filter operator registry keyed by filter type name */
41
+ [key: symbol]: any;
42
+ }
43
+ interface ScopeInputObject {
44
+ /** True if this is a table-level connection filter type (e.g. UserFilter) */
45
+ isPgConnectionFilter?: boolean;
46
+ /** Operator type scope data (present on scalar filter types like StringFilter) */
47
+ pgConnectionFilterOperators?: PgConnectionFilterOperatorsScope;
48
+ /** Foreign table resource (used by many filter types) */
49
+ foreignTable?: any;
50
+ /** True if this is a many-relation filter type (e.g. ClientToManyOrderFilter) */
51
+ isPgConnectionFilterMany?: boolean;
52
+ }
53
+ interface ScopeInputObjectFieldsField {
54
+ /** True if this field is an attribute-based filter field */
55
+ isPgConnectionFilterField?: boolean;
56
+ /** True if this field is a filter operator (e.g. equalTo, lessThan) */
57
+ isPgConnectionFilterOperator?: boolean;
58
+ /** True if this field is a logical operator (and/or/not) */
59
+ isPgConnectionFilterOperatorLogical?: boolean;
60
+ /** True if this is a many-relation filter field */
61
+ isPgConnectionFilterManyField?: boolean;
62
+ }
63
+ interface BehaviorStrings {
64
+ filter: true;
65
+ filterProc: true;
66
+ 'attribute:filterBy': true;
67
+ }
68
+ interface SchemaOptions {
69
+ connectionFilterArgumentName?: string;
70
+ connectionFilterArrays?: boolean;
71
+ connectionFilterLogicalOperators?: boolean;
72
+ connectionFilterAllowNullInput?: boolean;
73
+ connectionFilterAllowedFieldTypes?: string[];
74
+ connectionFilterAllowedOperators?: string[];
75
+ connectionFilterOperatorNames?: Record<string, string>;
76
+ connectionFilterSetofFunctions?: boolean;
77
+ connectionFilterComputedColumns?: boolean;
78
+ connectionFilterRelations?: boolean;
79
+ /** If true (default), relation filter fields are only added for FKs with supporting indexes.
80
+ * This prevents generating EXISTS subqueries that would cause sequential scans on large tables.
81
+ * Set to false to allow relation filters on all FKs regardless of index status. */
82
+ connectionFilterRelationsRequireIndex?: boolean;
83
+ /**
84
+ * Declarative operator factories. Each factory receives the build object
85
+ * and returns operator registrations. Replaces addConnectionFilterOperator.
86
+ */
87
+ connectionFilterOperatorFactories?: ConnectionFilterOperatorFactory[];
88
+ }
89
+ }
90
+ namespace GraphileConfig {
91
+ interface Plugins {
92
+ ConnectionFilterInflectionPlugin: true;
93
+ ConnectionFilterTypesPlugin: true;
94
+ ConnectionFilterArgPlugin: true;
95
+ ConnectionFilterAttributesPlugin: true;
96
+ ConnectionFilterOperatorsPlugin: true;
97
+ ConnectionFilterCustomOperatorsPlugin: true;
98
+ ConnectionFilterLogicalOperatorsPlugin: true;
99
+ ConnectionFilterComputedAttributesPlugin: true;
100
+ ConnectionFilterForwardRelationsPlugin: true;
101
+ ConnectionFilterBackwardRelationsPlugin: true;
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ /**
3
+ * TypeScript namespace augmentations for graphile-connection-filter.
4
+ *
5
+ * These extend the Graphile type system so that our custom inflection methods,
6
+ * build properties, scope properties, schema options, and behaviors are
7
+ * recognized by the TypeScript compiler.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ require("graphile-build");
11
+ require("graphile-build-pg");
@@ -0,0 +1,104 @@
1
+ /**
2
+ * TypeScript namespace augmentations for graphile-connection-filter.
3
+ *
4
+ * These extend the Graphile type system so that our custom inflection methods,
5
+ * build properties, scope properties, schema options, and behaviors are
6
+ * recognized by the TypeScript compiler.
7
+ */
8
+ import 'graphile-build';
9
+ import 'graphile-build-pg';
10
+ import type { ConnectionFilterOperatorFactory, ConnectionFilterOperatorsDigest, PgConnectionFilterOperatorsScope } from './types';
11
+ declare global {
12
+ namespace GraphileBuild {
13
+ interface Inflection {
14
+ /** Filter type name for a table, e.g. "UserFilter" */
15
+ filterType(this: Inflection, typeName: string): string;
16
+ /** Filter field type name for a scalar, e.g. "StringFilter" */
17
+ filterFieldType(this: Inflection, typeName: string): string;
18
+ /** Filter field list type name for an array scalar, e.g. "StringListFilter" */
19
+ filterFieldListType(this: Inflection, typeName: string): string;
20
+ /** Forward relation field name (passthrough) */
21
+ filterSingleRelationFieldName(this: Inflection, fieldName: string): string;
22
+ /** Forward relation exists field name, e.g. "clientByClientIdExists" */
23
+ filterForwardRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
24
+ /** Backward single relation field name (passthrough) */
25
+ filterSingleRelationByKeysBackwardsFieldName(this: Inflection, fieldName: string): string;
26
+ /** Backward single relation exists field name */
27
+ filterBackwardSingleRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
28
+ /** Backward many relation field name (passthrough) */
29
+ filterManyRelationByKeysFieldName(this: Inflection, fieldName: string): string;
30
+ /** Backward many relation exists field name */
31
+ filterBackwardManyRelationExistsFieldName(this: Inflection, relationFieldName: string): string;
32
+ /** Many filter type name, e.g. "ClientToManyOrderFilter" */
33
+ filterManyType(this: Inflection, table: any, foreignTable: any): string;
34
+ }
35
+ interface Build {
36
+ /** Returns the operator digest for a given codec, or null if not filterable */
37
+ connectionFilterOperatorsDigest(codec: any): ConnectionFilterOperatorsDigest | null;
38
+ /** Escapes LIKE wildcard characters (% and _) */
39
+ escapeLikeWildcards(input: unknown): string;
40
+ /** Internal filter operator registry keyed by filter type name */
41
+ [key: symbol]: any;
42
+ }
43
+ interface ScopeInputObject {
44
+ /** True if this is a table-level connection filter type (e.g. UserFilter) */
45
+ isPgConnectionFilter?: boolean;
46
+ /** Operator type scope data (present on scalar filter types like StringFilter) */
47
+ pgConnectionFilterOperators?: PgConnectionFilterOperatorsScope;
48
+ /** Foreign table resource (used by many filter types) */
49
+ foreignTable?: any;
50
+ /** True if this is a many-relation filter type (e.g. ClientToManyOrderFilter) */
51
+ isPgConnectionFilterMany?: boolean;
52
+ }
53
+ interface ScopeInputObjectFieldsField {
54
+ /** True if this field is an attribute-based filter field */
55
+ isPgConnectionFilterField?: boolean;
56
+ /** True if this field is a filter operator (e.g. equalTo, lessThan) */
57
+ isPgConnectionFilterOperator?: boolean;
58
+ /** True if this field is a logical operator (and/or/not) */
59
+ isPgConnectionFilterOperatorLogical?: boolean;
60
+ /** True if this is a many-relation filter field */
61
+ isPgConnectionFilterManyField?: boolean;
62
+ }
63
+ interface BehaviorStrings {
64
+ filter: true;
65
+ filterProc: true;
66
+ 'attribute:filterBy': true;
67
+ }
68
+ interface SchemaOptions {
69
+ connectionFilterArgumentName?: string;
70
+ connectionFilterArrays?: boolean;
71
+ connectionFilterLogicalOperators?: boolean;
72
+ connectionFilterAllowNullInput?: boolean;
73
+ connectionFilterAllowedFieldTypes?: string[];
74
+ connectionFilterAllowedOperators?: string[];
75
+ connectionFilterOperatorNames?: Record<string, string>;
76
+ connectionFilterSetofFunctions?: boolean;
77
+ connectionFilterComputedColumns?: boolean;
78
+ connectionFilterRelations?: boolean;
79
+ /** If true (default), relation filter fields are only added for FKs with supporting indexes.
80
+ * This prevents generating EXISTS subqueries that would cause sequential scans on large tables.
81
+ * Set to false to allow relation filters on all FKs regardless of index status. */
82
+ connectionFilterRelationsRequireIndex?: boolean;
83
+ /**
84
+ * Declarative operator factories. Each factory receives the build object
85
+ * and returns operator registrations. Replaces addConnectionFilterOperator.
86
+ */
87
+ connectionFilterOperatorFactories?: ConnectionFilterOperatorFactory[];
88
+ }
89
+ }
90
+ namespace GraphileConfig {
91
+ interface Plugins {
92
+ ConnectionFilterInflectionPlugin: true;
93
+ ConnectionFilterTypesPlugin: true;
94
+ ConnectionFilterArgPlugin: true;
95
+ ConnectionFilterAttributesPlugin: true;
96
+ ConnectionFilterOperatorsPlugin: true;
97
+ ConnectionFilterCustomOperatorsPlugin: true;
98
+ ConnectionFilterLogicalOperatorsPlugin: true;
99
+ ConnectionFilterComputedAttributesPlugin: true;
100
+ ConnectionFilterForwardRelationsPlugin: true;
101
+ ConnectionFilterBackwardRelationsPlugin: true;
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * TypeScript namespace augmentations for graphile-connection-filter.
3
+ *
4
+ * These extend the Graphile type system so that our custom inflection methods,
5
+ * build properties, scope properties, schema options, and behaviors are
6
+ * recognized by the TypeScript compiler.
7
+ */
8
+ import 'graphile-build';
9
+ import 'graphile-build-pg';
package/esm/index.d.ts ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * graphile-connection-filter
3
+ *
4
+ * A PostGraphile v5 native connection filter plugin.
5
+ * Adds advanced filtering capabilities to connection and list fields.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ConnectionFilterPreset } from 'graphile-connection-filter';
10
+ *
11
+ * const preset = {
12
+ * extends: [
13
+ * ConnectionFilterPreset(),
14
+ * ],
15
+ * };
16
+ * ```
17
+ *
18
+ * For satellite plugins that need to register custom operators, declare them
19
+ * as factories in the preset's `connectionFilterOperatorFactories` option:
20
+ * ```typescript
21
+ * import type { ConnectionFilterOperatorFactory } from 'graphile-connection-filter';
22
+ *
23
+ * const myOperatorFactory: ConnectionFilterOperatorFactory = (build) => [{
24
+ * typeNames: 'MyType',
25
+ * operatorName: 'myOperator',
26
+ * spec: {
27
+ * description: 'My custom operator',
28
+ * resolve: (sqlIdentifier, sqlValue) => build.sql`${sqlIdentifier} OP ${sqlValue}`,
29
+ * },
30
+ * }];
31
+ *
32
+ * export const MyPreset = {
33
+ * schema: {
34
+ * connectionFilterOperatorFactories: [myOperatorFactory],
35
+ * },
36
+ * plugins: [MyPlugin],
37
+ * };
38
+ * ```
39
+ *
40
+ * For satellite plugins that need to access the query builder from a filter apply:
41
+ * ```typescript
42
+ * import { getQueryBuilder } from 'graphile-connection-filter';
43
+ * // In your filter field's apply callback:
44
+ * const qb = getQueryBuilder(build, $condition);
45
+ * if (qb) {
46
+ * const idx = qb.selectAndReturnIndex(sql`...`);
47
+ * qb.setMeta('key', { selectIndex: idx });
48
+ * }
49
+ * ```
50
+ */
51
+ export { ConnectionFilterPreset } from './preset';
52
+ export { ConnectionFilterInflectionPlugin, ConnectionFilterTypesPlugin, ConnectionFilterArgPlugin, ConnectionFilterAttributesPlugin, ConnectionFilterOperatorsPlugin, ConnectionFilterCustomOperatorsPlugin, ConnectionFilterLogicalOperatorsPlugin, ConnectionFilterComputedAttributesPlugin, ConnectionFilterForwardRelationsPlugin, ConnectionFilterBackwardRelationsPlugin, makeApplyFromOperatorSpec, } from './plugins';
53
+ export type { ConnectionFilterOperatorSpec, ConnectionFilterOperatorRegistration, ConnectionFilterOperatorFactory, ConnectionFilterOptions, ConnectionFilterOperatorsDigest, PgConnectionFilterOperatorsScope, } from './types';
54
+ export { $$filters } from './types';
55
+ export { isEmpty, makeAssertAllowed, getQueryBuilder, isComputedScalarAttributeResource, getComputedAttributeResources, } from './utils';
package/esm/index.js ADDED
@@ -0,0 +1,56 @@
1
+ /**
2
+ * graphile-connection-filter
3
+ *
4
+ * A PostGraphile v5 native connection filter plugin.
5
+ * Adds advanced filtering capabilities to connection and list fields.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { ConnectionFilterPreset } from 'graphile-connection-filter';
10
+ *
11
+ * const preset = {
12
+ * extends: [
13
+ * ConnectionFilterPreset(),
14
+ * ],
15
+ * };
16
+ * ```
17
+ *
18
+ * For satellite plugins that need to register custom operators, declare them
19
+ * as factories in the preset's `connectionFilterOperatorFactories` option:
20
+ * ```typescript
21
+ * import type { ConnectionFilterOperatorFactory } from 'graphile-connection-filter';
22
+ *
23
+ * const myOperatorFactory: ConnectionFilterOperatorFactory = (build) => [{
24
+ * typeNames: 'MyType',
25
+ * operatorName: 'myOperator',
26
+ * spec: {
27
+ * description: 'My custom operator',
28
+ * resolve: (sqlIdentifier, sqlValue) => build.sql`${sqlIdentifier} OP ${sqlValue}`,
29
+ * },
30
+ * }];
31
+ *
32
+ * export const MyPreset = {
33
+ * schema: {
34
+ * connectionFilterOperatorFactories: [myOperatorFactory],
35
+ * },
36
+ * plugins: [MyPlugin],
37
+ * };
38
+ * ```
39
+ *
40
+ * For satellite plugins that need to access the query builder from a filter apply:
41
+ * ```typescript
42
+ * import { getQueryBuilder } from 'graphile-connection-filter';
43
+ * // In your filter field's apply callback:
44
+ * const qb = getQueryBuilder(build, $condition);
45
+ * if (qb) {
46
+ * const idx = qb.selectAndReturnIndex(sql`...`);
47
+ * qb.setMeta('key', { selectIndex: idx });
48
+ * }
49
+ * ```
50
+ */
51
+ export { ConnectionFilterPreset } from './preset';
52
+ // Re-export all plugins for granular use
53
+ export { ConnectionFilterInflectionPlugin, ConnectionFilterTypesPlugin, ConnectionFilterArgPlugin, ConnectionFilterAttributesPlugin, ConnectionFilterOperatorsPlugin, ConnectionFilterCustomOperatorsPlugin, ConnectionFilterLogicalOperatorsPlugin, ConnectionFilterComputedAttributesPlugin, ConnectionFilterForwardRelationsPlugin, ConnectionFilterBackwardRelationsPlugin, makeApplyFromOperatorSpec, } from './plugins';
54
+ export { $$filters } from './types';
55
+ // Re-export utilities
56
+ export { isEmpty, makeAssertAllowed, getQueryBuilder, isComputedScalarAttributeResource, getComputedAttributeResources, } from './utils';
@@ -0,0 +1,13 @@
1
+ import '../augmentations';
2
+ import type { GraphileConfig } from 'graphile-config';
3
+ /**
4
+ * ConnectionFilterArgPlugin
5
+ *
6
+ * Adds the filter argument (configurable name, default 'where') to connection
7
+ * and simple collection fields. Uses `applyPlan` to create a PgCondition that
8
+ * child filter fields can add WHERE clauses to.
9
+ *
10
+ * This runs before PgConnectionArgOrderByPlugin so that filters are applied
11
+ * before ordering (important for e.g. full-text search rank ordering).
12
+ */
13
+ export declare const ConnectionFilterArgPlugin: GraphileConfig.Plugin;
@@ -0,0 +1,96 @@
1
+ import '../augmentations';
2
+ import { isEmpty } from '../utils';
3
+ const version = '1.0.0';
4
+ /**
5
+ * ConnectionFilterArgPlugin
6
+ *
7
+ * Adds the filter argument (configurable name, default 'where') to connection
8
+ * and simple collection fields. Uses `applyPlan` to create a PgCondition that
9
+ * child filter fields can add WHERE clauses to.
10
+ *
11
+ * This runs before PgConnectionArgOrderByPlugin so that filters are applied
12
+ * before ordering (important for e.g. full-text search rank ordering).
13
+ */
14
+ export const ConnectionFilterArgPlugin = {
15
+ name: 'ConnectionFilterArgPlugin',
16
+ version,
17
+ description: 'Adds the filter argument to connection and list fields',
18
+ before: ['PgConnectionArgOrderByPlugin'],
19
+ schema: {
20
+ hooks: {
21
+ GraphQLObjectType_fields_field_args(args, build, context) {
22
+ const { extend, inflection, EXPORTABLE, dataplanPg: { PgCondition }, } = build;
23
+ const { scope: { isPgFieldConnection, isPgFieldSimpleCollection, pgFieldResource: resource, pgFieldCodec, fieldName, }, Self, } = context;
24
+ const shouldAddFilter = isPgFieldConnection || isPgFieldSimpleCollection;
25
+ if (!shouldAddFilter)
26
+ return args;
27
+ const codec = pgFieldCodec ?? resource?.codec;
28
+ if (!codec)
29
+ return args;
30
+ // Check behavior: procedures use "filterProc", tables use "filter"
31
+ const desiredBehavior = resource?.parameters
32
+ ? 'filterProc'
33
+ : 'filter';
34
+ if (resource
35
+ ? !build.behavior.pgResourceMatches(resource, desiredBehavior)
36
+ : !build.behavior.pgCodecMatches(codec, desiredBehavior)) {
37
+ return args;
38
+ }
39
+ const returnCodec = codec;
40
+ const nodeType = build.getGraphQLTypeByPgCodec(returnCodec, 'output');
41
+ if (!nodeType)
42
+ return args;
43
+ const nodeTypeName = nodeType.name;
44
+ const filterTypeName = inflection.filterType(nodeTypeName);
45
+ const FilterType = build.getTypeByName(filterTypeName);
46
+ if (!FilterType)
47
+ return args;
48
+ // For setof functions returning scalars, track the codec
49
+ const attributeCodec = resource?.parameters && !resource?.codec.attributes
50
+ ? resource.codec
51
+ : null;
52
+ const argName = build.options.connectionFilterArgumentName || 'where';
53
+ return extend(args, {
54
+ [argName]: {
55
+ description: 'A filter to be used in determining which values should be returned by the collection.',
56
+ type: FilterType,
57
+ ...(isPgFieldConnection
58
+ ? {
59
+ applyPlan: EXPORTABLE((PgCondition, isEmpty, attributeCodec) => function (_, $connection, fieldArg) {
60
+ const $pgSelect = $connection.getSubplan();
61
+ fieldArg.apply($pgSelect, (queryBuilder, value) => {
62
+ // If filter is null/undefined or empty {}, treat as "no filter" — skip
63
+ if (value == null || isEmpty(value))
64
+ return;
65
+ const condition = new PgCondition(queryBuilder);
66
+ if (attributeCodec) {
67
+ condition.extensions.pgFilterAttribute = {
68
+ codec: attributeCodec,
69
+ };
70
+ }
71
+ return condition;
72
+ });
73
+ }, [PgCondition, isEmpty, attributeCodec]),
74
+ }
75
+ : {
76
+ applyPlan: EXPORTABLE((PgCondition, isEmpty, attributeCodec) => function (_, $pgSelect, fieldArg) {
77
+ fieldArg.apply($pgSelect, (queryBuilder, value) => {
78
+ // If filter is null/undefined or empty {}, treat as "no filter" — skip
79
+ if (value == null || isEmpty(value))
80
+ return;
81
+ const condition = new PgCondition(queryBuilder);
82
+ if (attributeCodec) {
83
+ condition.extensions.pgFilterAttribute = {
84
+ codec: attributeCodec,
85
+ };
86
+ }
87
+ return condition;
88
+ });
89
+ }, [PgCondition, isEmpty, attributeCodec]),
90
+ }),
91
+ },
92
+ }, `Adding connection filter '${argName}' arg to field '${fieldName}' of '${Self.name}'`);
93
+ },
94
+ },
95
+ },
96
+ };
@@ -0,0 +1,14 @@
1
+ import '../augmentations';
2
+ import type { GraphileConfig } from 'graphile-config';
3
+ /**
4
+ * ConnectionFilterAttributesPlugin
5
+ *
6
+ * Adds per-column filter fields to the table filter types.
7
+ * For example, on `UserFilter`, adds fields like `name` (type: StringFilter),
8
+ * `age` (type: IntFilter), etc.
9
+ *
10
+ * Each field's `apply` function creates a new PgCondition with the
11
+ * `pgFilterAttribute` extension set, so downstream operator fields know
12
+ * which column they are operating on.
13
+ */
14
+ export declare const ConnectionFilterAttributesPlugin: GraphileConfig.Plugin;