joist-graphql-resolver-utils 2.3.0-next.7 → 2.3.0-next.71
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/build/context.cjs +2 -0
- package/build/context.d.cts +7 -0
- package/build/context.d.cts.map +1 -0
- package/build/context.d.mts +7 -0
- package/build/context.d.mts.map +1 -0
- package/build/context.js +2 -3
- package/build/cursorPagination.cjs +104 -0
- package/build/cursorPagination.cjs.map +1 -0
- package/build/cursorPagination.d.cts +43 -0
- package/build/cursorPagination.d.cts.map +1 -0
- package/build/cursorPagination.d.mts +43 -0
- package/build/cursorPagination.d.mts.map +1 -0
- package/build/cursorPagination.js +88 -62
- package/build/cursorPagination.js.map +1 -1
- package/build/entityResolver.cjs +95 -0
- package/build/entityResolver.cjs.map +1 -0
- package/build/entityResolver.d.cts +23 -0
- package/build/entityResolver.d.cts.map +1 -0
- package/build/entityResolver.d.mts +23 -0
- package/build/entityResolver.d.mts.map +1 -0
- package/build/entityResolver.js +84 -135
- package/build/entityResolver.js.map +1 -1
- package/build/hint.cjs +50 -0
- package/build/hint.cjs.map +1 -0
- package/build/hint.d.cts +12 -0
- package/build/hint.d.cts.map +1 -0
- package/build/hint.d.mts +12 -0
- package/build/hint.d.mts.map +1 -0
- package/build/hint.js +36 -65
- package/build/hint.js.map +1 -1
- package/build/index.cjs +14 -0
- package/build/index.d.cts +6 -0
- package/build/index.d.mts +6 -0
- package/build/index.js +6 -17
- package/build/limitPagination.cjs +68 -0
- package/build/limitPagination.cjs.map +1 -0
- package/build/limitPagination.d.cts +34 -0
- package/build/limitPagination.d.cts.map +1 -0
- package/build/limitPagination.d.mts +34 -0
- package/build/limitPagination.d.mts.map +1 -0
- package/build/limitPagination.js +62 -52
- package/build/limitPagination.js.map +1 -1
- package/build/makeRunInputMutation.cjs +21 -0
- package/build/makeRunInputMutation.cjs.map +1 -0
- package/build/{makeRunInputMutation.d.ts → makeRunInputMutation.d.cts} +9 -7
- package/build/makeRunInputMutation.d.cts.map +1 -0
- package/build/makeRunInputMutation.d.mts +24 -0
- package/build/makeRunInputMutation.d.mts.map +1 -0
- package/build/makeRunInputMutation.js +16 -14
- package/build/makeRunInputMutation.js.map +1 -1
- package/build/makeRunObjectField.cjs +22 -0
- package/build/makeRunObjectField.cjs.map +1 -0
- package/build/{makeRunObjectField.d.ts → makeRunObjectField.d.cts} +7 -5
- package/build/makeRunObjectField.d.cts.map +1 -0
- package/build/makeRunObjectField.d.mts +16 -0
- package/build/makeRunObjectField.d.mts.map +1 -0
- package/build/makeRunObjectField.js +17 -16
- package/build/makeRunObjectField.js.map +1 -1
- package/build/makeRunObjectFields.cjs +24 -0
- package/build/makeRunObjectFields.cjs.map +1 -0
- package/build/{makeRunObjectFields.d.ts → makeRunObjectFields.d.cts} +8 -8
- package/build/makeRunObjectFields.d.cts.map +1 -0
- package/build/makeRunObjectFields.d.mts +15 -0
- package/build/makeRunObjectFields.d.mts.map +1 -0
- package/build/makeRunObjectFields.js +19 -19
- package/build/makeRunObjectFields.js.map +1 -1
- package/build/makeRunQuery.cjs +20 -0
- package/build/makeRunQuery.cjs.map +1 -0
- package/build/{makeRunQuery.d.ts → makeRunQuery.d.cts} +7 -5
- package/build/makeRunQuery.d.cts.map +1 -0
- package/build/makeRunQuery.d.mts +20 -0
- package/build/makeRunQuery.d.mts.map +1 -0
- package/build/makeRunQuery.js +15 -14
- package/build/makeRunQuery.js.map +1 -1
- package/build/paginationUtils.cjs +34 -0
- package/build/paginationUtils.cjs.map +1 -0
- package/build/paginationUtils.d.cts +17 -0
- package/build/paginationUtils.d.cts.map +1 -0
- package/build/paginationUtils.d.mts +17 -0
- package/build/paginationUtils.d.mts.map +1 -0
- package/build/paginationUtils.js +30 -4
- package/build/paginationUtils.js.map +1 -1
- package/build/saveEntity.cjs +24 -0
- package/build/saveEntity.cjs.map +1 -0
- package/build/saveEntity.d.cts +15 -0
- package/build/saveEntity.d.cts.map +1 -0
- package/build/saveEntity.d.mts +15 -0
- package/build/saveEntity.d.mts.map +1 -0
- package/build/saveEntity.js +15 -13
- package/build/saveEntity.js.map +1 -1
- package/build/tests.cjs +9 -0
- package/build/tests.d.cts +6 -0
- package/build/tests.d.mts +6 -0
- package/build/tests.js +5 -27
- package/build/typeUtils.cjs +2 -0
- package/build/typeUtils.d.cts +11 -0
- package/build/typeUtils.d.cts.map +1 -0
- package/build/typeUtils.d.mts +11 -0
- package/build/typeUtils.d.mts.map +1 -0
- package/build/typeUtils.js +2 -3
- package/package.json +74 -16
- package/build/context.d.ts +0 -4
- package/build/context.d.ts.map +0 -1
- package/build/context.js.map +0 -1
- package/build/cursorPagination.d.ts +0 -33
- package/build/cursorPagination.d.ts.map +0 -1
- package/build/entityResolver.d.ts +0 -25
- package/build/entityResolver.d.ts.map +0 -1
- package/build/hint.d.ts +0 -9
- package/build/hint.d.ts.map +0 -1
- package/build/index.d.ts +0 -6
- package/build/index.d.ts.map +0 -1
- package/build/index.js.map +0 -1
- package/build/limitPagination.d.ts +0 -28
- package/build/limitPagination.d.ts.map +0 -1
- package/build/makeRunInputMutation.d.ts.map +0 -1
- package/build/makeRunObjectField.d.ts.map +0 -1
- package/build/makeRunObjectFields.d.ts.map +0 -1
- package/build/makeRunQuery.d.ts.map +0 -1
- package/build/paginationUtils.d.ts +0 -7
- package/build/paginationUtils.d.ts.map +0 -1
- package/build/saveEntity.d.ts +0 -12
- package/build/saveEntity.d.ts.map +0 -1
- package/build/tests.d.ts +0 -6
- package/build/tests.d.ts.map +0 -1
- package/build/tests.js.map +0 -1
- package/build/typeUtils.d.ts +0 -10
- package/build/typeUtils.d.ts.map +0 -1
- package/build/typeUtils.js.map +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Resolver } from "./context.mjs";
|
|
2
|
+
import { Collection, Entity, EntityMetadata, IdOf, MaybeAbstractEntityConstructor, Property, ReactiveGetter, ReadOnlyCollection, Reference } from "joist-core";
|
|
3
|
+
//#region src/entityResolver.d.ts
|
|
4
|
+
type GraphQLPrimitive = string | Date | boolean | number | bigint | null | undefined;
|
|
5
|
+
/**
|
|
6
|
+
* Maps properties like `Entity.firstName: string` to field resolver functions like `firstName(): Promise<string>`.
|
|
7
|
+
*
|
|
8
|
+
* Note that we don't necessarily know/care if `firstName` is in the `Entity` GraphQL type, we just map
|
|
9
|
+
* every field to a potential resolver, and then will let the `EntityResolvers` type-check effectively
|
|
10
|
+
* do the union of "what's defined on the ORM type vs. what's defined on the GraphQL type".
|
|
11
|
+
*
|
|
12
|
+
* Note this might require setting GraphQL options like `requireResolversToMatchSchema: ignore` to avoid
|
|
13
|
+
* the GraphQL infra complaining about the extra field resolvers that Joist creates for fields that
|
|
14
|
+
* are not technically mapped in your GraphQL schema.
|
|
15
|
+
*/
|
|
16
|
+
type EntityResolver<T extends Entity> = { [P in keyof T]: P extends "id" ? Resolver<T, Record<string, any>, IdOf<T>> : T[P] extends GraphQLPrimitive | GraphQLPrimitive[] ? Resolver<T, Record<string, any>, T[P]> : T[P] extends Collection<any, infer U> ? Resolver<T, Record<string, any>, U[]> : T[P] extends ReadOnlyCollection<any, infer U> ? Resolver<T, Record<string, any>, U[]> : T[P] extends Reference<any, infer U, infer N> ? Resolver<T, Record<string, any>, U | N> : T[P] extends Property<any, infer V> ? Resolver<T, Record<string, any>, V> : T[P] extends ReactiveGetter<any, infer V> ? Resolver<T, Record<string, any>, V> : T[P] extends Promise<infer V> ? Resolver<T, Record<string, any>, V> : T[P] extends (() => Promise<infer V>) ? Resolver<T, Record<string, any>, V> : T[P] extends (() => infer V) ? Resolver<T, Record<string, any>, V> : Resolver<T, Record<string, any>, T[P]>; };
|
|
17
|
+
/**
|
|
18
|
+
* Creates field resolvers for each of the fields on our entity.
|
|
19
|
+
*/
|
|
20
|
+
declare function entityResolver<T extends Entity, A extends Record<string, keyof T> = {}>(entity: MaybeAbstractEntityConstructor<T> | EntityMetadata<T>, aliases?: A): EntityResolver<T> & { [K in keyof A]: EntityResolver<T>[A[K]]; };
|
|
21
|
+
//#endregion
|
|
22
|
+
export { EntityResolver, entityResolver };
|
|
23
|
+
//# sourceMappingURL=entityResolver.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entityResolver.d.mts","names":[],"sources":["../src/entityResolver.ts"],"mappings":";;;KAwCK,4BAA4B;;;;;;;;;;;;KAarB,eAAe,UAAU,aAClC,WAAW,IAAI,iBACZ,SAAS,GAAG,qBAAqB,KAAK,MACtC,EAAE,WAAW,mBAAmB,qBAC9B,SAAS,GAAG,qBAAqB,EAAE,MACnC,EAAE,WAAW,sBAAsB,KACjC,SAAS,GAAG,qBAAqB,OACjC,EAAE,WAAW,8BAA8B,KACzC,SAAS,GAAG,qBAAqB,OACjC,EAAE,WAAW,qBAAqB,SAAS,KACzC,SAAS,GAAG,qBAAqB,IAAI,KACrC,EAAE,WAAW,oBAAoB,KAC/B,SAAS,GAAG,qBAAqB,KACjC,EAAE,WAAW,0BAA0B,KACrC,SAAS,GAAG,qBAAqB,KACjC,EAAE,WAAW,cAAc,KACzB,SAAS,GAAG,qBAAqB,KACjC,EAAE,kBAAiB,cAAc,MAC/B,SAAS,GAAG,qBAAqB,KACjC,EAAE,wBAAuB,KACvB,SAAS,GAAG,qBAAqB,KACjC,SAAS,GAAG,qBAAqB,EAAE;;;;iBAM3C,eAAe,UAAU,QAAQ,UAAU,qBAAqB,SAC9E,QAAQ,+BAA+B,KAAK,eAAe,IAC3D,UAAU,IACT,eAAe,QAAQ,WAAW,IAAI,eAAe,GAAG,EAAE"}
|
package/build/entityResolver.js
CHANGED
|
@@ -1,145 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import "./context.js";
|
|
2
|
+
import { convertInfoToLoadHint } from "./hint.js";
|
|
3
|
+
import "graphql/type";
|
|
4
|
+
import { getMetadata, getProperties, isAsyncProperty, isCollection, isLoadedAsyncProperty, isLoadedCollection, isLoadedLazyField, isLoadedProperty, isLoadedReadOnlyCollection, isLoadedReference, isManyToOneField, isOneToManyField, isProperty, isReactiveGetter, isReadOnlyCollection, isReference } from "joist-core";
|
|
5
|
+
//#region src/entityResolver.ts
|
|
6
6
|
/**
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
* Creates field resolvers for each of the fields on our entity.
|
|
8
|
+
*/
|
|
9
9
|
function entityResolver(entity, aliases) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
return collection.load();
|
|
83
|
-
},
|
|
84
|
-
]);
|
|
85
|
-
const ormResolvers = Object.fromEntries([...primitiveResolvers, ...referenceResolvers, ...collectionResolvers]);
|
|
86
|
-
// Look for non-orm properties on the domain object's prototype
|
|
87
|
-
// and on an instance of the domain object itself to get
|
|
88
|
-
// non-prototype properties like CustomReferences
|
|
89
|
-
const alreadyFoundKeys = Object.keys(ormResolvers);
|
|
90
|
-
const customProperties = Object.keys((0, joist_core_1.getProperties)(entityMetadata)).filter((n) => !alreadyFoundKeys.includes(n));
|
|
91
|
-
const customResolvers = customProperties.map((key) => [
|
|
92
|
-
key,
|
|
93
|
-
(entity) => {
|
|
94
|
-
const property = entity[key];
|
|
95
|
-
if (typeof property === "function") {
|
|
96
|
-
// Support methods like `async name(): Promise<string>`
|
|
97
|
-
return property.apply(entity);
|
|
98
|
-
}
|
|
99
|
-
else if ((0, joist_core_1.isReactiveGetter)(property)) {
|
|
100
|
-
return property.get;
|
|
101
|
-
}
|
|
102
|
-
else if ((0, joist_core_1.isReference)(property) || (0, joist_core_1.isCollection)(property) || (0, joist_core_1.isProperty)(property)) {
|
|
103
|
-
if ((0, joist_core_1.isLoadedReference)(property) || (0, joist_core_1.isLoadedCollection)(property) || (0, joist_core_1.isLoadedProperty)(property)) {
|
|
104
|
-
return property.get;
|
|
105
|
-
}
|
|
106
|
-
// ...we need to know the `property.otherMetadata()` return type, which isn't available right now
|
|
107
|
-
// const loadHint = convertInfoToLoadHint(getMetadata(entity), info);
|
|
108
|
-
// if (loadHint) {
|
|
109
|
-
// return entity.em.populate(entity, loadHint).then(() => (property as any).get);
|
|
110
|
-
// }
|
|
111
|
-
return property.load();
|
|
112
|
-
}
|
|
113
|
-
else if ((0, joist_core_1.isReadOnlyCollection)(property)) {
|
|
114
|
-
if ((0, joist_core_1.isLoadedReadOnlyCollection)(property)) {
|
|
115
|
-
return property.get;
|
|
116
|
-
}
|
|
117
|
-
return property.load();
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
return property;
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
]);
|
|
124
|
-
let resolvers = {
|
|
125
|
-
id: idResolver,
|
|
126
|
-
...ormResolvers,
|
|
127
|
-
...Object.fromEntries(customResolvers),
|
|
128
|
-
};
|
|
129
|
-
if (aliases) {
|
|
130
|
-
Object.entries(aliases).forEach(([alias, field]) => {
|
|
131
|
-
resolvers[alias] = resolvers[field];
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
return resolvers;
|
|
10
|
+
const entityMetadata = getMetadata(entity);
|
|
11
|
+
const idResolver = (entityOrId) => {
|
|
12
|
+
return typeof entityOrId === "string" ? entityOrId : entityOrId.id;
|
|
13
|
+
};
|
|
14
|
+
const primitiveResolvers = Object.values(entityMetadata.allFields).filter((ormField) => !isPrimaryKeyField(ormField) && !isReferenceField(ormField) && !isCollectionField(ormField)).map((ormField) => {
|
|
15
|
+
if ("derived" in ormField && ormField.derived === "async") return [ormField.fieldName, (entity) => entity[ormField.fieldName].get];
|
|
16
|
+
else if ("lazy" in ormField && ormField.lazy) return [ormField.fieldName, (entity) => {
|
|
17
|
+
const lazyField = entity[ormField.fieldName];
|
|
18
|
+
return isLoadedLazyField(lazyField) ? lazyField.get : lazyField.load();
|
|
19
|
+
}];
|
|
20
|
+
else return [ormField.fieldName, (entity) => entity[ormField.fieldName]];
|
|
21
|
+
});
|
|
22
|
+
const referenceResolvers = Object.values(entityMetadata.allFields).filter((ormField) => isReferenceField(ormField)).map((ormField) => [ormField.fieldName, (entity, args, ctx, info) => {
|
|
23
|
+
if ((ormField.kind === "m2o" || ormField.kind === "poly") && info?.fieldNodes.length === 1) {
|
|
24
|
+
const selectionSet = info.fieldNodes[0].selectionSet;
|
|
25
|
+
const hasAbstractType = ormField.kind === "m2o" && ormField.otherMetadata().inheritanceType !== void 0 || ormField.kind === "poly" && ormField.components.some((c) => c.otherMetadata().inheritanceType !== void 0);
|
|
26
|
+
if (selectionSet && !hasAbstractType) {
|
|
27
|
+
if (selectionSet.selections.length === 1 && selectionSet.selections[0].kind === "Field" && selectionSet.selections[0].name.value === "id") return entity[ormField.fieldName].idMaybe;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const reference = entity[ormField.fieldName];
|
|
31
|
+
if (isLoadedReference(reference)) return reference.get;
|
|
32
|
+
if (info && (isManyToOneField(ormField) || isOneToManyField(ormField))) {
|
|
33
|
+
const loadHint = convertInfoToLoadHint(ormField.otherMetadata(), info);
|
|
34
|
+
if (loadHint) {
|
|
35
|
+
const parentHint = { [ormField.fieldName]: loadHint };
|
|
36
|
+
return entity.em.populate(entity, parentHint).then(() => reference.get);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return reference.load();
|
|
40
|
+
}]);
|
|
41
|
+
const collectionResolvers = Object.values(entityMetadata.allFields).filter((ormField) => isCollectionField(ormField)).map((ormField) => [ormField.fieldName, (entity, args, ctx, info) => {
|
|
42
|
+
const field = ormField;
|
|
43
|
+
const collection = entity[field.fieldName];
|
|
44
|
+
if (isLoadedCollection(collection)) return collection.get;
|
|
45
|
+
if (info) {
|
|
46
|
+
const loadHint = convertInfoToLoadHint(field.otherMetadata(), info);
|
|
47
|
+
if (loadHint) {
|
|
48
|
+
const parentHint = { [field.fieldName]: loadHint };
|
|
49
|
+
return entity.em.populate(entity, parentHint).then(() => collection.get);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return collection.load();
|
|
53
|
+
}]);
|
|
54
|
+
const ormResolvers = Object.fromEntries([
|
|
55
|
+
...primitiveResolvers,
|
|
56
|
+
...referenceResolvers,
|
|
57
|
+
...collectionResolvers
|
|
58
|
+
]);
|
|
59
|
+
const alreadyFoundKeys = Object.keys(ormResolvers);
|
|
60
|
+
const customResolvers = Object.keys(getProperties(entityMetadata)).filter((n) => !alreadyFoundKeys.includes(n)).map((key) => [key, (entity) => {
|
|
61
|
+
const property = entity[key];
|
|
62
|
+
if (typeof property === "function") return property.apply(entity);
|
|
63
|
+
else if (isReactiveGetter(property)) return property.get;
|
|
64
|
+
else if (isReference(property) || isCollection(property) || isProperty(property) || isAsyncProperty(property)) {
|
|
65
|
+
if (isLoadedReference(property) || isLoadedCollection(property) || isLoadedProperty(property) || isLoadedAsyncProperty(property)) return property.get;
|
|
66
|
+
return property.load();
|
|
67
|
+
} else if (isReadOnlyCollection(property)) {
|
|
68
|
+
if (isLoadedReadOnlyCollection(property)) return property.get;
|
|
69
|
+
return property.load();
|
|
70
|
+
} else return property;
|
|
71
|
+
}]);
|
|
72
|
+
let resolvers = {
|
|
73
|
+
id: idResolver,
|
|
74
|
+
...ormResolvers,
|
|
75
|
+
...Object.fromEntries(customResolvers)
|
|
76
|
+
};
|
|
77
|
+
if (aliases) Object.entries(aliases).forEach(([alias, field]) => {
|
|
78
|
+
resolvers[alias] = resolvers[field];
|
|
79
|
+
});
|
|
80
|
+
return resolvers;
|
|
135
81
|
}
|
|
136
82
|
function isReferenceField(ormField) {
|
|
137
|
-
|
|
83
|
+
return ormField.kind === "m2o" || ormField.kind === "o2o" || ormField.kind === "poly";
|
|
138
84
|
}
|
|
139
85
|
function isCollectionField(ormField) {
|
|
140
|
-
|
|
86
|
+
return ormField.kind === "o2m" || ormField.kind === "m2m";
|
|
141
87
|
}
|
|
142
88
|
function isPrimaryKeyField(ormField) {
|
|
143
|
-
|
|
89
|
+
return ormField.kind === "primaryKey";
|
|
144
90
|
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { entityResolver };
|
|
93
|
+
|
|
145
94
|
//# sourceMappingURL=entityResolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityResolver.js","sourceRoot":"","sources":["../src/entityResolver.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entityResolver.js","names":[],"sources":["../src/entityResolver.ts"],"sourcesContent":["import { type GraphQLResolveInfo } from \"graphql/type\";\nimport {\n type Collection,\n type Entity,\n type EntityMetadata,\n type Field,\n type IdOf,\n type LoadHint,\n type ManyToManyField,\n type ManyToOneField,\n type MaybeAbstractEntityConstructor,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PrimaryKeyField,\n type Property,\n type ReactiveGetter,\n type ReadOnlyCollection,\n type Reference,\n getMetadata,\n getProperties,\n isAsyncProperty,\n isCollection,\n isLoadedAsyncProperty,\n isLoadedCollection,\n isLoadedLazyField,\n isLoadedProperty,\n isLoadedReadOnlyCollection,\n isLoadedReference,\n isManyToOneField,\n isOneToManyField,\n isProperty,\n isReactiveGetter,\n isReadOnlyCollection,\n isReference,\n} from \"joist-core\";\n\nimport { type Resolver } from \"./context.ts\";\nimport { convertInfoToLoadHint } from \"./hint.ts\";\n\ntype GraphQLPrimitive = string | Date | boolean | number | bigint | null | undefined;\n\n/**\n * Maps properties like `Entity.firstName: string` to field resolver functions like `firstName(): Promise<string>`.\n *\n * Note that we don't necessarily know/care if `firstName` is in the `Entity` GraphQL type, we just map\n * every field to a potential resolver, and then will let the `EntityResolvers` type-check effectively\n * do the union of \"what's defined on the ORM type vs. what's defined on the GraphQL type\".\n *\n * Note this might require setting GraphQL options like `requireResolversToMatchSchema: ignore` to avoid\n * the GraphQL infra complaining about the extra field resolvers that Joist creates for fields that\n * are not technically mapped in your GraphQL schema.\n */\nexport type EntityResolver<T extends Entity> = {\n [P in keyof T]: P extends \"id\"\n ? Resolver<T, Record<string, any>, IdOf<T>>\n : T[P] extends GraphQLPrimitive | GraphQLPrimitive[]\n ? Resolver<T, Record<string, any>, T[P]>\n : T[P] extends Collection<any, infer U>\n ? Resolver<T, Record<string, any>, U[]>\n : T[P] extends ReadOnlyCollection<any, infer U>\n ? Resolver<T, Record<string, any>, U[]>\n : T[P] extends Reference<any, infer U, infer N>\n ? Resolver<T, Record<string, any>, U | N>\n : T[P] extends Property<any, infer V>\n ? Resolver<T, Record<string, any>, V>\n : T[P] extends ReactiveGetter<any, infer V>\n ? Resolver<T, Record<string, any>, V>\n : T[P] extends Promise<infer V>\n ? Resolver<T, Record<string, any>, V>\n : T[P] extends () => Promise<infer V>\n ? Resolver<T, Record<string, any>, V>\n : T[P] extends () => infer V\n ? Resolver<T, Record<string, any>, V>\n : Resolver<T, Record<string, any>, T[P]>;\n};\n\n/**\n * Creates field resolvers for each of the fields on our entity.\n */\nexport function entityResolver<T extends Entity, A extends Record<string, keyof T> = {}>(\n entity: MaybeAbstractEntityConstructor<T> | EntityMetadata<T>,\n aliases?: A,\n): EntityResolver<T> & { [K in keyof A]: EntityResolver<T>[A[K]] } {\n const entityMetadata = getMetadata(entity as any);\n\n const idResolver = (entityOrId: T | string) => {\n return typeof entityOrId === \"string\" ? entityOrId : entityOrId.id;\n };\n\n const primitiveResolvers = Object.values(entityMetadata.allFields)\n .filter((ormField) => !isPrimaryKeyField(ormField) && !isReferenceField(ormField) && !isCollectionField(ormField))\n .map((ormField) => {\n if (\"derived\" in ormField && ormField.derived === \"async\") {\n return [ormField.fieldName, (entity: T) => (entity as any)[ormField.fieldName].get];\n } else if (\"lazy\" in ormField && ormField.lazy) {\n // `lazy` columns are excluded from the default SELECT and exposed as `LazyField`s, so put the\n // value on the wire by loading it on demand (or reading `.get` if already loaded/populated).\n return [\n ormField.fieldName,\n (entity: T) => {\n const lazyField = (entity as any)[ormField.fieldName];\n return isLoadedLazyField(lazyField) ? lazyField.get : lazyField.load();\n },\n ];\n } else {\n // Currently, we only support primitives, i.e. strings/numbers/etc. and not collections.\n return [ormField.fieldName, (entity: T) => (entity as any)[ormField.fieldName]];\n }\n });\n\n const referenceResolvers: [string, Resolver<any, any, any>][] = Object.values(entityMetadata.allFields)\n .filter((ormField) => isReferenceField(ormField))\n .map((ormField) => [\n ormField.fieldName,\n (entity: T, args, ctx, info: GraphQLResolveInfo | undefined) => {\n // Use the `info` to see if the query is only returning `{ id }` and if so avoid fetching the entity\n if ((ormField.kind === \"m2o\" || ormField.kind === \"poly\") && info?.fieldNodes.length === 1) {\n const selectionSet = info.fieldNodes[0].selectionSet;\n // We can't do this if the expected return type uses inheritance, as graphql wouldn't know how to map to a\n // resolver with just an id since there could be multiple implementations\n const hasAbstractType =\n (ormField.kind === \"m2o\" && ormField.otherMetadata().inheritanceType !== undefined) ||\n (ormField.kind === \"poly\" &&\n ormField.components.some((c) => c.otherMetadata().inheritanceType !== undefined));\n if (selectionSet && !hasAbstractType) {\n if (\n selectionSet.selections.length === 1 &&\n selectionSet.selections[0].kind === \"Field\" &&\n selectionSet.selections[0].name.value === \"id\"\n ) {\n // This is cheating and returning the \"wrong root\", but our `id` field resolvers\n // knows to look for it, to optimize this case and avoiding the unnecessary load\n return (entity as any)[ormField.fieldName].idMaybe;\n }\n }\n }\n const reference = (entity as any)[ormField.fieldName];\n if (isLoadedReference(reference)) {\n return reference.get;\n }\n // We skip polys b/c they can't have load hints anyway\n if (info && (isManyToOneField(ormField) || isOneToManyField(ormField))) {\n // See if we can populate the collection from the GraphQL selection set\n const loadHint = convertInfoToLoadHint(ormField.otherMetadata(), info);\n if (loadHint) {\n const parentHint = { [ormField.fieldName]: loadHint } as LoadHint<T>;\n return entity.em.populate(entity, parentHint).then(() => reference.get);\n }\n }\n return reference.load();\n },\n ]);\n\n const collectionResolvers: [string, Resolver<T, any, any>][] = Object.values(entityMetadata.allFields)\n .filter((ormField) => isCollectionField(ormField))\n .map((ormField) => [\n ormField.fieldName,\n (entity, args, ctx, info: GraphQLResolveInfo | undefined) => {\n const field = ormField as OneToManyField | ManyToManyField;\n const collection = (entity as any)[field.fieldName];\n if (isLoadedCollection(collection)) {\n return collection.get;\n }\n if (info) {\n // See if we can populate the collection from the GraphQL selection set\n const loadHint = convertInfoToLoadHint(field.otherMetadata(), info);\n if (loadHint) {\n const parentHint = { [field.fieldName]: loadHint } as LoadHint<T>;\n return entity.em.populate(entity, parentHint).then(() => collection.get);\n }\n }\n return collection.load();\n },\n ]);\n\n const ormResolvers = Object.fromEntries([...primitiveResolvers, ...referenceResolvers, ...collectionResolvers]);\n\n // Look for non-orm properties on the domain object's prototype\n // and on an instance of the domain object itself to get\n // non-prototype properties like CustomReferences\n const alreadyFoundKeys = Object.keys(ormResolvers);\n const customProperties = Object.keys(getProperties(entityMetadata)).filter((n) => !alreadyFoundKeys.includes(n));\n const customResolvers: [string, Resolver<T, any, any>][] = customProperties.map((key) => [\n key,\n (entity) => {\n const property = (entity as any)[key];\n if (typeof property === \"function\") {\n // Support methods like `async name(): Promise<string>`\n return (property as Function).apply(entity);\n } else if (isReactiveGetter(property)) {\n return property.get;\n } else if (isReference(property) || isCollection(property) || isProperty(property) || isAsyncProperty(property)) {\n if (\n isLoadedReference(property) ||\n isLoadedCollection(property) ||\n isLoadedProperty(property) ||\n isLoadedAsyncProperty(property)\n ) {\n return property.get;\n }\n // ...we need to know the `property.otherMetadata()` return type, which isn't available right now\n // const loadHint = convertInfoToLoadHint(getMetadata(entity), info);\n // if (loadHint) {\n // return entity.em.populate(entity, loadHint).then(() => (property as any).get);\n // }\n return property.load();\n } else if (isReadOnlyCollection(property)) {\n if (isLoadedReadOnlyCollection(property)) {\n return property.get;\n }\n return property.load();\n } else {\n return property;\n }\n },\n ]);\n\n let resolvers = {\n id: idResolver,\n ...ormResolvers,\n ...Object.fromEntries(customResolvers),\n } as any;\n\n if (aliases) {\n Object.entries(aliases).forEach(([alias, field]) => {\n resolvers[alias] = resolvers[field];\n });\n }\n\n return resolvers;\n}\n\nfunction isReferenceField(ormField: Field): ormField is ManyToOneField | OneToOneField | PolymorphicField {\n return ormField.kind === \"m2o\" || ormField.kind === \"o2o\" || ormField.kind === \"poly\";\n}\n\nfunction isCollectionField(ormField: Field): ormField is OneToManyField | ManyToManyField {\n return ormField.kind === \"o2m\" || ormField.kind === \"m2m\";\n}\n\nfunction isPrimaryKeyField(ormField: Field): ormField is PrimaryKeyField {\n return ormField.kind === \"primaryKey\";\n}\n"],"mappings":"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"}
|
package/build/hint.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let graphql_type = require("graphql/type");
|
|
3
|
+
require("joist-core");
|
|
4
|
+
require("graphql/language");
|
|
5
|
+
//#region src/hint.ts
|
|
6
|
+
/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */
|
|
7
|
+
function convertInfoToLoadHint(meta, info) {
|
|
8
|
+
const objectType = convertToObjectType(info.returnType);
|
|
9
|
+
const { selectionSet, arguments: args } = info.fieldNodes[0];
|
|
10
|
+
const hasArgs = !!args && args.length > 0;
|
|
11
|
+
if (objectType && selectionSet && !hasArgs) {
|
|
12
|
+
const hint = selectionSetToObject(info, meta, objectType, selectionSet);
|
|
13
|
+
return Object.keys(hint).length === 0 ? void 0 : hint;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */
|
|
17
|
+
function selectionSetToObject(info, meta, gqlType, selectionSet) {
|
|
18
|
+
const result = {};
|
|
19
|
+
for (const selection of selectionSet.selections) if (selection.kind === "Field") {
|
|
20
|
+
if (selection.arguments && selection.arguments.length > 0) continue;
|
|
21
|
+
const fieldName = selection.name.value;
|
|
22
|
+
const field = gqlType.getFields()[fieldName];
|
|
23
|
+
if (field === void 0) continue;
|
|
24
|
+
const fieldType = convertToObjectType(field.type);
|
|
25
|
+
const ormField = meta.allFields[fieldName];
|
|
26
|
+
if (fieldType && selection.selectionSet && ormField && "otherMetadata" in ormField) result[fieldName] = selectionSetToObject(info, ormField.otherMetadata(), fieldType, selection.selectionSet);
|
|
27
|
+
} else if (selection.kind === "FragmentSpread") {
|
|
28
|
+
const fragmentName = selection.name.value;
|
|
29
|
+
const fragment = info.fragments[fragmentName];
|
|
30
|
+
const objectType = convertToObjectType(info.schema.getType(fragment.typeCondition.name.value));
|
|
31
|
+
if (objectType) deepMerge(result, selectionSetToObject(info, meta, objectType, fragment.selectionSet));
|
|
32
|
+
} else if (selection.kind === "InlineFragment" && selection.typeCondition) {
|
|
33
|
+
const objectType = convertToObjectType(info.schema.getType(selection.typeCondition.name.value));
|
|
34
|
+
if (objectType) deepMerge(result, selectionSetToObject(info, meta, objectType, selection.selectionSet));
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function convertToObjectType(type) {
|
|
39
|
+
if (type instanceof graphql_type.GraphQLNonNull || type instanceof graphql_type.GraphQLList) return convertToObjectType(type.ofType);
|
|
40
|
+
else if ((0, graphql_type.isObjectType)(type)) return type;
|
|
41
|
+
}
|
|
42
|
+
function deepMerge(a, b) {
|
|
43
|
+
for (const [key, value] of Object.entries(b)) deepMerge(a[key] ??= {}, value);
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
exports.convertInfoToLoadHint = convertInfoToLoadHint;
|
|
47
|
+
exports.convertToObjectType = convertToObjectType;
|
|
48
|
+
exports.selectionSetToObject = selectionSetToObject;
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=hint.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hint.cjs","names":["GraphQLNonNull","GraphQLList","isObjectType"],"sources":["../src/hint.ts"],"sourcesContent":["import { type SelectionSetNode } from \"graphql/language\";\nimport {\n GraphQLList,\n GraphQLNonNull,\n type GraphQLObjectType,\n type GraphQLOutputType,\n type GraphQLResolveInfo,\n isObjectType,\n} from \"graphql/type\";\nimport { type Entity, type EntityMetadata, type LoadHint } from \"joist-core\";\n\n/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */\nexport function convertInfoToLoadHint<T extends Entity>(\n meta: EntityMetadata,\n info: GraphQLResolveInfo,\n): LoadHint<T> | undefined {\n // The return type of the current field resolver is the root type, i.e.\n // Author.books fieldResolver ==> objectType = Book, or\n // query.authors fieldResolver ==> objectType = Author\n const objectType = convertToObjectType(info.returnType);\n const { selectionSet, arguments: args } = info.fieldNodes[0];\n const hasArgs = !!args && args.length > 0;\n if (objectType && selectionSet && !hasArgs) {\n const hint = selectionSetToObject(info, meta, objectType, selectionSet);\n // Don't return an empty hint\n return Object.keys(hint).length === 0 ? undefined : hint;\n }\n return undefined;\n}\n\n/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */\nexport function selectionSetToObject(\n info: GraphQLResolveInfo,\n meta: EntityMetadata,\n gqlType: GraphQLObjectType,\n selectionSet: SelectionSetNode,\n): Record<string, any> {\n const result: Record<string, any> = {};\n for (const selection of selectionSet.selections) {\n if (selection.kind === \"Field\") {\n // If there are arguments, defer to the field resolver to apply them.\n if (selection.arguments && selection.arguments.length > 0) continue;\n const fieldName = selection.name.value;\n const field = gqlType.getFields()[fieldName];\n // This might be __typename, which is a meta field\n if (field === undefined) continue;\n const fieldType = convertToObjectType(field.type);\n const ormField = meta.allFields[fieldName];\n if (fieldType && selection.selectionSet && ormField && \"otherMetadata\" in ormField) {\n result[fieldName] = selectionSetToObject(info, ormField.otherMetadata(), fieldType, selection.selectionSet);\n }\n } else if (selection.kind === \"FragmentSpread\") {\n const fragmentName = selection.name.value;\n const fragment = info.fragments[fragmentName]!;\n const type = info.schema.getType(fragment.typeCondition.name.value)!;\n const objectType = convertToObjectType(type as any);\n if (objectType) {\n const other = selectionSetToObject(info, meta, objectType, fragment.selectionSet);\n deepMerge(result, other);\n }\n } else if (selection.kind === \"InlineFragment\" && selection.typeCondition) {\n const type = info.schema.getType(selection.typeCondition.name.value)!;\n const objectType = convertToObjectType(type as any);\n if (objectType) {\n const other = selectionSetToObject(info, meta, objectType, selection.selectionSet);\n deepMerge(result, other);\n }\n }\n }\n return result;\n}\n\nexport function convertToObjectType(type: GraphQLOutputType): GraphQLObjectType | undefined {\n if (type instanceof GraphQLNonNull || type instanceof GraphQLList) {\n return convertToObjectType(type.ofType);\n } else if (isObjectType(type)) {\n return type;\n }\n return undefined;\n}\n\nfunction deepMerge<T extends object>(a: T, b: T): void {\n for (const [key, value] of Object.entries(b)) {\n deepMerge(((a as any)[key] ??= {}), value);\n }\n}\n"],"mappings":";;;;;;AAYA,SAAgB,sBACd,MACA,MACyB;CAIzB,MAAM,aAAa,oBAAoB,KAAK,UAAU;CACtD,MAAM,EAAE,cAAc,WAAW,SAAS,KAAK,WAAW;CAC1D,MAAM,UAAU,CAAC,CAAC,QAAQ,KAAK,SAAS;CACxC,IAAI,cAAc,gBAAgB,CAAC,SAAS;EAC1C,MAAM,OAAO,qBAAqB,MAAM,MAAM,YAAY,YAAY;EAEtE,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,IAAI,KAAA,IAAY;CACtD;AAEF;;AAGA,SAAgB,qBACd,MACA,MACA,SACA,cACqB;CACrB,MAAM,SAA8B,CAAC;CACrC,KAAK,MAAM,aAAa,aAAa,YACnC,IAAI,UAAU,SAAS,SAAS;EAE9B,IAAI,UAAU,aAAa,UAAU,UAAU,SAAS,GAAG;EAC3D,MAAM,YAAY,UAAU,KAAK;EACjC,MAAM,QAAQ,QAAQ,UAAU,CAAC,CAAC;EAElC,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,YAAY,oBAAoB,MAAM,IAAI;EAChD,MAAM,WAAW,KAAK,UAAU;EAChC,IAAI,aAAa,UAAU,gBAAgB,YAAY,mBAAmB,UACxE,OAAO,aAAa,qBAAqB,MAAM,SAAS,cAAc,GAAG,WAAW,UAAU,YAAY;CAE9G,OAAO,IAAI,UAAU,SAAS,kBAAkB;EAC9C,MAAM,eAAe,UAAU,KAAK;EACpC,MAAM,WAAW,KAAK,UAAU;EAEhC,MAAM,aAAa,oBADN,KAAK,OAAO,QAAQ,SAAS,cAAc,KAAK,KACnB,CAAQ;EAClD,IAAI,YAEF,UAAU,QADI,qBAAqB,MAAM,MAAM,YAAY,SAAS,YAC9C,CAAC;CAE3B,OAAO,IAAI,UAAU,SAAS,oBAAoB,UAAU,eAAe;EAEzE,MAAM,aAAa,oBADN,KAAK,OAAO,QAAQ,UAAU,cAAc,KAAK,KACpB,CAAQ;EAClD,IAAI,YAEF,UAAU,QADI,qBAAqB,MAAM,MAAM,YAAY,UAAU,YAC/C,CAAC;CAE3B;CAEF,OAAO;AACT;AAEA,SAAgB,oBAAoB,MAAwD;CAC1F,IAAI,gBAAgBA,aAAAA,kBAAkB,gBAAgBC,aAAAA,aACpD,OAAO,oBAAoB,KAAK,MAAM;MACjC,KAAA,GAAIC,aAAAA,aAAAA,CAAa,IAAI,GAC1B,OAAO;AAGX;AAEA,SAAS,UAA4B,GAAM,GAAY;CACrD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,CAAC,GACzC,UAAW,EAAW,SAAS,CAAC,GAAI,KAAK;AAE7C"}
|
package/build/hint.d.cts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GraphQLObjectType, GraphQLOutputType, GraphQLResolveInfo } from "graphql/type";
|
|
2
|
+
import { Entity, EntityMetadata, LoadHint } from "joist-core";
|
|
3
|
+
import { SelectionSetNode } from "graphql/language";
|
|
4
|
+
//#region src/hint.d.ts
|
|
5
|
+
/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */
|
|
6
|
+
declare function convertInfoToLoadHint<T extends Entity>(meta: EntityMetadata, info: GraphQLResolveInfo): LoadHint<T> | undefined;
|
|
7
|
+
/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */
|
|
8
|
+
declare function selectionSetToObject(info: GraphQLResolveInfo, meta: EntityMetadata, gqlType: GraphQLObjectType, selectionSet: SelectionSetNode): Record<string, any>;
|
|
9
|
+
declare function convertToObjectType(type: GraphQLOutputType): GraphQLObjectType | undefined;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { convertInfoToLoadHint, convertToObjectType, selectionSetToObject };
|
|
12
|
+
//# sourceMappingURL=hint.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hint.d.cts","names":[],"sources":["../src/hint.ts"],"mappings":";;;;;iBAYgB,sBAAsB,UAAU,QAC9C,MAAM,gBACN,MAAM,qBACL,SAAS;;iBAgBI,qBACd,MAAM,oBACN,MAAM,gBACN,SAAS,mBACT,cAAc,mBACb;iBAoCa,oBAAoB,MAAM,oBAAoB"}
|
package/build/hint.d.mts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GraphQLObjectType, GraphQLOutputType, GraphQLResolveInfo } from "graphql/type";
|
|
2
|
+
import { Entity, EntityMetadata, LoadHint } from "joist-core";
|
|
3
|
+
import { SelectionSetNode } from "graphql/language";
|
|
4
|
+
//#region src/hint.d.ts
|
|
5
|
+
/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */
|
|
6
|
+
declare function convertInfoToLoadHint<T extends Entity>(meta: EntityMetadata, info: GraphQLResolveInfo): LoadHint<T> | undefined;
|
|
7
|
+
/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */
|
|
8
|
+
declare function selectionSetToObject(info: GraphQLResolveInfo, meta: EntityMetadata, gqlType: GraphQLObjectType, selectionSet: SelectionSetNode): Record<string, any>;
|
|
9
|
+
declare function convertToObjectType(type: GraphQLOutputType): GraphQLObjectType | undefined;
|
|
10
|
+
//#endregion
|
|
11
|
+
export { convertInfoToLoadHint, convertToObjectType, selectionSetToObject };
|
|
12
|
+
//# sourceMappingURL=hint.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hint.d.mts","names":[],"sources":["../src/hint.ts"],"mappings":";;;;;iBAYgB,sBAAsB,UAAU,QAC9C,MAAM,gBACN,MAAM,qBACL,SAAS;;iBAgBI,qBACd,MAAM,oBACN,MAAM,gBACN,SAAS,mBACT,cAAc,mBACb;iBAoCa,oBAAoB,MAAM,oBAAoB"}
|
package/build/hint.js
CHANGED
|
@@ -1,76 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.convertToObjectType = convertToObjectType;
|
|
6
|
-
const type_1 = require("graphql/type");
|
|
1
|
+
import { GraphQLList, GraphQLNonNull, isObjectType } from "graphql/type";
|
|
2
|
+
import "joist-core";
|
|
3
|
+
import "graphql/language";
|
|
4
|
+
//#region src/hint.ts
|
|
7
5
|
/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */
|
|
8
6
|
function convertInfoToLoadHint(meta, info) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const hint = selectionSetToObject(info, meta, objectType, selectionSet);
|
|
17
|
-
// Don't return an empty hint
|
|
18
|
-
return Object.keys(hint).length === 0 ? undefined : hint;
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
7
|
+
const objectType = convertToObjectType(info.returnType);
|
|
8
|
+
const { selectionSet, arguments: args } = info.fieldNodes[0];
|
|
9
|
+
const hasArgs = !!args && args.length > 0;
|
|
10
|
+
if (objectType && selectionSet && !hasArgs) {
|
|
11
|
+
const hint = selectionSetToObject(info, meta, objectType, selectionSet);
|
|
12
|
+
return Object.keys(hint).length === 0 ? void 0 : hint;
|
|
13
|
+
}
|
|
21
14
|
}
|
|
22
15
|
/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */
|
|
23
16
|
function selectionSetToObject(info, meta, gqlType, selectionSet) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const fragment = info.fragments[fragmentName];
|
|
44
|
-
const type = info.schema.getType(fragment.typeCondition.name.value);
|
|
45
|
-
const objectType = convertToObjectType(type);
|
|
46
|
-
if (objectType) {
|
|
47
|
-
const other = selectionSetToObject(info, meta, objectType, fragment.selectionSet);
|
|
48
|
-
deepMerge(result, other);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
else if (selection.kind === "InlineFragment" && selection.typeCondition) {
|
|
52
|
-
const type = info.schema.getType(selection.typeCondition.name.value);
|
|
53
|
-
const objectType = convertToObjectType(type);
|
|
54
|
-
if (objectType) {
|
|
55
|
-
const other = selectionSetToObject(info, meta, objectType, selection.selectionSet);
|
|
56
|
-
deepMerge(result, other);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return result;
|
|
17
|
+
const result = {};
|
|
18
|
+
for (const selection of selectionSet.selections) if (selection.kind === "Field") {
|
|
19
|
+
if (selection.arguments && selection.arguments.length > 0) continue;
|
|
20
|
+
const fieldName = selection.name.value;
|
|
21
|
+
const field = gqlType.getFields()[fieldName];
|
|
22
|
+
if (field === void 0) continue;
|
|
23
|
+
const fieldType = convertToObjectType(field.type);
|
|
24
|
+
const ormField = meta.allFields[fieldName];
|
|
25
|
+
if (fieldType && selection.selectionSet && ormField && "otherMetadata" in ormField) result[fieldName] = selectionSetToObject(info, ormField.otherMetadata(), fieldType, selection.selectionSet);
|
|
26
|
+
} else if (selection.kind === "FragmentSpread") {
|
|
27
|
+
const fragmentName = selection.name.value;
|
|
28
|
+
const fragment = info.fragments[fragmentName];
|
|
29
|
+
const objectType = convertToObjectType(info.schema.getType(fragment.typeCondition.name.value));
|
|
30
|
+
if (objectType) deepMerge(result, selectionSetToObject(info, meta, objectType, fragment.selectionSet));
|
|
31
|
+
} else if (selection.kind === "InlineFragment" && selection.typeCondition) {
|
|
32
|
+
const objectType = convertToObjectType(info.schema.getType(selection.typeCondition.name.value));
|
|
33
|
+
if (objectType) deepMerge(result, selectionSetToObject(info, meta, objectType, selection.selectionSet));
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
61
36
|
}
|
|
62
37
|
function convertToObjectType(type) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
else if ((0, type_1.isObjectType)(type)) {
|
|
67
|
-
return type;
|
|
68
|
-
}
|
|
69
|
-
return undefined;
|
|
38
|
+
if (type instanceof GraphQLNonNull || type instanceof GraphQLList) return convertToObjectType(type.ofType);
|
|
39
|
+
else if (isObjectType(type)) return type;
|
|
70
40
|
}
|
|
71
41
|
function deepMerge(a, b) {
|
|
72
|
-
|
|
73
|
-
deepMerge((a[key] ??= {}), value);
|
|
74
|
-
}
|
|
42
|
+
for (const [key, value] of Object.entries(b)) deepMerge(a[key] ??= {}, value);
|
|
75
43
|
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { convertInfoToLoadHint, convertToObjectType, selectionSetToObject };
|
|
46
|
+
|
|
76
47
|
//# sourceMappingURL=hint.js.map
|
package/build/hint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hint.js","
|
|
1
|
+
{"version":3,"file":"hint.js","names":[],"sources":["../src/hint.ts"],"sourcesContent":["import { type SelectionSetNode } from \"graphql/language\";\nimport {\n GraphQLList,\n GraphQLNonNull,\n type GraphQLObjectType,\n type GraphQLOutputType,\n type GraphQLResolveInfo,\n isObjectType,\n} from \"graphql/type\";\nimport { type Entity, type EntityMetadata, type LoadHint } from \"joist-core\";\n\n/** Returns a load hint for the given `meta` entity at the `info` node.populate`. */\nexport function convertInfoToLoadHint<T extends Entity>(\n meta: EntityMetadata,\n info: GraphQLResolveInfo,\n): LoadHint<T> | undefined {\n // The return type of the current field resolver is the root type, i.e.\n // Author.books fieldResolver ==> objectType = Book, or\n // query.authors fieldResolver ==> objectType = Author\n const objectType = convertToObjectType(info.returnType);\n const { selectionSet, arguments: args } = info.fieldNodes[0];\n const hasArgs = !!args && args.length > 0;\n if (objectType && selectionSet && !hasArgs) {\n const hint = selectionSetToObject(info, meta, objectType, selectionSet);\n // Don't return an empty hint\n return Object.keys(hint).length === 0 ? undefined : hint;\n }\n return undefined;\n}\n\n/** Converts a GraphQL selection set into a hint for `EntityManager.populate`. */\nexport function selectionSetToObject(\n info: GraphQLResolveInfo,\n meta: EntityMetadata,\n gqlType: GraphQLObjectType,\n selectionSet: SelectionSetNode,\n): Record<string, any> {\n const result: Record<string, any> = {};\n for (const selection of selectionSet.selections) {\n if (selection.kind === \"Field\") {\n // If there are arguments, defer to the field resolver to apply them.\n if (selection.arguments && selection.arguments.length > 0) continue;\n const fieldName = selection.name.value;\n const field = gqlType.getFields()[fieldName];\n // This might be __typename, which is a meta field\n if (field === undefined) continue;\n const fieldType = convertToObjectType(field.type);\n const ormField = meta.allFields[fieldName];\n if (fieldType && selection.selectionSet && ormField && \"otherMetadata\" in ormField) {\n result[fieldName] = selectionSetToObject(info, ormField.otherMetadata(), fieldType, selection.selectionSet);\n }\n } else if (selection.kind === \"FragmentSpread\") {\n const fragmentName = selection.name.value;\n const fragment = info.fragments[fragmentName]!;\n const type = info.schema.getType(fragment.typeCondition.name.value)!;\n const objectType = convertToObjectType(type as any);\n if (objectType) {\n const other = selectionSetToObject(info, meta, objectType, fragment.selectionSet);\n deepMerge(result, other);\n }\n } else if (selection.kind === \"InlineFragment\" && selection.typeCondition) {\n const type = info.schema.getType(selection.typeCondition.name.value)!;\n const objectType = convertToObjectType(type as any);\n if (objectType) {\n const other = selectionSetToObject(info, meta, objectType, selection.selectionSet);\n deepMerge(result, other);\n }\n }\n }\n return result;\n}\n\nexport function convertToObjectType(type: GraphQLOutputType): GraphQLObjectType | undefined {\n if (type instanceof GraphQLNonNull || type instanceof GraphQLList) {\n return convertToObjectType(type.ofType);\n } else if (isObjectType(type)) {\n return type;\n }\n return undefined;\n}\n\nfunction deepMerge<T extends object>(a: T, b: T): void {\n for (const [key, value] of Object.entries(b)) {\n deepMerge(((a as any)[key] ??= {}), value);\n }\n}\n"],"mappings":";;;;;AAYA,SAAgB,sBACd,MACA,MACyB;CAIzB,MAAM,aAAa,oBAAoB,KAAK,UAAU;CACtD,MAAM,EAAE,cAAc,WAAW,SAAS,KAAK,WAAW;CAC1D,MAAM,UAAU,CAAC,CAAC,QAAQ,KAAK,SAAS;CACxC,IAAI,cAAc,gBAAgB,CAAC,SAAS;EAC1C,MAAM,OAAO,qBAAqB,MAAM,MAAM,YAAY,YAAY;EAEtE,OAAO,OAAO,KAAK,IAAI,CAAC,CAAC,WAAW,IAAI,KAAA,IAAY;CACtD;AAEF;;AAGA,SAAgB,qBACd,MACA,MACA,SACA,cACqB;CACrB,MAAM,SAA8B,CAAC;CACrC,KAAK,MAAM,aAAa,aAAa,YACnC,IAAI,UAAU,SAAS,SAAS;EAE9B,IAAI,UAAU,aAAa,UAAU,UAAU,SAAS,GAAG;EAC3D,MAAM,YAAY,UAAU,KAAK;EACjC,MAAM,QAAQ,QAAQ,UAAU,CAAC,CAAC;EAElC,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,YAAY,oBAAoB,MAAM,IAAI;EAChD,MAAM,WAAW,KAAK,UAAU;EAChC,IAAI,aAAa,UAAU,gBAAgB,YAAY,mBAAmB,UACxE,OAAO,aAAa,qBAAqB,MAAM,SAAS,cAAc,GAAG,WAAW,UAAU,YAAY;CAE9G,OAAO,IAAI,UAAU,SAAS,kBAAkB;EAC9C,MAAM,eAAe,UAAU,KAAK;EACpC,MAAM,WAAW,KAAK,UAAU;EAEhC,MAAM,aAAa,oBADN,KAAK,OAAO,QAAQ,SAAS,cAAc,KAAK,KACnB,CAAQ;EAClD,IAAI,YAEF,UAAU,QADI,qBAAqB,MAAM,MAAM,YAAY,SAAS,YAC9C,CAAC;CAE3B,OAAO,IAAI,UAAU,SAAS,oBAAoB,UAAU,eAAe;EAEzE,MAAM,aAAa,oBADN,KAAK,OAAO,QAAQ,UAAU,cAAc,KAAK,KACpB,CAAQ;EAClD,IAAI,YAEF,UAAU,QADI,qBAAqB,MAAM,MAAM,YAAY,UAAU,YAC/C,CAAC;CAE3B;CAEF,OAAO;AACT;AAEA,SAAgB,oBAAoB,MAAwD;CAC1F,IAAI,gBAAgB,kBAAkB,gBAAgB,aACpD,OAAO,oBAAoB,KAAK,MAAM;MACjC,IAAI,aAAa,IAAI,GAC1B,OAAO;AAGX;AAEA,SAAS,UAA4B,GAAM,GAAY;CACrD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,CAAC,GACzC,UAAW,EAAW,SAAS,CAAC,GAAI,KAAK;AAE7C"}
|
package/build/index.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_cursorPagination = require("./cursorPagination.cjs");
|
|
3
|
+
const require_hint = require("./hint.cjs");
|
|
4
|
+
const require_entityResolver = require("./entityResolver.cjs");
|
|
5
|
+
const require_limitPagination = require("./limitPagination.cjs");
|
|
6
|
+
const require_saveEntity = require("./saveEntity.cjs");
|
|
7
|
+
exports.CursorPageInfo = require_cursorPagination.CursorPageInfo;
|
|
8
|
+
exports.LimitPageInfo = require_limitPagination.LimitPageInfo;
|
|
9
|
+
exports.convertInfoToLoadHint = require_hint.convertInfoToLoadHint;
|
|
10
|
+
exports.entityResolver = require_entityResolver.entityResolver;
|
|
11
|
+
exports.paginateCursor = require_cursorPagination.paginateCursor;
|
|
12
|
+
exports.paginateLimit = require_limitPagination.paginateLimit;
|
|
13
|
+
exports.saveEntities = require_saveEntity.saveEntities;
|
|
14
|
+
exports.saveEntity = require_saveEntity.saveEntity;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CursorPageInfo, paginateCursor } from "./cursorPagination.cjs";
|
|
2
|
+
import { entityResolver } from "./entityResolver.cjs";
|
|
3
|
+
import { convertInfoToLoadHint } from "./hint.cjs";
|
|
4
|
+
import { LimitPageInfo, paginateLimit } from "./limitPagination.cjs";
|
|
5
|
+
import { saveEntities, saveEntity } from "./saveEntity.cjs";
|
|
6
|
+
export { CursorPageInfo, LimitPageInfo, convertInfoToLoadHint, entityResolver, paginateCursor, paginateLimit, saveEntities, saveEntity };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CursorPageInfo, paginateCursor } from "./cursorPagination.mjs";
|
|
2
|
+
import { entityResolver } from "./entityResolver.mjs";
|
|
3
|
+
import { convertInfoToLoadHint } from "./hint.mjs";
|
|
4
|
+
import { LimitPageInfo, paginateLimit } from "./limitPagination.mjs";
|
|
5
|
+
import { saveEntities, saveEntity } from "./saveEntity.mjs";
|
|
6
|
+
export { CursorPageInfo, LimitPageInfo, convertInfoToLoadHint, entityResolver, paginateCursor, paginateLimit, saveEntities, saveEntity };
|