Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
3,538 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
module.exports = { | ||
parserOptions: { | ||
sourceType: "module", | ||
}, | ||
extends: ["eslint:recommended", "prettier"], | ||
plugins: ["prettier"], | ||
env: { | ||
node: true, | ||
es6: true, | ||
}, | ||
rules: { | ||
"prettier/prettier": [ | ||
"error", | ||
{ | ||
trailingComma: "es5", | ||
}, | ||
], | ||
"comma-dangle": [ | ||
2, | ||
{ | ||
arrays: "always-multiline", | ||
objects: "always-multiline", | ||
imports: "always-multiline", | ||
exports: "always-multiline", | ||
functions: "never", | ||
}, | ||
], | ||
"no-confusing-arrow": 0, | ||
"no-else-return": 0, | ||
"no-underscore-dangle": 0, | ||
"no-unused-vars": [ | ||
2, | ||
{ | ||
argsIgnorePattern: "^_", | ||
}, | ||
], | ||
"no-restricted-syntax": 0, | ||
"no-await-in-loop": 0, | ||
camelcase: 0, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* text=auto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,76 @@ | ||
[![Package on npm](https://img.shields.io/npm/v/postgraphile-plugin-derived-field.svg)](https://www.npmjs.com/package/postgraphile-plugin-derived-field) | ||
|
||
# postgraphile-plugin-derived-field | ||
Add derived fields in PostGraphile | ||
This plugin adds derived fields in PostGraphile v4. | ||
|
||
> **Note:** This plugin targets the beta release of PostGraphile v4. | ||
## Getting Started | ||
|
||
``` js | ||
const express = require("express"); | ||
const { postgraphile } = require("postgraphile"); | ||
const PostGraphileDerivedFieldPlugin = require("postgraphile-plugin-derived-field"); | ||
|
||
const app = express(); | ||
|
||
const AWS = require("aws-sdk"); | ||
const s3 = new AWS.S3(); | ||
const bucket = "postgraphile-plugin-test"; | ||
|
||
app.use( | ||
postgraphile(pgConfig, schema, { | ||
graphiql: true, | ||
appendPlugins: [PostGraphileDerivedFieldPlugin], | ||
graphileBuildOptions: { | ||
derivedFieldDefinitions: [ | ||
{ | ||
identifiers: ["my_schema.my_table.my_column"], | ||
inflect: (fieldName) => `${fieldName}Derived`, | ||
resolve: (val) => `Value derived from ${val}` | ||
} | ||
] | ||
} | ||
}) | ||
); | ||
|
||
app.listen(5000); | ||
``` | ||
|
||
## Examples | ||
|
||
<details> | ||
|
||
<summary>Generate pre-signed URLs for client-side S3 GET requests</summary> | ||
|
||
``` js | ||
const express = require("express"); | ||
const { postgraphile } = require("postgraphile"); | ||
const PostGraphileDerivedFieldPlugin = require("postgraphile-plugin-derived-field"); | ||
|
||
const AWS = require("aws-sdk"); | ||
const s3 = new AWS.S3(); | ||
const bucket = "postgraphile-plugin-test"; | ||
|
||
const app = express(); | ||
|
||
app.use( | ||
postgraphile(pgConfig, schema, { | ||
graphiql: true, | ||
appendPlugins: [PostGraphileDerivedFieldPlugin], | ||
graphileBuildOptions: { | ||
derivedFieldDefinitions: [ | ||
{ | ||
identifiers: ["my_schema.my_table.my_column"], | ||
inflect: (fieldName) => `${fieldName}Url`, | ||
resolve: (val) => s3.getSignedUrl('getObject', {Bucket: bucket, Key: val, Expires: 900}) | ||
} | ||
] | ||
} | ||
}) | ||
); | ||
|
||
app.listen(5000); | ||
``` | ||
|
||
</details> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module.exports = function PostGraphileDerivedFieldPlugin(builder, options) { | ||
require("./src/DerivedFieldPlugin.js")(builder, options); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
{ | ||
"name": "postgraphile-plugin-derived-field", | ||
"version": "1.0.0-alpha.0", | ||
"description": "Add derived fields in PostGraphile", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "scripts/test" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/mattbretl/postgraphile-plugin-derived-field.git" | ||
}, | ||
"author": "Matt Bretl", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/mattbretl/postgraphile-plugin-derived-field/issues" | ||
}, | ||
"dependencies": {}, | ||
"peerDependencies": { | ||
"postgraphile": "^4.0.0-beta.0" | ||
}, | ||
"devDependencies": { | ||
"eslint": "^4.0.0", | ||
"eslint-config-prettier": "2.3.0", | ||
"eslint-plugin-jest": "^20.0.3", | ||
"eslint-plugin-prettier": "^2.1.2", | ||
"graphql": "^0.10.5", | ||
"jest": "^20.0.4", | ||
"pg": ">=6.1.0 <8", | ||
"postgraphile-core": "^4.0.0-beta.0", | ||
"prettier": "^1.4.4" | ||
}, | ||
"jest": { | ||
"testRegex": "__tests__/.*\\.test\\.js$" | ||
}, | ||
"files": [ | ||
"src" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
function DerivedFieldPlugin( | ||
builder, | ||
{ pgInflection: inflection, derivedFieldDefinitions } | ||
) { | ||
builder.hook("GraphQLObjectType:fields", (fields, build, context) => { | ||
const { | ||
extend, | ||
pgIntrospectionResultsByKind: introspectionResultsByKind, | ||
graphql: { GraphQLString }, | ||
pgColumnFilter, | ||
fieldDataGeneratorsByFieldNameByType, | ||
} = build; | ||
const { | ||
scope: { pgIntrospection: table, isPgRowType }, | ||
fieldWithHooks, | ||
Self, | ||
} = context; | ||
|
||
if ( | ||
!isPgRowType || | ||
!table || | ||
table.kind !== "class" || | ||
derivedFieldDefinitions == null | ||
) { | ||
return fields; | ||
} | ||
|
||
const tableType = introspectionResultsByKind.type.filter( | ||
type => | ||
type.type === "c" && | ||
type.namespaceId === table.namespaceId && | ||
type.classId === table.id | ||
)[0]; | ||
if (!tableType) { | ||
throw new Error("Could not determine the type for this table"); | ||
} | ||
|
||
const derivedFields = introspectionResultsByKind.attribute | ||
.filter(attr => attr.classId === table.id) | ||
.filter(attr => pgColumnFilter(attr, build, context)) | ||
.reduce((memo, attr) => { | ||
for (let def of derivedFieldDefinitions) { | ||
if ( | ||
def.identifiers.includes( | ||
`${table.namespaceName}.${table.name}.${attr.name}` | ||
) | ||
) { | ||
const fieldName = inflection.column( | ||
attr.name, | ||
table.name, | ||
table.namespaceName | ||
); | ||
const derivedFieldName = def.inflect(fieldName); | ||
if (memo[derivedFieldName]) { | ||
throw new Error( | ||
`Derived field '${derivedFieldName}' conflicts with existing GraphQL field` | ||
); | ||
} | ||
const field = fields[fieldName]; | ||
const { resolve: oldResolve } = field; | ||
memo[derivedFieldName] = fieldWithHooks( | ||
derivedFieldName, | ||
({ addDataGenerator }) => { | ||
const generatorsByField = fieldDataGeneratorsByFieldNameByType.get( | ||
Self | ||
); | ||
generatorsByField[fieldName].forEach(g => { | ||
addDataGenerator(g); | ||
}); | ||
return { | ||
type: def.returnType || GraphQLString, | ||
resolve: (...resolveParams) => { | ||
const val = oldResolve(...resolveParams); | ||
return def.resolve(val); | ||
}, | ||
}; | ||
}, | ||
{ pgFieldIntrospection: attr } | ||
); | ||
} | ||
} | ||
return memo; | ||
}, {}); | ||
|
||
return extend( | ||
fields, | ||
derivedFields, | ||
`Adding derived field to '${Self.name}'` | ||
); | ||
}); | ||
} | ||
|
||
module.exports = DerivedFieldPlugin; |
Oops, something went wrong.