Skip to content
This repository was archived by the owner on Dec 26, 2023. It is now read-only.

Commit 9603f4f

Browse files
committed
Initial commit
0 parents  commit 9603f4f

18 files changed

+2215
-0
lines changed

.babelrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"presets": [
3+
["env", {
4+
"loose": true
5+
}],
6+
"stage-3"
7+
],
8+
"plugins": ["add-module-exports"]
9+
}

.editorconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
12+
[*.md]
13+
trim_trailing_whitespace = false

.gitignore

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
.idea
2+
lib
3+
4+
# Created by https://www.gitignore.io/api/node,linux,macos
5+
6+
### Linux ###
7+
*~
8+
9+
# temporary files which can be created if a process still has a handle open of a deleted file
10+
.fuse_hidden*
11+
12+
# KDE directory preferences
13+
.directory
14+
15+
# Linux trash folder which might appear on any partition or disk
16+
.Trash-*
17+
18+
# .nfs files are created when an open file is removed but is still being accessed
19+
.nfs*
20+
21+
### macOS ###
22+
*.DS_Store
23+
.AppleDouble
24+
.LSOverride
25+
26+
# Icon must end with two \r
27+
Icon
28+
29+
# Thumbnails
30+
._*
31+
32+
# Files that might appear in the root of a volume
33+
.DocumentRevisions-V100
34+
.fseventsd
35+
.Spotlight-V100
36+
.TemporaryItems
37+
.Trashes
38+
.VolumeIcon.icns
39+
.com.apple.timemachine.donotpresent
40+
41+
# Directories potentially created on remote AFP share
42+
.AppleDB
43+
.AppleDesktop
44+
Network Trash Folder
45+
Temporary Items
46+
.apdisk
47+
48+
### Node ###
49+
# Logs
50+
logs
51+
*.log
52+
npm-debug.log*
53+
yarn-debug.log*
54+
yarn-error.log*
55+
56+
# Runtime data
57+
pids
58+
*.pid
59+
*.seed
60+
*.pid.lock
61+
62+
# Directory for instrumented libs generated by jscoverage/JSCover
63+
lib-cov
64+
65+
# Coverage directory used by tools like istanbul
66+
coverage
67+
68+
# nyc test coverage
69+
.nyc_output
70+
71+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
72+
.grunt
73+
74+
# Bower dependency directory (https://bower.io/)
75+
bower_components
76+
77+
# node-waf configuration
78+
.lock-wscript
79+
80+
# Compiled binary addons (http://nodejs.org/api/addons.html)
81+
build/Release
82+
83+
# Dependency directories
84+
node_modules/
85+
jspm_packages/
86+
87+
# Typescript v1 declaration files
88+
typings/
89+
90+
# Optional npm cache directory
91+
.npm
92+
93+
# Optional eslint cache
94+
.eslintcache
95+
96+
# Optional REPL history
97+
.node_repl_history
98+
99+
# Output of 'npm pack'
100+
*.tgz
101+
102+
# Yarn Integrity file
103+
.yarn-integrity
104+
105+
# dotenv environment variables file
106+
.env
107+
108+
109+
110+
# End of https://www.gitignore.io/api/node,linux,macos

package.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "parse-server-graphql",
3+
"version": "0.0.0",
4+
"main": "index.js",
5+
"author": "stephentuso",
6+
"license": "MIT",
7+
"scripts": {
8+
"build": "babel src -d lib"
9+
},
10+
"dependencies": {
11+
"axios": "^0.18.0",
12+
"express-graphql": "^0.6.12",
13+
"graphql": "^0.13.1",
14+
"graphql-list-fields": "^2.0.1",
15+
"graphql-type-json": "^0.2.0",
16+
"lodash": "^4.17.5",
17+
"parse": "^1.11.0"
18+
},
19+
"devDependencies": {
20+
"babel-cli": "^6.26.0",
21+
"babel-plugin-add-module-exports": "^0.2.1",
22+
"babel-preset-env": "^1.6.1",
23+
"babel-preset-stage-3": "^6.24.1"
24+
}
25+
}

src/baseMapping.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { mapValues, constant } from 'lodash/fp';
2+
import File from './types/File';
3+
import Date from './types/Date';
4+
import ACL from './types/ACL';
5+
import {
6+
GraphQLString,
7+
GraphQLBoolean,
8+
GraphQLFloat,
9+
} from 'graphql';
10+
11+
export default mapValues(constant, {
12+
File,
13+
Date,
14+
ACL,
15+
String: GraphQLString,
16+
Boolean: GraphQLBoolean,
17+
Number: GraphQLFloat,
18+
});

src/fetchParseSchema.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import axios from 'axios';
2+
import { get } from 'lodash';
3+
4+
export default async function fetchParseSchema({ serverUrl, appId, masterKey }) {
5+
const response = await axios({
6+
method: 'get',
7+
url: `${serverUrl}/schemas`,
8+
headers: {
9+
'X-Parse-Application-Id': appId,
10+
'X-Parse-Master-Key': masterKey,
11+
},
12+
});
13+
14+
if (response.status !== 200) {
15+
throw new Error('Error retrieving Parse schema');
16+
}
17+
18+
if (!get(response, 'data.results') || !response.data.results.length) {
19+
throw new Error('No Parse classes found');
20+
}
21+
22+
return response.data.results;
23+
}

src/generateSchema.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { mapValues } from 'lodash';
2+
import { GraphQLSchema, GraphQLObjectType } from 'graphql';
3+
import typeForClass from './typeForClass';
4+
import dependencyHelper from './utils/dependencyHelper';
5+
import baseMapping from './baseMapping';
6+
import queryForType from './queryForType'
7+
8+
export default function generateSchema(parseSchema) {
9+
const types = dependencyHelper(
10+
baseMapping,
11+
mapValues(parseSchema, typeForClass),
12+
);
13+
14+
const queryFields = parseSchema.reduce((acc, { className }) => ({
15+
...acc,
16+
[className]: queryForType(types[className]),
17+
}), {});
18+
19+
const query = new GraphQLObjectType({
20+
name: 'Query',
21+
fields: queryFields,
22+
});
23+
24+
return new GraphQLSchema({ query });
25+
}

src/index.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import graphqlHTTP from 'express-graphql';
2+
import generateSchema from './generateSchema';
3+
import fetchParseSchema from './fetchParseSchema';
4+
5+
const getSchema = (() => {
6+
let schema;
7+
return async (options, alwaysRecreate) => {
8+
if (!schema || alwaysRecreate) {
9+
schema = generateSchema(await fetchParseSchema(options));
10+
}
11+
return schema;
12+
}
13+
});
14+
15+
export default function parseGraphQL(options) {
16+
return graphqlHTTP(async () => ({
17+
schema: await getSchema(options, options.dynamicSchema),
18+
graphiql: true,
19+
}));
20+
};

src/mapType.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function mapType({ type, ...params }, mapping) {
2+
return mapping[type](params);
3+
}

src/queryForType.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { GraphQLList } from 'graphql';
2+
import JSON from 'graphql-type-json';
3+
import getFieldNames from 'graphql-list-fields';
4+
import Parse from 'parse/node';
5+
6+
export default (Type) => ({
7+
type: GraphQLList(Type),
8+
args: {
9+
json: {
10+
type: JSON,
11+
}
12+
},
13+
resolve(_, { json }, context, info) {
14+
const fields = getFieldNames(info);
15+
const query = Parse.Query.from(json);
16+
fields.forEach(field => query.include(field));
17+
return query.find();
18+
}
19+
});

0 commit comments

Comments
 (0)