-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
graphql: Added new package providing a graphql based backend
- Loading branch information
Showing
6 changed files
with
325 additions
and
0 deletions.
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 |
---|---|---|
|
@@ -3,3 +3,4 @@ dist | |
build | ||
lib | ||
**/lib | ||
yarn-error.log |
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,14 @@ | ||
const { NODE_ENV, BABEL_ENV } = process.env | ||
const cjs = NODE_ENV === 'test' || BABEL_ENV === 'commonjs' | ||
const loose = true | ||
|
||
module.exports = { | ||
presets: [['@babel/env', { loose, modules: false }]], | ||
plugins: [ | ||
['@babel/proposal-decorators', { legacy: true }], | ||
['@babel/proposal-object-rest-spread', { loose }], | ||
'@babel/transform-react-jsx', | ||
cjs && ['@babel/transform-modules-commonjs', { loose }], | ||
['@babel/transform-runtime', { useESModules: !cjs }], | ||
].filter(Boolean), | ||
} |
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,8 @@ | ||
{ | ||
"extends": "airbnb", | ||
"rules": { | ||
"react/jsx-props-no-spreading": "off", | ||
"import/prefer-default-export": "off", | ||
"react/prop-types": "off", | ||
}, | ||
} |
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,96 @@ | ||
{ | ||
"name": "@pihanga/graphql", | ||
"version": "0.1.0", | ||
"description": "Implemnts a graphql based backend for local state management", | ||
"homepage": "https://github.com/n1analytics/pihanga#readme", | ||
"main": "lib/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/n1analytics/pihanga.git" | ||
}, | ||
"bugs": "https://github.com/n1analytics/pihanga/issues", | ||
"keywords": [ | ||
"graphql", | ||
"framework" | ||
], | ||
"contributors": [ | ||
"Max Ott <[email protected]> (http://linkedin.com/in/max-ott)", | ||
"Pihanga Team" | ||
], | ||
"license": "MIT", | ||
"unpkg": "dist/pihanga-graphql.min.js", | ||
"module": "lib/index.js", | ||
"files": [ | ||
"dist", | ||
"lib", | ||
"src" | ||
], | ||
"dependencies": { | ||
"apollo-cache-inmemory": "^1.6.0", | ||
"apollo-client": "^2.6.0", | ||
"apollo-link": "^1.2.0", | ||
"apollo-link-error": "^1.1.0", | ||
"apollo-link-http": "^1.5.0", | ||
"graphql": "^14.5.0", | ||
"graphql-tag": "^2.10.0" | ||
}, | ||
"peerDependencies": { | ||
"@pihanga/core": "^0.3.0" | ||
}, | ||
"devDependencies": { | ||
"@pihanga/core": "^0.3.0", | ||
"@babel/cli": "^7.5.0", | ||
"@babel/core": "^7.5.0", | ||
"@babel/plugin-proposal-decorators": "^7.4.0", | ||
"@babel/plugin-proposal-object-rest-spread": "^7.5.0", | ||
"@babel/plugin-transform-react-display-name": "^7.2.0", | ||
"@babel/plugin-transform-react-jsx": "^7.3.0", | ||
"@babel/plugin-transform-runtime": "^7.5.0", | ||
"@babel/preset-env": "^7.5.0", | ||
"babel-core": "^6.23.0", | ||
"babel-eslint": "^10.0.2", | ||
"babel-jest": "^24.9.0", | ||
"codecov": "^3.5.0", | ||
"cross-env": "^5.2.0", | ||
"cross-spawn": "^6.0.5", | ||
"es3ify": "^0.2.0", | ||
"eslint": "^6.1.0", | ||
"eslint-config-airbnb": "^18.0.1", | ||
"eslint-plugin-import": "^2.18.0", | ||
"eslint-plugin-jsx-a11y": "^6.2.0", | ||
"eslint-plugin-react": "^7.14.0", | ||
"eslint-plugin-react-hooks": "^1.7.0", | ||
"glob": "^7.1.4", | ||
"jest": "^24.9.0", | ||
"jest-dom": "^3.5.0", | ||
"npm-run": "^5.0.1", | ||
"prettier": "^1.18.2", | ||
"rimraf": "^2.7.1", | ||
"rollup": "^1.19.4", | ||
"rollup-plugin-babel": "^4.3.3", | ||
"rollup-plugin-commonjs": "^9.3.4", | ||
"rollup-plugin-node-resolve": "^4.2.4", | ||
"rollup-plugin-replace": "^2.2.0", | ||
"rollup-plugin-terser": "^4.0.4", | ||
"semver": "^5.7.1" | ||
}, | ||
"scripts": { | ||
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib && touch lib/DO_NOT_EDIT", | ||
"build:es": "babel src --out-dir dist/es", | ||
"build:umd": "cross-env NODE_ENV=development rollup -c -o dist/pihanga-core.js", | ||
"build:umd:min": "cross-env NODE_ENV=production rollup -c -o dist/pihanga-core.min.js", | ||
"xxx-build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", | ||
"build": "npm run build:commonjs && npm run build:es", | ||
"clean": "rimraf lib dist coverage", | ||
"format": "prettier --write \"{src,test}/**/*.{js,ts}\" index.d.ts \"docs/**/*.md\"", | ||
"lint": "eslint src test/utils test/components", | ||
"prepare": "npm run clean && npm run build", | ||
"pretest": "npm run lint", | ||
"test": "node ./test/run-tests.js", | ||
"coverage": "codecov", | ||
"publish": "npm publish --tag latest --access=public", | ||
"x-prepublishOnly": "npm run build", | ||
"x-prepublish": "yarn run lint && yarn run test && yarn run build" | ||
}, | ||
"gitHead": "aa43c27ff6344d6ead75a83e1d23ff69a7f4feb4" | ||
} |
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,61 @@ | ||
import nodeResolve from 'rollup-plugin-node-resolve' | ||
import babel from 'rollup-plugin-babel' | ||
import replace from 'rollup-plugin-replace' | ||
import commonjs from 'rollup-plugin-commonjs' | ||
import { terser } from 'rollup-plugin-terser' | ||
import pkg from './package.json' | ||
|
||
const env = process.env.NODE_ENV | ||
|
||
const config = { | ||
input: 'src/index.js', | ||
external: Object.keys(pkg.peerDependencies || {}), | ||
output: { | ||
format: 'umd', | ||
name: 'ReactRedux', | ||
globals: { | ||
react: 'React', | ||
redux: 'Redux' | ||
} | ||
}, | ||
plugins: [ | ||
nodeResolve({ | ||
mainFields: ['module', 'main'], | ||
//jsnext: true, | ||
extensions: ['.js', '.jsx', '.json'] | ||
}), | ||
babel({ | ||
exclude: '**/node_modules/**', | ||
runtimeHelpers: true | ||
}), | ||
replace({ | ||
'process.env.NODE_ENV': JSON.stringify(env) | ||
}), | ||
commonjs({ | ||
namedExports: { | ||
'node_modules/react-is/index.js': [ | ||
'isValidElementType', | ||
'isContextConsumer' | ||
], | ||
'node_modules/@pihanga/core/lib/index.js': [ | ||
'dispatch' | ||
] | ||
} | ||
}) | ||
] | ||
} | ||
|
||
if (env === 'production') { | ||
config.plugins.push( | ||
terser({ | ||
compress: { | ||
pure_getters: true, | ||
unsafe: true, | ||
unsafe_comps: true, | ||
warnings: false | ||
} | ||
}) | ||
) | ||
} | ||
|
||
export default config |
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,145 @@ | ||
import { ApolloClient } from 'apollo-client'; | ||
import { InMemoryCache } from 'apollo-cache-inmemory'; | ||
import { HttpLink } from 'apollo-link-http'; | ||
import { onError } from 'apollo-link-error'; | ||
import { ApolloLink } from 'apollo-link'; | ||
import { registerActions, dispatch, dispatchFromReducer } from '@pihanga/core'; | ||
import gql from 'graphql-tag'; | ||
import { visit } from 'graphql'; | ||
|
||
|
||
const Domain = 'GRAPHQL'; | ||
export const ACTION_TYPES = registerActions(Domain, | ||
['QUERY_SUBMITTED', 'QUERY_RESULT', 'QUERY_ERROR', 'QL_ERROR', 'NETWORK_ERROR', 'NOT_INITIALISED']); | ||
|
||
let client; | ||
let registerReducer; | ||
|
||
/** | ||
* Standard pihanga init function to initialize an Apollo client. | ||
* | ||
* Expects all relevant configuration options to be found in | ||
* `register.environment.GRAPHQL_URI` (needs most likely more). | ||
* | ||
* @param {*} register | ||
*/ | ||
export function init(register) { | ||
const uri = register.environment.GRAPHQL_URI || '/graphql'; | ||
client = createClient(uri); | ||
registerReducer = register.reducer; | ||
} | ||
|
||
/** | ||
* Register a GraphQL query and all related processing steps. | ||
* | ||
* The argument to this function is a map with the following key/value pairs. | ||
* | ||
* * query: The GraphQL query to be issued | ||
* * trigger: The Redux action type to potentially trigger this query | ||
* * request: A function expected to return a map of the variable assignmets for this query. | ||
* If undefined is returned, no query is issued. The function is called with paramters: | ||
* triggering action, current redux state, and a map describing the declared variables | ||
* and their respective types. | ||
* * reply: A function expected to return a possibly updated redux state in respond to a | ||
* successful query result. The function is called witht paramters: the current redux state | ||
* and the 'data' element of the returned query. | ||
* * error: An optional function expected to return a possibly updated redux state in respond to a | ||
* failed query. The function is called witht paramters: the current redux state | ||
* and the error condition. | ||
* | ||
* | ||
* @param {*} opts | ||
*/ | ||
export function registerQuery({query, trigger, request, reply, error}) { | ||
const {name, variables, doc} = parseQuery(query); | ||
if (!trigger) { | ||
throw Error('Missing "trigger"'); | ||
} | ||
if (!request) { | ||
throw Error('Missing "request"'); | ||
} | ||
if (!reply) { | ||
throw Error('Missing "reply"'); | ||
} | ||
|
||
const submitType = `${ACTION_TYPES.QUERY_SUBMITTED}:${name}`; | ||
const resultType = `${ACTION_TYPES.QUERY_RESULT}:${name}`; | ||
const errorType = `${ACTION_TYPES.QUERY_ERROR}:${name}`; | ||
|
||
registerReducer(trigger, (state, action) => { | ||
const vars = request(action, state, variables); | ||
if (vars) { | ||
runQuery(name, doc, vars, resultType, errorType); | ||
dispatchFromReducer({type: submitType, queryID: name, vars}); | ||
} | ||
return state; | ||
}); | ||
|
||
registerReducer(resultType, (state, action) => { | ||
return reply(state, action.data); | ||
}); | ||
|
||
if (error) { | ||
registerReducer(errorType, (state, action) => { | ||
return reply(state, error); | ||
}); | ||
} | ||
} | ||
|
||
function parseQuery(query) { | ||
const doc = gql(query); | ||
let name = null; | ||
const variables = {}; | ||
const visitor = { | ||
enter: { | ||
OperationDefinition: (node) => { | ||
name = node.name.value; | ||
return undefined; | ||
}, | ||
VariableDefinition: (node) => { | ||
const type = node.type.name.value; | ||
const name = node.variable.name.value; | ||
const defValue = node.defaultValue ? node.defaultValue.value : null; | ||
variables[name] = {name, type, defValue}; | ||
return undefined; | ||
}, | ||
} | ||
}; | ||
visit(doc, visitor); | ||
return {name, variables, doc, query}; | ||
} | ||
|
||
function runQuery(queryID, query, variables, resultType, errorType) { | ||
if (client === null) { | ||
dispatch({ type: ACTION_TYPES.NOT_INITIALISED, queryID }); | ||
} | ||
client.query({query, variables}) | ||
.then(data => { | ||
dispatch({ type: resultType, queryID, data: data.data }); | ||
}) | ||
.catch(error => { | ||
dispatch({ type: errorType, queryID, error }); | ||
}); | ||
} | ||
|
||
function createClient(uri) { | ||
return new ApolloClient({ | ||
link: ApolloLink.from([ | ||
onError(({ graphQLErrors, networkError }) => { | ||
if (graphQLErrors) { | ||
graphQLErrors.forEach(({ message, locations, path }) => { | ||
dispatch({ type: ACTION_TYPES.QL_ERROR, message, locations, path }); | ||
}); | ||
} | ||
if (networkError) { | ||
dispatch({ type: ACTION_TYPES.NETWORK_ERROR, networkError }); | ||
} | ||
}), | ||
new HttpLink({ | ||
uri, | ||
// credentials: 'same-origin' | ||
}) | ||
]), | ||
cache: new InMemoryCache() | ||
}); | ||
} |