Skip to content

Commit 92f0924

Browse files
committed
docs: add GRAPHILE.md documenting the plugin architecture
Comprehensive documentation of the PostGraphile v5 plugin ecosystem: - Active packages with usage examples and key features - Legacy directories and what replaced them - How satellite plugins register filter operators - Key design decisions (condition disabled, unified search, etc.) - Testing matrix with commands and coverage areas - ConstructivePreset composition tree
1 parent 180ba9e commit 92f0924

1 file changed

Lines changed: 226 additions & 0 deletions

File tree

graphile/GRAPHILE.md

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# Graphile Plugin Architecture
2+
3+
This document describes the PostGraphile v5 plugin ecosystem in the Constructive monorepo. All plugins are v5-native, written in TypeScript, and compose via Graphile's preset system.
4+
5+
## Overview
6+
7+
The `graphile/` directory contains all PostGraphile v5 plugins, organized as individual packages in the pnpm workspace. The central entry point is `graphile-settings`, which exports `ConstructivePreset` — a single preset that wires everything together.
8+
9+
```
10+
ConstructivePreset
11+
├── MinimalPreset (no Node/Relay — keeps id as id)
12+
├── InflektPreset (custom inflection via inflekt library)
13+
├── ConflictDetectorPreset (warns about naming conflicts between schemas)
14+
├── InflectorLoggerPreset (debug logging for inflector calls)
15+
├── NoUniqueLookupPreset (primary key only lookups)
16+
├── ConnectionFilterPreset (v5-native connection filter with relation filters)
17+
├── EnableAllFilterColumnsPreset (allow filtering on all columns)
18+
├── ManyToManyOptInPreset (many-to-many via @behavior +manyToMany)
19+
├── MetaSchemaPreset (_meta query for schema introspection)
20+
├── UnifiedSearchPreset (tsvector + BM25 + pg_trgm + pgvector)
21+
├── GraphilePostgisPreset (PostGIS types + spatial filter operators)
22+
├── UploadPreset (S3/MinIO file uploads)
23+
├── SqlExpressionValidatorPreset (validates @sqlExpression columns)
24+
└── PgTypeMappingsPreset (custom type → GraphQL scalar mappings)
25+
```
26+
27+
## Active Packages
28+
29+
### graphile-settings
30+
31+
**The main configuration package.** Exports `ConstructivePreset` and all sub-presets. This is the only package most consumers need to import.
32+
33+
- Combines all plugins into a single composable preset
34+
- Disables `condition` argument (all filtering via `filter`/`where`)
35+
- Configures connection filter options (logical operators, arrays, computed columns)
36+
- Aggregates satellite plugin operator factories
37+
38+
```typescript
39+
import { ConstructivePreset, makePgService } from 'graphile-settings';
40+
```
41+
42+
### graphile-connection-filter
43+
44+
**V5-native connection filter plugin.** Adds the `where` argument to connections with per-table filter types (e.g. `UserFilter`) and per-scalar operator types (e.g. `StringFilter`, `IntFilter`).
45+
46+
Key features:
47+
- Standard operators: `equalTo`, `notEqualTo`, `isNull`, `in`, `notIn`, `lessThan`, `greaterThan`
48+
- Pattern matching: `includes`, `startsWith`, `endsWith`, `like` + case-insensitive variants
49+
- Type-specific operators: JSONB, hstore, inet, array, range
50+
- Logical operators: `and`, `or`, `not`
51+
- Relation filters: filter by related table fields (forward and backward)
52+
- **Declarative operator API**: satellite plugins register custom operators via `connectionFilterOperatorFactories`
53+
54+
```typescript
55+
import { ConnectionFilterPreset } from 'graphile-connection-filter';
56+
```
57+
58+
### graphile-search
59+
60+
**Unified search plugin with adapter pattern.** Replaces the previous separate plugins (`graphile-tsvector`, `graphile-bm25`, `graphile-trgm`, `graphile-pgvector`) with a single plugin that supports all four search algorithms.
61+
62+
Each algorithm is a ~50-line adapter implementing the `SearchAdapter` interface:
63+
- **tsvector** — PostgreSQL full-text search via `ts_rank`
64+
- **BM25**`pg_textsearch` extension scoring
65+
- **pg_trgm** — Trigram fuzzy matching via `similarity()`
66+
- **pgvector** — Vector similarity search (cosine, L2, inner product)
67+
68+
Generated GraphQL fields per adapter:
69+
- **Score fields**: `{column}{Algorithm}{Metric}` (e.g. `bodyBm25Score`, `titleTrgmSimilarity`)
70+
- **Composite score**: `searchScore` — normalized 0..1 aggregating all active search signals
71+
- **OrderBy enums**: `{COLUMN}_{ALGORITHM}_{METRIC}_ASC/DESC` + `SEARCH_SCORE_ASC/DESC`
72+
- **Filter fields**: `{algorithm}{Column}` on connection filter input types (e.g. `fullTextBody`, `trgmTitle`)
73+
74+
Zero config — auto-discovers columns and indexes per adapter.
75+
76+
```typescript
77+
import { UnifiedSearchPreset } from 'graphile-search';
78+
```
79+
80+
### graphile-postgis
81+
82+
**PostGIS support.** Generates GraphQL types for geometry/geography columns including GeoJSON scalar types, dimension-aware interfaces, and spatial filter operators.
83+
84+
Features:
85+
- GeoJSON scalar type for input/output
86+
- Concrete types for all geometry subtypes (Point, LineString, Polygon, etc.)
87+
- Geography-aware field naming (longitude/latitude instead of x/y)
88+
- Spatial filter operators via `createPostgisOperatorFactory()`
89+
- Graceful degradation when PostGIS is not installed
90+
91+
```typescript
92+
import { GraphilePostgisPreset, createPostgisOperatorFactory } from 'graphile-postgis';
93+
```
94+
95+
### graphile-misc-plugins
96+
97+
**Collection of smaller plugins** that don't warrant their own package:
98+
99+
| Plugin/Preset | Description |
100+
|---|---|
101+
| `MinimalPreset` | PostGraphile without Node/Relay features |
102+
| `InflektPreset` | Custom inflection using inflekt library |
103+
| `ConflictDetectorPreset` | Warns about naming conflicts between schemas |
104+
| `InflectorLoggerPreset` | Debug logging (enable with `INFLECTOR_LOG=1`) |
105+
| `EnableAllFilterColumnsPreset` | Allow filtering on all columns (not just indexed) |
106+
| `ManyToManyOptInPreset` | Many-to-many via `@behavior +manyToMany` smart tag |
107+
| `NoUniqueLookupPreset` | Disable non-primary-key unique lookups |
108+
| `MetaSchemaPreset` | `_meta` query for database schema introspection |
109+
| `PgTypeMappingsPreset` | Custom PostgreSQL type → GraphQL scalar mappings |
110+
111+
### graphile-cache
112+
113+
**PostGraphile instance LRU cache** with automatic cleanup when PostgreSQL pools are disposed. Integrates with `pg-cache` for pool management.
114+
115+
```typescript
116+
import { graphileCache } from 'graphile-cache';
117+
```
118+
119+
### graphile-schema
120+
121+
**Lightweight GraphQL SDL builder.** Build schemas directly from a database or fetch from a running endpoint — no server dependencies.
122+
123+
```typescript
124+
import { buildSchemaSDL } from 'graphile-schema';
125+
import { fetchEndpointSchemaSDL } from 'graphile-schema';
126+
```
127+
128+
### graphile-query
129+
130+
**GraphQL query execution utilities.** Supports `pgSettings`, role-based access control, and custom request context.
131+
132+
- `GraphileQuery` — Full-featured with roles, settings, and request context
133+
- `GraphileQuerySimple` — Minimal wrapper for simple execution
134+
135+
```typescript
136+
import { GraphileQuery } from 'graphile-query';
137+
```
138+
139+
### graphile-test
140+
141+
**Testing utilities for PostGraphile.** Builds on `pgsql-test` to provide isolated, seeded, role-aware test databases with GraphQL helpers.
142+
143+
- Per-test rollback via savepoints
144+
- RLS-aware context injection (`setContext`)
145+
- GraphQL `query()` function with snapshot support
146+
- Seed support for SQL, JSON, CSV, Constructive, or Sqitch
147+
148+
For batteries-included testing with all Constructive plugins, use `@constructive-io/graphql-test` instead.
149+
150+
```typescript
151+
import { getConnections, seed } from 'graphile-test';
152+
```
153+
154+
### graphile-sql-expression-validator
155+
156+
**SQL expression validation** for PostGraphile v5. Validates SQL expressions against a configurable allowlist of functions and schemas.
157+
158+
```typescript
159+
import { SqlExpressionValidatorPreset } from 'graphile-sql-expression-validator';
160+
```
161+
162+
### graphile-upload-plugin
163+
164+
**File upload support** for PostGraphile v5. Handles S3/MinIO uploads for image, upload, and attachment domain columns.
165+
166+
```typescript
167+
import { UploadPreset } from 'graphile-upload-plugin';
168+
```
169+
170+
## Legacy Directories (Not Source Code)
171+
172+
The following directories contain npm-installed upstream packages from the v4 era. They have no `package.json` or `src/` — only `dist/` and `node_modules/`. They are consumed as dependencies but not maintained as source:
173+
174+
| Directory | Status |
175+
|---|---|
176+
| `graphile-i18n` | Upstream v4 package |
177+
| `graphile-many-to-many` | Upstream `@graphile-contrib/pg-many-to-many` |
178+
| `graphile-meta-schema` | Folded into `graphile-misc-plugins` as `MetaSchemaPreset` |
179+
| `graphile-pg-type-mappings` | Folded into `graphile-misc-plugins` as `PgTypeMappingsPreset` |
180+
| `graphile-plugin-connection-filter` | Replaced by v5-native `graphile-connection-filter` |
181+
| `graphile-plugin-fulltext-filter` | Replaced by `graphile-search` unified plugin |
182+
| `graphile-simple-inflector` | Replaced by `InflektPreset` in `graphile-misc-plugins` |
183+
184+
## How Satellite Plugins Register Filter Operators
185+
186+
Satellite plugins (search, PostGIS, trgm) register custom filter operators via the **declarative operator factory API** on `graphile-connection-filter`. Each factory is a function that receives the Graphile `build` object and returns operator registrations:
187+
188+
```typescript
189+
// In constructive-preset.ts
190+
schema: {
191+
connectionFilterOperatorFactories: [
192+
createMatchesOperatorFactory('FullText', 'english'), // tsvector matches
193+
createTrgmOperatorFactories(), // similarTo, wordSimilarTo
194+
createPostgisOperatorFactory(), // spatial operators
195+
],
196+
}
197+
```
198+
199+
This ensures `graphile-config`'s array replacement behavior is handled correctly — all factories are collected at the top-level preset.
200+
201+
## Key Design Decisions
202+
203+
1. **`condition` is disabled.** All filtering lives under `where` (the v5-native filter argument). `PgConditionArgumentPlugin` and `PgConditionCustomFieldsPlugin` are explicitly disabled in the preset.
204+
205+
2. **All columns are filterable.** `EnableAllFilterColumnsPreset` overrides PostGraphile's default of only filtering indexed columns. Index optimization is left to DBAs.
206+
207+
3. **Many-to-many is opt-in.** No many-to-many fields are generated unless the junction table has `@behavior +manyToMany` smart tag. This prevents API bloat.
208+
209+
4. **Relation filters are enabled.** `connectionFilterRelations: true` allows filtering across foreign key relationships (forward and backward).
210+
211+
5. **Search is unified.** One plugin (`graphile-search`) handles all four search algorithms via adapters instead of four separate plugins.
212+
213+
6. **Computed fields are excluded from codegen defaults.** The codegen's `getSelectableScalarFields()` helper uses the TypeRegistry to filter out plugin-added computed fields (search scores, hash UUIDs) from default CLI select objects.
214+
215+
## Testing
216+
217+
| Test Suite | Command | What It Covers |
218+
|---|---|---|
219+
| `graphile-connection-filter` | `pnpm --filter graphile-connection-filter test` | 51 filter operator tests |
220+
| `graphile-search` | `pnpm --filter graphile-search test` | Unified search adapter tests |
221+
| `graphile-settings` | `pnpm --filter graphile-settings test` | Preset integration + metadata tests |
222+
| `graphile-test` | `pnpm --filter graphile-test test` | Test framework self-tests |
223+
| `graphql/test` | `pnpm --filter @constructive-io/graphql-test test` | Full ConstructivePreset integration (84 tests) |
224+
| `graphql/server-test` | `pnpm --filter @constructive-io/graphql-server-test test` | Server-level integration + search mega queries |
225+
226+
All tests run in CI against `constructiveio/postgres-plus:18` (includes PostGIS, pg_trgm, pgvector, pg_textsearch).

0 commit comments

Comments
 (0)