@fougere/adapter-graphql 0.2.0-alpha.2
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/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/auto-register.d.ts +101 -0
- package/dist/auto-register.d.ts.map +1 -0
- package/dist/auto-register.js +339 -0
- package/dist/auto-register.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/pothos-entry.d.ts +10 -0
- package/dist/pothos-entry.d.ts.map +1 -0
- package/dist/pothos-entry.js +9 -0
- package/dist/pothos-entry.js.map +1 -0
- package/dist/pothos.d.ts +177 -0
- package/dist/pothos.d.ts.map +1 -0
- package/dist/pothos.js +696 -0
- package/dist/pothos.js.map +1 -0
- package/dist/serve.d.ts +29 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +101 -0
- package/dist/serve.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fougere contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @fougere/adapter-graphql
|
|
2
|
+
> Entity → GraphQL, through Pothos
|
|
3
|
+
Types, inputs and CRUD operations derived from the entity. The `boundary` projections
|
|
4
|
+
are honoured: a `writeOnly` field appears in no output type.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @fougere/adapter-graphql
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Part of [Fougere](https://github.com/chok/fougere) — one schema, a gradient from
|
|
14
|
+
monolith to distributed, the same user code.
|
|
15
|
+
Reference documentation: [the site](https://chok.github.io/fougere/) (en/fr).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-register GraphQL types and operations from a fougere App.
|
|
3
|
+
*
|
|
4
|
+
* Reads scanned entities + handler facades and registers
|
|
5
|
+
* types, inputs, queries and mutations automatically.
|
|
6
|
+
* Respects handler method-based contracts and surfaces config.
|
|
7
|
+
*
|
|
8
|
+
* Relations (ref/many) are auto-wired between registered types.
|
|
9
|
+
*/
|
|
10
|
+
import type SchemaBuilder from '@pothos/core';
|
|
11
|
+
import type { SchemaView, SchemaSource } from '@fougere/schema';
|
|
12
|
+
interface OperationMeta {
|
|
13
|
+
input?: SchemaView;
|
|
14
|
+
output?: SchemaView;
|
|
15
|
+
signature?: {
|
|
16
|
+
name: string;
|
|
17
|
+
params: {
|
|
18
|
+
name: string;
|
|
19
|
+
type: {
|
|
20
|
+
raw: string;
|
|
21
|
+
name: string;
|
|
22
|
+
array?: boolean;
|
|
23
|
+
nullable?: boolean;
|
|
24
|
+
generics?: any[];
|
|
25
|
+
};
|
|
26
|
+
optional?: boolean;
|
|
27
|
+
}[];
|
|
28
|
+
returnType?: {
|
|
29
|
+
raw: string;
|
|
30
|
+
name: string;
|
|
31
|
+
array?: boolean;
|
|
32
|
+
nullable?: boolean;
|
|
33
|
+
generics?: any[];
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
interface EntityEntry {
|
|
38
|
+
name: string;
|
|
39
|
+
/** A live class in-process, a card from a frond whose class never crossed. */
|
|
40
|
+
entityClass: SchemaSource;
|
|
41
|
+
exposed?: boolean;
|
|
42
|
+
}
|
|
43
|
+
interface HandlerEntry {
|
|
44
|
+
/** The name the door answers to — `PostHandler` → `post`. NOT an entity name: a handler may carry none. */
|
|
45
|
+
address: string;
|
|
46
|
+
operations: Map<string, OperationMeta>;
|
|
47
|
+
surface?: string;
|
|
48
|
+
outputOverride?: SchemaView;
|
|
49
|
+
ctor?: {
|
|
50
|
+
__output?: SchemaView;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
interface PresenterFieldMeta {
|
|
54
|
+
name: string;
|
|
55
|
+
returnType?: string;
|
|
56
|
+
/** The field emits a list per row, the page level of its return type removed. */
|
|
57
|
+
list?: boolean;
|
|
58
|
+
nullable?: boolean;
|
|
59
|
+
}
|
|
60
|
+
interface PresenterEntry {
|
|
61
|
+
entityName: string;
|
|
62
|
+
fields: string[];
|
|
63
|
+
fieldMeta: PresenterFieldMeta[];
|
|
64
|
+
/** The view each computed field emits, when the presenter declares one. */
|
|
65
|
+
views?: Record<string, unknown>;
|
|
66
|
+
}
|
|
67
|
+
interface FrondLike {
|
|
68
|
+
name: string;
|
|
69
|
+
entities: EntityEntry[];
|
|
70
|
+
handlers: HandlerEntry[];
|
|
71
|
+
presenters: PresenterEntry[];
|
|
72
|
+
surfaces?: Record<string, string[]>;
|
|
73
|
+
operationsOverrides?: Record<string, {
|
|
74
|
+
kind?: 'query' | 'command';
|
|
75
|
+
handlerName?: string;
|
|
76
|
+
method?: string;
|
|
77
|
+
policy?: string;
|
|
78
|
+
}>;
|
|
79
|
+
}
|
|
80
|
+
interface AppLike {
|
|
81
|
+
fronds: FrondLike[];
|
|
82
|
+
resolve<T>(name: string): T;
|
|
83
|
+
/** The façade an entity exposes to one audience — `undefined` when none. */
|
|
84
|
+
facadeFor(entity: string, surface?: string): Record<string, Function> | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* The presenter of an entity — `undefined` when none. Asked for rather than
|
|
87
|
+
* resolved by a key spelled here: this adapter used to build `${Name}Presenter`
|
|
88
|
+
* itself, and a convention respelled in two places drifts silently on the day it
|
|
89
|
+
* changes, exactly as `facadeFor` exists to prevent for doors.
|
|
90
|
+
*/
|
|
91
|
+
presenterFor(entity: string): unknown | undefined;
|
|
92
|
+
}
|
|
93
|
+
export interface RegisterAllOptions {
|
|
94
|
+
/** Override which entities to expose. Default: all scanned entities with a handler. */
|
|
95
|
+
filter?: (entity: EntityEntry, frondName: string) => boolean;
|
|
96
|
+
/** Surface name for filtering (e.g. 'graphql', 'rest'). Uses frond.config.ts surfaces if set. */
|
|
97
|
+
surface?: string;
|
|
98
|
+
}
|
|
99
|
+
export declare function registerAll(builder: InstanceType<typeof SchemaBuilder>, app: AppLike, options?: RegisterAllOptions): void;
|
|
100
|
+
export {};
|
|
101
|
+
//# sourceMappingURL=auto-register.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../src/auto-register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
import { Anatomy, fieldsOf, } from '@fougere/schema';
|
|
2
|
+
import { registerType, registerOperations } from './pothos.js';
|
|
3
|
+
/**
|
|
4
|
+
* The relation a foreign key points at — `authorId → author`, `user_id → user`.
|
|
5
|
+
* Returns undefined when the field carries no id suffix at all: there is nothing to
|
|
6
|
+
* derive, and taking the scalar's own name would collide with it.
|
|
7
|
+
*/
|
|
8
|
+
function relationNameFor(fieldName) {
|
|
9
|
+
const stripped = fieldName.replace(/(_id|Id|ID)$/, '');
|
|
10
|
+
return stripped && stripped !== fieldName ? stripped : undefined;
|
|
11
|
+
}
|
|
12
|
+
/** The field a target is keyed by — what a batch read indexes its answer on. */
|
|
13
|
+
function primaryNameOf(fields) {
|
|
14
|
+
for (const [name, field] of Object.entries(fields))
|
|
15
|
+
if (field.role?.primary)
|
|
16
|
+
return name;
|
|
17
|
+
return 'id';
|
|
18
|
+
}
|
|
19
|
+
/** The batch of ONE direction — the two sides of a relation must not share a read. */
|
|
20
|
+
const directionKey = (entity, field) => `${entity}#${field}`;
|
|
21
|
+
/**
|
|
22
|
+
* How many keys go into one `list` call.
|
|
23
|
+
*
|
|
24
|
+
* A page has no ceiling, and `list` is the one read the ORM refuses to split (a limit
|
|
25
|
+
* and an order do not recompose across statements). So the slicing happens HERE, where
|
|
26
|
+
* the answer is a map being assembled and slices merge for free. Below SQL Server's
|
|
27
|
+
* 2100 bindings, the lowest of the four engines — this side does not know the dialect,
|
|
28
|
+
* so it takes the floor rather than guessing.
|
|
29
|
+
*/
|
|
30
|
+
const KEYS_PER_READ = 1000;
|
|
31
|
+
/** Read a key set in slices, merging what each answers. */
|
|
32
|
+
async function readInSlices(keys, read, merge) {
|
|
33
|
+
if (keys.length <= KEYS_PER_READ)
|
|
34
|
+
return read(keys);
|
|
35
|
+
const all = new Map();
|
|
36
|
+
for (let i = 0; i < keys.length; i += KEYS_PER_READ) {
|
|
37
|
+
merge(all, await read(keys.slice(i, i + KEYS_PER_READ)));
|
|
38
|
+
}
|
|
39
|
+
return all;
|
|
40
|
+
}
|
|
41
|
+
/** A key answers one row: a later slice never contradicts an earlier one. */
|
|
42
|
+
const keepEach = (into, from) => {
|
|
43
|
+
for (const [key, value] of from)
|
|
44
|
+
into.set(key, value);
|
|
45
|
+
};
|
|
46
|
+
/** A key answers a group: slices of the SAME key concatenate. */
|
|
47
|
+
const concatEach = (into, from) => {
|
|
48
|
+
for (const [key, rows] of from) {
|
|
49
|
+
const held = into.get(key);
|
|
50
|
+
if (held)
|
|
51
|
+
held.push(...rows);
|
|
52
|
+
else
|
|
53
|
+
into.set(key, rows);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The keys asked for during one tick, answered by one read.
|
|
58
|
+
*
|
|
59
|
+
* graphql-js calls a field resolver once per parent, so a page of 50 rows asked for
|
|
60
|
+
* its relation 50 times — measured, with 5 distinct keys behind those 50 calls. The
|
|
61
|
+
* keys of a tick are collected and answered together, which is the shape the framework
|
|
62
|
+
* already imposes one level up: a presenter receives the PAGE (`egress.ts`).
|
|
63
|
+
*
|
|
64
|
+
* Scoped by the request's context object, which graphql-js hands identically to every
|
|
65
|
+
* resolver of one request and never shares with another — two callers must never be
|
|
66
|
+
* answered out of one read. When there is no context (a resolver called directly, as
|
|
67
|
+
* the tests do), the scope is a shared object and the tick alone bounds the batch.
|
|
68
|
+
*/
|
|
69
|
+
const batches = new WeakMap();
|
|
70
|
+
const NO_CONTEXT = {};
|
|
71
|
+
function loadByKey(ctx, entityKey, id, read, absent) {
|
|
72
|
+
const scope = ctx && typeof ctx === 'object' ? ctx : NO_CONTEXT;
|
|
73
|
+
let open = batches.get(scope);
|
|
74
|
+
if (!open) {
|
|
75
|
+
open = new Map();
|
|
76
|
+
batches.set(scope, open);
|
|
77
|
+
}
|
|
78
|
+
let batch = open.get(entityKey);
|
|
79
|
+
if (!batch) {
|
|
80
|
+
const keys = new Set();
|
|
81
|
+
// The next microtask: every sibling resolver of the page has run by then, so
|
|
82
|
+
// their keys travel together. Closed first, so the following tick opens a new one.
|
|
83
|
+
const rows = Promise.resolve().then(() => {
|
|
84
|
+
open.delete(entityKey);
|
|
85
|
+
return read([...keys]);
|
|
86
|
+
});
|
|
87
|
+
batch = { keys, rows };
|
|
88
|
+
open.set(entityKey, batch);
|
|
89
|
+
}
|
|
90
|
+
batch.keys.add(id);
|
|
91
|
+
return batch.rows.then((found) => found.get(id) ?? absent());
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Redirect specific ops to alternate handlers based on frond.config.ts overrides.
|
|
95
|
+
* For ops declaring `handler: OtherClass, method?: 'name'`, replaces the facade entry
|
|
96
|
+
* with a call into the resolved alternate handler.
|
|
97
|
+
*/
|
|
98
|
+
function applyOperationOverrides(baseFacade, overrides, app) {
|
|
99
|
+
const patched = { ...baseFacade };
|
|
100
|
+
for (const [opName, override] of Object.entries(overrides)) {
|
|
101
|
+
if (!override.handlerName)
|
|
102
|
+
continue;
|
|
103
|
+
try {
|
|
104
|
+
const altFacade = app.resolve(override.handlerName);
|
|
105
|
+
const methodName = override.method ?? opName;
|
|
106
|
+
const fn = altFacade[methodName];
|
|
107
|
+
if (typeof fn === 'function') {
|
|
108
|
+
patched[opName] = fn.bind(altFacade);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch { /* alternate handler not in DI — silent skip */ }
|
|
112
|
+
}
|
|
113
|
+
return patched;
|
|
114
|
+
}
|
|
115
|
+
// ─── Helpers ────────────────────────────────────
|
|
116
|
+
function capitalize(s) {
|
|
117
|
+
return s[0].toUpperCase() + s.slice(1);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The key an entity is filed under — case-folded, because the same entity is spelled
|
|
121
|
+
* differently depending on where its name came from: the scan yields the registration name
|
|
122
|
+
* (`authorUser`), while a card's relation target is fully lowercased by `describe`
|
|
123
|
+
* (`authoruser`). Folding both is what lets one registry serve both sources.
|
|
124
|
+
*/
|
|
125
|
+
function registryKey(entityName) {
|
|
126
|
+
return entityName.toLowerCase();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The key a relation points at. A live entity class answers with its class name; a target
|
|
130
|
+
* rebuilt from a lone card is a `{ name }` stand-in and answers with the name `describe`
|
|
131
|
+
* wrote. Both are names, which is the whole reason this resolves by name.
|
|
132
|
+
*/
|
|
133
|
+
function targetKey(target) {
|
|
134
|
+
return registryKey(String(target?.name ?? ''));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Auto-register GraphQL types and operations for all entities
|
|
138
|
+
* in the app that have a matching handler facade.
|
|
139
|
+
*
|
|
140
|
+
* Operations are driven by parsed handler signatures (from the scanner).
|
|
141
|
+
* Relations (ref/many) are auto-wired between registered entity types.
|
|
142
|
+
*/
|
|
143
|
+
/**
|
|
144
|
+
* The GraphQL type of a declared presenter view, built once per view class.
|
|
145
|
+
*
|
|
146
|
+
* Named after the field that emits it (`OrderItems`, `OrderUser`) rather than after the view
|
|
147
|
+
* class, so two fields sharing one view still land on the same type and a view used twice is
|
|
148
|
+
* registered once — Pothos refuses a duplicate type name and would take the schema down.
|
|
149
|
+
*/
|
|
150
|
+
const viewTypes = new WeakMap();
|
|
151
|
+
function viewTypeOf(builder, view, name) {
|
|
152
|
+
const known = viewTypes.get(view);
|
|
153
|
+
if (known)
|
|
154
|
+
return known;
|
|
155
|
+
const type = registerType(builder, { name, entity: view });
|
|
156
|
+
viewTypes.set(view, type);
|
|
157
|
+
return type;
|
|
158
|
+
}
|
|
159
|
+
export function registerAll(builder, app, options) {
|
|
160
|
+
// Collect registered types across all fronds for relation wiring, keyed by entity NAME.
|
|
161
|
+
//
|
|
162
|
+
// The name is the identity everywhere else in the system — `facadeFor(entity)`,
|
|
163
|
+
// `ormFor(entity)`, `schemaFor(entity)` all take one, and the table, the GraphQL type
|
|
164
|
+
// and the DI match are all derived from it. This registry keyed by class OBJECT was the
|
|
165
|
+
// lone dissent, and it cost a silent failure: a relation target that is not the very
|
|
166
|
+
// object registered (an entity rebuilt from a card, whose `to()` leaves a `{ name }`
|
|
167
|
+
// stand-in) missed the lookup, hit `if (!targetEntry) continue`, and the relation
|
|
168
|
+
// vanished from the schema without a word. `schema-sql` already resolved by name.
|
|
169
|
+
const typeRegistry = new Map();
|
|
170
|
+
// ── Pass 1: register types + operations ────────
|
|
171
|
+
for (const frond of app.fronds) {
|
|
172
|
+
const handlerMap = new Map(frond.handlers.filter((h) => !h.surface).map((h) => [h.address, h]));
|
|
173
|
+
const presenterMap = new Map((frond.presenters ?? []).map((p) => [p.entityName, p]));
|
|
174
|
+
const surfaceName = options?.surface;
|
|
175
|
+
for (const entity of frond.entities) {
|
|
176
|
+
// Membership is core's answer, not ours — one rule, read here (see App.facadeFor).
|
|
177
|
+
const facade = app.facadeFor(entity.name, surfaceName);
|
|
178
|
+
if (!facade)
|
|
179
|
+
continue;
|
|
180
|
+
if (options?.filter && !options.filter(entity, frond.name))
|
|
181
|
+
continue;
|
|
182
|
+
if (!surfaceName && entity.exposed === false)
|
|
183
|
+
continue;
|
|
184
|
+
const handler = (surfaceName
|
|
185
|
+
? frond.handlers.find((h) => h.address === entity.name && h.surface === surfaceName)
|
|
186
|
+
: undefined) ?? handlerMap.get(entity.name);
|
|
187
|
+
const typeName = capitalize(entity.name);
|
|
188
|
+
const presenterMeta = presenterMap.get(entity.name);
|
|
189
|
+
let presenter;
|
|
190
|
+
if (presenterMeta) {
|
|
191
|
+
presenter = app.presenterFor(entity.name);
|
|
192
|
+
}
|
|
193
|
+
// Use handler's output schema if declared, otherwise entity
|
|
194
|
+
const outputSchema = handler?.outputOverride
|
|
195
|
+
?? handler?.ctor?.__output
|
|
196
|
+
?? entity.entityClass;
|
|
197
|
+
const type = registerType(builder, {
|
|
198
|
+
name: typeName,
|
|
199
|
+
entity: outputSchema,
|
|
200
|
+
presenter: presenter,
|
|
201
|
+
presenterFields: presenterMeta?.fields,
|
|
202
|
+
presenterFieldMeta: presenterMeta?.fieldMeta,
|
|
203
|
+
presenterViews: presenterMeta?.views,
|
|
204
|
+
viewType: (view, fieldName) => viewTypeOf(builder, view, `${typeName}${capitalize(fieldName)}`),
|
|
205
|
+
});
|
|
206
|
+
// Track for relation wiring. The presenter's computed field names travel too: pass 2
|
|
207
|
+
// must not derive a relation over a name the author wrote.
|
|
208
|
+
typeRegistry.set(registryKey(entity.name), {
|
|
209
|
+
name: typeName, type, facade,
|
|
210
|
+
presenterFields: new Set(presenterMeta?.fields ?? []),
|
|
211
|
+
fields: fieldsOf(entity.entityClass),
|
|
212
|
+
});
|
|
213
|
+
// Apply per-op handler/method overrides: redirect specific ops to a different handler instance.
|
|
214
|
+
const opOverrides = frond.operationsOverrides;
|
|
215
|
+
const effectiveFacade = opOverrides
|
|
216
|
+
? applyOperationOverrides(facade, opOverrides, app)
|
|
217
|
+
: facade;
|
|
218
|
+
registerOperations(builder, {
|
|
219
|
+
name: typeName,
|
|
220
|
+
type,
|
|
221
|
+
facade: effectiveFacade,
|
|
222
|
+
operations: handler?.operations ?? new Map(),
|
|
223
|
+
operationsOverrides: opOverrides,
|
|
224
|
+
// What an op declares as its return becomes its GraphQL type — unless that IS
|
|
225
|
+
// the entity's own schema, which already has one.
|
|
226
|
+
viewType: (view, opName) => view === outputSchema || view === entity.entityClass
|
|
227
|
+
? type
|
|
228
|
+
: viewTypeOf(builder, view, `${typeName}${capitalize(opName)}`),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// ── Pass 2: auto-wire relations (ref → N:1, many → 1:N) ──
|
|
233
|
+
for (const [entityName, { type, fields, presenterFields }] of typeRegistry) {
|
|
234
|
+
const relationFields = {};
|
|
235
|
+
for (const [fieldName, field] of Object.entries(fields)) {
|
|
236
|
+
if (field.role?.relation?.kind === 'one') {
|
|
237
|
+
const target = field.role.relation.to();
|
|
238
|
+
if (!target)
|
|
239
|
+
continue;
|
|
240
|
+
const targetEntry = typeRegistry.get(targetKey(target));
|
|
241
|
+
if (!targetEntry)
|
|
242
|
+
continue;
|
|
243
|
+
// authorId → author, user_id → user. Both spellings, because a foreign key
|
|
244
|
+
// is named by its author and `/Id$/` alone left `user_id` untouched — the
|
|
245
|
+
// relation then took the scalar's own name and Pothos refused the duplicate,
|
|
246
|
+
// taking the WHOLE schema down with it.
|
|
247
|
+
const relationName = relationNameFor(fieldName);
|
|
248
|
+
// Nothing to strip, or the name is already taken by a field of the entity or by
|
|
249
|
+
// a presenter's computed field: the author named it, the author wins. Deriving
|
|
250
|
+
// over it would either crash the build or shadow what they wrote.
|
|
251
|
+
if (!relationName || relationName in fields || presenterFields.has(relationName))
|
|
252
|
+
continue;
|
|
253
|
+
const nullable = Anatomy.isNullable(field.shape);
|
|
254
|
+
const targetKeyName = primaryNameOf(targetEntry.fields);
|
|
255
|
+
const targetList = targetEntry.facade.list;
|
|
256
|
+
relationFields[relationName] = (t) => t.field({
|
|
257
|
+
type: targetEntry.type,
|
|
258
|
+
nullable,
|
|
259
|
+
resolve: (parent, _args, ctx) => {
|
|
260
|
+
const fk = parent[fieldName];
|
|
261
|
+
if (fk == null)
|
|
262
|
+
return null;
|
|
263
|
+
// A door that serves no list — a handler narrowed to `findById` — keeps the
|
|
264
|
+
// row-at-a-time path rather than losing the relation entirely.
|
|
265
|
+
if (typeof targetList !== 'function') {
|
|
266
|
+
return targetEntry.facade.findById({ params: { id: fk }, query: {}, body: undefined, state: {} });
|
|
267
|
+
}
|
|
268
|
+
return loadByKey(ctx, directionKey(targetKey(target), targetKeyName), String(fk), (ids) =>
|
|
269
|
+
// The door the `many` dual already uses, with a SET where it names one
|
|
270
|
+
// value. Nothing new is published: a criterion learned to name several.
|
|
271
|
+
readInSlices(ids, async (slice) => {
|
|
272
|
+
const result = await targetList.call(targetEntry.facade, {
|
|
273
|
+
params: {}, query: { where: { [targetKeyName]: slice } }, body: undefined, state: {},
|
|
274
|
+
});
|
|
275
|
+
const rows = Array.isArray(result) ? result : result?.items ?? result?.data ?? [];
|
|
276
|
+
return new Map(rows.map((row) => [String(row?.[targetKeyName]), row]));
|
|
277
|
+
}, keepEach), () => null);
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (field.role?.relation?.kind === 'many') {
|
|
282
|
+
const target = field.role.relation.to();
|
|
283
|
+
if (!target)
|
|
284
|
+
continue;
|
|
285
|
+
const targetEntry = typeRegistry.get(targetKey(target));
|
|
286
|
+
if (!targetEntry)
|
|
287
|
+
continue;
|
|
288
|
+
// Trouver la FK inverse sur l'entité cible (la relation « one » qui pointe ici).
|
|
289
|
+
// Read off the registry, not off the target object: a target rebuilt from a card is
|
|
290
|
+
// a `{ name }` stand-in with no fields to walk, and the registry already holds them.
|
|
291
|
+
const reverseFk = Object.entries(targetEntry.fields).find(([, f]) => f.role?.relation?.kind === 'one'
|
|
292
|
+
&& targetKey(f.role.relation.to()) === entityName);
|
|
293
|
+
if (!reverseFk)
|
|
294
|
+
continue;
|
|
295
|
+
const [reverseFkName] = reverseFk;
|
|
296
|
+
relationFields[fieldName] = (t) => t.field({
|
|
297
|
+
type: [targetEntry.type],
|
|
298
|
+
resolve: (parent, _args, ctx) => {
|
|
299
|
+
const id = parent.id;
|
|
300
|
+
if (id == null)
|
|
301
|
+
return [];
|
|
302
|
+
// The same batch as its `one` dual, one query for the whole page — the two
|
|
303
|
+
// directions differ only in what a key answers: one row there, a group here.
|
|
304
|
+
//
|
|
305
|
+
// `where` — un critère se nomme. Passé à la racine de la query, il retombait
|
|
306
|
+
// dans les options de `list()`, qui ignore ce qu'elle ne connaît pas : la
|
|
307
|
+
// relation rendait alors TOUTE la table cible, sans un mot.
|
|
308
|
+
return loadByKey(ctx, directionKey(targetKey(target), reverseFkName), String(id), (ids) => readInSlices(ids, async (slice) => {
|
|
309
|
+
const result = await targetEntry.facade.list({
|
|
310
|
+
params: {}, query: { where: { [reverseFkName]: slice } }, body: undefined, state: {},
|
|
311
|
+
});
|
|
312
|
+
const rows = Array.isArray(result) ? result : result?.items ?? result?.data ?? [];
|
|
313
|
+
const grouped = new Map();
|
|
314
|
+
for (const row of rows) {
|
|
315
|
+
const key = String(row?.[reverseFkName]);
|
|
316
|
+
const held = grouped.get(key);
|
|
317
|
+
if (held)
|
|
318
|
+
held.push(row);
|
|
319
|
+
else
|
|
320
|
+
grouped.set(key, [row]);
|
|
321
|
+
}
|
|
322
|
+
return grouped;
|
|
323
|
+
}, concatEach), () => []);
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (Object.keys(relationFields).length > 0) {
|
|
329
|
+
builder.objectFields(type, (t) => {
|
|
330
|
+
const result = {};
|
|
331
|
+
for (const [name, factory] of Object.entries(relationFields)) {
|
|
332
|
+
result[name] = factory(t);
|
|
333
|
+
}
|
|
334
|
+
return result;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
//# sourceMappingURL=auto-register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-register.js","sourceRoot":"","sources":["../src/auto-register.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GraphQL surface, in two calls: derive the schema, then mount it.
|
|
3
|
+
*
|
|
4
|
+
* The Pothos primitives `registerAll` stands on live one import away, under
|
|
5
|
+
* `@fougere/adapter-graphql/pothos`. They are a complement — a field the projection cannot
|
|
6
|
+
* derive — never a second way to build what it already gives. Offering them at the same
|
|
7
|
+
* rank made that hierarchy invisible: an agent looking for "how do I declare a type" found
|
|
8
|
+
* three doors and rebuilt two hundred lines by hand (measured 2026-08-02).
|
|
9
|
+
*/
|
|
10
|
+
export { registerAll } from './auto-register.js';
|
|
11
|
+
export type { RegisterAllOptions } from './auto-register.js';
|
|
12
|
+
export { registerGraphQL } from './serve.js';
|
|
13
|
+
export type { GraphQLServeOptions } from './serve.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The GraphQL surface, in two calls: derive the schema, then mount it.
|
|
3
|
+
*
|
|
4
|
+
* The Pothos primitives `registerAll` stands on live one import away, under
|
|
5
|
+
* `@fougere/adapter-graphql/pothos`. They are a complement — a field the projection cannot
|
|
6
|
+
* derive — never a second way to build what it already gives. Offering them at the same
|
|
7
|
+
* rank made that hierarchy invisible: an agent looking for "how do I declare a type" found
|
|
8
|
+
* three doors and rebuilt two hundred lines by hand (measured 2026-08-02).
|
|
9
|
+
*/
|
|
10
|
+
export { registerAll } from './auto-register.js';
|
|
11
|
+
export { registerGraphQL } from './serve.js';
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Pothos primitives — for what `registerAll` cannot derive, never to replace it.
|
|
3
|
+
*
|
|
4
|
+
* Reach for these to add a field the projection has no way to know about. Rebuilding
|
|
5
|
+
* types, inputs and operations with them reimplements `registerAll` by hand and drops
|
|
6
|
+
* what it wires for free: relations, and a presenter's computed fields.
|
|
7
|
+
*/
|
|
8
|
+
export { registerType, registerInput, registerOperations, registerObjectType } from './pothos.js';
|
|
9
|
+
export type { TypeConfig, InputConfig, OperationsConfig, ObjectFieldDef } from './pothos.js';
|
|
10
|
+
//# sourceMappingURL=pothos-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pothos-entry.d.ts","sourceRoot":"","sources":["../src/pothos-entry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClG,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Pothos primitives — for what `registerAll` cannot derive, never to replace it.
|
|
3
|
+
*
|
|
4
|
+
* Reach for these to add a field the projection has no way to know about. Rebuilding
|
|
5
|
+
* types, inputs and operations with them reimplements `registerAll` by hand and drops
|
|
6
|
+
* what it wires for free: relations, and a presenter's computed fields.
|
|
7
|
+
*/
|
|
8
|
+
export { registerType, registerInput, registerOperations, registerObjectType } from './pothos.js';
|
|
9
|
+
//# sourceMappingURL=pothos-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pothos-entry.js","sourceRoot":"","sources":["../src/pothos-entry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC"}
|