@haathie/postgraphile-replace-types 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare const ReplaceTypesPlugin: GraphileConfig.Plugin;
package/lib/index.js ADDED
@@ -0,0 +1,98 @@
1
+ function wrapOutputType(originalType, replacementType, { graphql: { GraphQLList, GraphQLNonNull } }) {
2
+ let result = replacementType;
3
+ const wrappers = [];
4
+ let current = originalType;
5
+ while (current instanceof GraphQLNonNull || current instanceof GraphQLList) {
6
+ wrappers.unshift(current.constructor);
7
+ current = current.ofType;
8
+ }
9
+ for (const Wrapper of wrappers) {
10
+ result = new Wrapper(result);
11
+ }
12
+ return result;
13
+ }
14
+ function wrapInputType(originalType, replacementType, { graphql: { GraphQLList, GraphQLNonNull } }) {
15
+ let result = replacementType;
16
+ const wrappers = [];
17
+ let current = originalType;
18
+ while (current instanceof GraphQLNonNull || current instanceof GraphQLList) {
19
+ wrappers.unshift(current.constructor);
20
+ current = current.ofType;
21
+ }
22
+ for (const Wrapper of wrappers) {
23
+ result = new Wrapper(result);
24
+ }
25
+ return result;
26
+ }
27
+ function getAttributeFromScope(pgCodec, fieldName, inflection) {
28
+ if (!pgCodec.attributes) {
29
+ return undefined;
30
+ }
31
+ if (pgCodec.attributes[fieldName]) {
32
+ return pgCodec.attributes[fieldName];
33
+ }
34
+ for (const [attrName, attr] of Object.entries(pgCodec.attributes)) {
35
+ const graphqlName = inflection.attribute({ attributeName: attrName, codec: pgCodec });
36
+ if (graphqlName === fieldName) {
37
+ return attr;
38
+ }
39
+ }
40
+ return undefined;
41
+ }
42
+ export const ReplaceTypesPlugin = {
43
+ name: 'ReplaceTypesPlugin',
44
+ version: '0.1.0',
45
+ schema: {
46
+ hooks: {
47
+ 'GraphQLObjectType_fields_field': (field, build, ctx) => {
48
+ const { scope: { pgFieldAttribute, pgCodec, fieldName } } = ctx;
49
+ if (!pgFieldAttribute || !pgCodec || !fieldName) {
50
+ return field;
51
+ }
52
+ const attr = getAttributeFromScope(pgCodec, fieldName, build.inflection);
53
+ if (!attr) {
54
+ return field;
55
+ }
56
+ const replaceType = attr.extensions?.tags?.replaceType;
57
+ if (!replaceType) {
58
+ return field;
59
+ }
60
+ const replacementType = build.getTypeByName(replaceType);
61
+ if (!replacementType) {
62
+ console.warn(`[ReplaceTypesPlugin] Type '${replaceType}' not found. `
63
+ + `Cannot replace field '${fieldName}'.`);
64
+ return field;
65
+ }
66
+ return {
67
+ ...field,
68
+ type: wrapOutputType(field.type, replacementType, build),
69
+ };
70
+ },
71
+ 'GraphQLInputObjectType_fields_field': (field, build, ctx) => {
72
+ const { scope: { pgCodec, fieldName } } = ctx;
73
+ if (!pgCodec || !fieldName) {
74
+ return field;
75
+ }
76
+ const attr = getAttributeFromScope(pgCodec, fieldName, build.inflection);
77
+ if (!attr) {
78
+ return field;
79
+ }
80
+ const replaceType = attr.extensions?.tags?.replaceType;
81
+ if (typeof replaceType !== 'string') {
82
+ return field;
83
+ }
84
+ const replacementType = build.getTypeByName(replaceType + 'Input')
85
+ || build.getTypeByName(replaceType);
86
+ if (!replacementType) {
87
+ console.warn(`[ReplaceTypesPlugin] Type '${replaceType}Input' (or '${replaceType}') not found. `
88
+ + `Cannot replace input field '${fieldName}'.`);
89
+ return field;
90
+ }
91
+ return {
92
+ ...field,
93
+ type: wrapInputType(field.type, replacementType, build),
94
+ };
95
+ },
96
+ },
97
+ },
98
+ };
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@haathie/postgraphile-replace-types",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "files": ["lib"],
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/haathie/graphile-tools.git"
14
+ },
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json"
17
+ },
18
+ "dependencies": {
19
+ "@haathie/postgraphile-common-utils": "^0.1.2"
20
+ },
21
+ "peerDependencies": {
22
+ "postgraphile": "*"
23
+ }
24
+ }
package/readme.md ADDED
@@ -0,0 +1,49 @@
1
+ # Replace Types
2
+
3
+ This plugin allows you to replace fields in the GraphQL schema with custom types.
4
+ This is useful for cases where you want to change the behavior of a field without changing the underlying database schema.
5
+
6
+ ## Usage
7
+
8
+ To use this plugin, you need to install it and then add it to your PostGraphile configuration.
9
+
10
+ ```
11
+ npm i @haathie/postgraphile-replace-types
12
+ ```
13
+
14
+ Add to your preset's plugins:
15
+ ```ts
16
+ import { ReplaceTypesPlugin } from '@haathie/postgraphile-replace-types';
17
+ const preset = {
18
+ ...otherStuff,
19
+ plugins: [
20
+ ...otherPlugins,
21
+ extendSchema(() => {
22
+ return {
23
+ typeDefs: `
24
+ enum NewTypeName {
25
+ VALUE1
26
+ }
27
+ `,
28
+ enums: {
29
+ NewTypeName: {
30
+ values: {
31
+ VALUE1: 'VALUE1',
32
+ }
33
+ },
34
+ }
35
+ }
36
+ })
37
+ ReplaceTypesPlugin,
38
+ ],
39
+ }
40
+ ```
41
+
42
+ ## Replacing a Field
43
+
44
+ Add a smart comment tag to the column in the database:
45
+ ```sql
46
+ COMMENT ON COLUMN table_name.field_name IS '@replaceType NewTypeName';
47
+ ```
48
+
49
+ For input types, it will first try `NewTypeNameInput`, then fall back to `NewTypeName`.