Skip to content

Commit 0e4a629

Browse files
Merge pull request #160 from protographql2/master
Version 2 Pull Request
2 parents ab75009 + 3badf67 commit 0e4a629

19 files changed

+239
-95
lines changed

README.md

+64-55
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,84 @@
11
<p align="center" ><img src="public/assets/pictures/ProtographQLBanner.png" width="800px"></p>
2-
3-
# ProtoGraphQL
4-
5-
ProtoGraphQL is a **prototyping tool** that helps developers build and visualize GraphQL schemas and queries without writing any code. Users simply input their relational database tables and ProtoGraphQL will dynamically create a customized and functional GraphQL Apollo Server readily available for export.
6-
7-
ProtoGraphQL is currently in beta. We would appreciate if you could post any issues to our GitHub – we are actively looking for areas for improvement and we welcome feedback from the community.
8-
9-
Upcoming releases include adding visual indicators for table relationships in the “Schema” view, enabling users to create customizable GraphQL mutations, and extending support for NoSQL databases such as MongoDB.
10-
11-
\* *We recently added support for users to view the structures and relationships of their tables using our GraphQL schema tree visualizer!*
12-
2+
3+
# ProtoGraphQL ver. 2.0
4+
5+
*** The latest release of ProtoGraphQL includes a new view that can jumpstart your query testing with the Jest framework and the ability to import tables from an existing database. ***
6+
7+
ProtoGraphQL is a **prototyping tool** that empowers developers to build and visualize GraphQL schemas and queries without writing any code. Once users import or input their relational database tables, ProtoGraphQL can generate an export package that allows developers to spin up a customized and functional GraphQL Apollo Server as an independent app. (As of version 2.0 custom mutations are also supported!)
8+
9+
ProtoGraphQL is in beta. Please post any issues to our GitHub - we are actively looking for opportunities to improve this tool and we welcome your feedback.
10+
11+
Upcoming releases will improve the “Schema” view and add support for NoSQL databases.
12+
1313
## Getting Started:
14-
15-
1. Download for [Mac](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/ProtoGraphQL-1.0.0.dmg), [Windows](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/ProtoGraphQL.Setup.1.0.0.exe), or [Linux](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/protographql_1.0.0_amd64.deb)
16-
14+
15+
1. Download: [Mac](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/ProtoGraphQL-1.0.0.dmg), [Windows](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/ProtoGraphQL.Setup.1.0.0.exe), [Linux](https://github.com/oslabs-beta/protographql/releases/download/v1.0.0-beta/protographql_1.0.0_amd64.deb)
16+
1717
2. Extract file
18-
19-
3. Run app
20-
18+
19+
3. Run application
20+
2121
## How to Use:
22-
23-
1. When the application loads, click on **Add Table** and populate the table form with a name and new fields. Optionally, you may also use the last three inputs in the form to create relationships to other tables. When you are done, click **Save**.
24-
25-
<p align="center"><kbd><img src="public/assets/pictures/add-table demo.mov.gif" width="800px"></kbd><p>
26-
27-
2. Navigate to the **Schema**, **Code**, and **Visualize** tabs to toggle views:
28-
* **Schema** - view, edit, or delete tables you've added
22+
23+
1. When the application starts you will be given the option to either **CREATE YOUR TABLES** or **IMPORT TABLES**. To create your tables, click the “Add Table” button in the lower left corner of the screen. When your config is complete, click **Save**. When importing, simply paste your database URI in the field and click the **Connect** button. In either case, your tables will be displayed in the main view when you are done.
24+
25+
<p align="center"><kbd><img src="public/assets/pictures/v2-add-tables.gif" width="800px"></kbd><p>
26+
27+
2. Navigate to the alternate views within the app using the tabs on the left: **Schema**, **Code**, **Visualize**, and **Tests**
28+
29+
* **Schema** - view, edut or delete tables you've added.
2930

30-
<p align="center"><kbd><img src="public/assets/pictures/Schema_Screenshot.png" width="800px"></kbd></p>
31+
<p align="center"><kbd><img src="public/assets/pictures/v2-schema-view.png" width="800px"></kbd></p>
3132

32-
* **Code** - view generated GraphQL and SQL code before export
33+
* **Code** - view generated GraphQL and SQL code.
3334

34-
<p align="center"><kbd><img src="public/assets/pictures/Code_Screenshot.png" width="800px"></kbd></p>
35+
<p align="center"><kbd><img src="public/assets/pictures/v2-codeview.png" width="800px"></kbd></p>
3536

36-
* **Visualize** - view the GraphQL schema intuitively as a simple tree
37+
* **Visualize** - view the GraphQL schema as a simple tree.
3738

38-
<p align="center" ><kbd><img src="public/assets/pictures/tree visializer demo.gif" width="800px"></kbd></p>
39-
40-
3. Export the code by clicking the **Export** icon.
41-
42-
<p align="center" ><kbd><img src="public/assets/pictures/Export_Screenshot.png" width="800px"></kbd></p>
43-
44-
4. Enter your Postgres database URI and then select the directory you want to save your executable GraphQL server.
45-
39+
<p align="center" ><kbd><img src="public/assets/pictures/v2-visualizer.gif" width="800px"></kbd></p>
40+
41+
* **Tests** - create and export query and response pairs from a custom GraphQL Endpoint.
42+
43+
<p align="center" ><kbd><img src="public/assets/pictures/v2-test-queries.gif" width="800px"></kbd></p>
44+
45+
3. Export your code by clicking the **Export** icon in the upper right.
46+
47+
<p align="center" ><kbd><img src="public/assets/pictures/v2-export.png" width="800px"></kbd></p>
48+
49+
4. Enter your Postgres database URI, then select the directory you want to save your compressed GraphQL server package in.
50+
51+
4652
## How to Run GraphQL Server:
47-
53+
4854
There are several libraries we could have used to create a GraphQL server, but we decided to use Apollo Server – the most popular library to setup an endpoint for responding to incoming GraphQL requests in JavaScript.
49-
50-
1. Extract apollo-server.zip file
51-
55+
56+
1. Extract apollo-server.zip file
57+
5258
2. Open the project
53-
54-
3. Install dependencies
59+
60+
3. Install dependencies
5561
```
5662
npm install
5763
```
58-
59-
4. Run the server and visit localhost:3000
64+
65+
4. Run the server and point your browser to localhost:3000
6066
```
6167
npm start
6268
```
63-
64-
5. Use Apollo Server Playground to mock client GraphQL queries and responses to your server. [Learn more about constructing GraphQL Queries here](https://graphql.org/learn/queries/)
65-
69+
70+
5. Use Apollo Server Playground to mock client GraphQL queries and responses to your server. [Learn more about constructing GraphQL Queries here](https://graphql.org/learn/queries/)
71+
6672
## Contributors:
67-
73+
6874
<img align="right" src="public/assets/pictures/icon/icon.png" width="125px">
69-
70-
- Alena Budzko [@AlenaBudzko](https://github.com/AlenaBudzko)
71-
- Bryan Fong [@bryanfong-dev](https://github.com/bryanfong-dev)
72-
- Rodolfo Guzman [@Rodolfoguzman25](https://github.com/Rodolfoguzman25)
73-
- Jarred Jack Harewood [@jackhajb](https://github.com/jackhajb)
74-
- Geoffrey Lin [@geofflin](https://github.com/geofflin)
75-
75+
76+
- Alena Budzko | [@AlenaBudzko](https://github.com/AlenaBudzko)
77+
- Bryan Fong | [@bryanfong-dev](https://github.com/bryanfong-dev)
78+
- Rodolfo Guzman | [@Rodolfoguzman25](https://github.com/Rodolfoguzman25)
79+
- Haris Hambasic | [@hambasicharis1995](https://github.com/hambasicharis1995)
80+
- Jarred Jack Harewood | [@jackhajb](https://github.com/jackhajb)
81+
- Geoffrey Lin | [@geofflin](https://github.com/geofflin)
82+
- Michele Moody | [@Milmoody](https://github.com/Milmoody)
83+
- Jessica Vaughan | [@jessicavaughan820](https://github.com/jessicavaughan820)
84+
- Vance Wallace | [@Vancito](https://github.com/Vancito)

src/utils/buildENV.test.js renamed to _protographql_tests_/buildENV.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import buildEnvURI from './buildENV';
2-
import buildENV from './buildENV';
1+
import buildEnvURI from '../src/utils/buildENV';
2+
import buildENV from '../src/utils/buildENV';
33

44
test('When trying to create the Environment URI the result is not null: ', () => {
55
expect(buildEnvURI("thisIsNotNull")).not.toBeNull;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import buildGQLInputTypes from '../src/utils/buildGQLInputTypes';
2+
import { build } from 'protobufjs';
3+
4+
const testInput = {
5+
0: {
6+
type: 'FirstTable',
7+
fields: {
8+
0: {
9+
name: 'FirstColumn',
10+
type: 'ID',
11+
primaryKey: true,
12+
unique: true,
13+
required: false,
14+
defaultValue: '1',
15+
relationSelected: false,
16+
relation: {
17+
tableIndex: -1,
18+
fieldIndex: -1,
19+
refType: ''
20+
},
21+
tableNum: 0,
22+
fieldNum: 0,
23+
queryable: false
24+
},
25+
1: {
26+
name: 'SecondColumn',
27+
type: 'String',
28+
primaryKey: false,
29+
unique: false,
30+
required: true,
31+
defaultValue: 'thisIsADefaultValue',
32+
relationSelected: false,
33+
relation: {
34+
tableIndex: -1,
35+
fieldIndex: -1,
36+
refType: ''
37+
},
38+
tableNum: 0,
39+
fieldNum: 1,
40+
queryable: true
41+
},
42+
2: {
43+
name: 'ThirdColumn',
44+
type: 'String',
45+
primaryKey: false,
46+
unique: false,
47+
required: true,
48+
defaultValue: '',
49+
relationSelected: false,
50+
relation: {
51+
tableIndex: -1,
52+
fieldIndex: -1,
53+
refType: ''
54+
},
55+
tableNum: 0,
56+
fieldNum: 2,
57+
queryable: false
58+
}
59+
},
60+
fieldIndex: 3,
61+
tableID: 0
62+
},
63+
1: {
64+
type: 'SecondTable',
65+
fields: {
66+
0: {
67+
name: 'SecondTableFirstColumn',
68+
type: 'ID',
69+
primaryKey: true,
70+
unique: true,
71+
required: false,
72+
defaultValue: '',
73+
relationSelected: false,
74+
relation: {
75+
tableIndex: -1,
76+
fieldIndex: -1,
77+
refType: ''
78+
},
79+
tableNum: 1,
80+
fieldNum: 0,
81+
queryable: true
82+
},
83+
1: {
84+
name: 'SecondSecondColumn',
85+
type: 'String',
86+
primaryKey: false,
87+
unique: false,
88+
required: true,
89+
defaultValue: 'anotherDefaultValue',
90+
relationSelected: false,
91+
relation: {
92+
tableIndex: -1,
93+
fieldIndex: -1,
94+
refType: ''
95+
},
96+
tableNum: 1,
97+
fieldNum: 1,
98+
queryable: true
99+
},
100+
2: {
101+
name: 'SecondThirdColumn',
102+
type: 'ID',
103+
primaryKey: false,
104+
unique: false,
105+
required: true,
106+
defaultValue: '',
107+
relationSelected: true,
108+
relation: {
109+
tableIndex: '0',
110+
fieldIndex: '0',
111+
refType: 'many to one'
112+
},
113+
tableNum: 1,
114+
fieldNum: 2,
115+
queryable: true
116+
}
117+
},
118+
fieldIndex: 3,
119+
tableID: 1
120+
},
121+
};
122+
123+
const testOutput = ` input FirstTableInput {
124+
FirstColumn: ID,
125+
SecondColumn: String!,
126+
ThirdColumn: String!,
127+
}
128+
129+
input SecondTableInput {
130+
SecondTableFirstColumn: ID,
131+
SecondSecondColumn: String!,
132+
firsttable: FirstTableInput,
133+
}
134+
135+
`
136+
137+
test('Building GQL Input Types does not return null: ', () => {
138+
expect(buildGQLInputTypes(testInput)).not.toBeNull;
139+
});
140+
141+
test('When trying to create the GQL Input Types the result is a string: ', () => {
142+
expect(typeof(buildGQLInputTypes(testInput))).toBe('string');
143+
});
144+
145+
test('Building GQL Input Types works given test input: ', () => {
146+
expect(buildGQLInputTypes(testInput)).toBe(testOutput);
147+
});

src/utils/buildGQLSchema.test.js renamed to _protographql_tests_/buildGQLSchema.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import buildGQLSchema from './buildGQLSchema';
1+
import buildGQLSchema from '../src/utils/buildGQLSchema';
22
import { build } from 'protobufjs';
33

44
const testInput = {
611 KB
Loading
198 KB
Loading

public/assets/pictures/v2-export.png

160 KB
Loading
582 KB
Loading
50.4 KB
Loading
838 KB
Loading
963 KB
Loading

src/components/popup/instructions.jsx

+5-4
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,11 @@ function DraggableDialog(props) {
9393
<Title style={{ cursor: "move" }} id="draggable-dialog-title">Instructions</Title>
9494

9595
<ContentDiv style={{ marginTop: "15px", marginBottom: "25px", textAlign: "left" }}>
96-
<DialogContentText>1) Add the endpoint of your running GraphQL server in the "GraphQL Endpoint URL" box. (For example: "http://localhost:3000") Click the "Add URL" button</DialogContentText>
97-
<DialogContentText>2) Type your test query in the box on the left.</DialogContentText>
98-
<DialogContentText>3) Click the "Add Query" button <br />(Repeat steps 2 and 3 to add additional query response pairs)</DialogContentText>
99-
<DialogContentText>4) To export your test file click the "Export Tests" button.</DialogContentText>
96+
<DialogContentText>1) Add the endpoint of your running GraphQL server in the "GraphQL Endpoint URL" box. Click the "Add URL" button</DialogContentText>
97+
<DialogContentText>2) If no valid endpoint is entered, the default endpoint will be set to http://localhost:3000/GraphQL </DialogContentText>
98+
<DialogContentText>3) Type your test query in the box on the left.</DialogContentText>
99+
<DialogContentText>4) Click the "Add Query" button <br />(Repeat steps 2 and 3 to add additional query response pairs)</DialogContentText>
100+
<DialogContentText>5) To export your test file click the "Export Tests" button.</DialogContentText>
100101
</ContentDiv>
101102
<DialogActionsDiv>
102103
<GotItButton onClick={handleClose} color="primary">Got it!</GotItButton>

src/components/view/testsView.jsx

+7-4
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,13 @@ function updateURL() {
171171
if (url.match(/http:\/\/.+/) || url.match(/https:\/\/.+/)) {
172172
dispatch({ type: ADD_APOLLO_SERVER_URI, payload: url });
173173
console.log('test updateURL', apolloServerURI);
174+
document.querySelector('#endpointStatus').innerHTML = `Current endpoint: ${document.getElementById('url').value}`;
175+
document.querySelector('#endpointStatus').classList.remove('invisible');
174176
document.getElementById('url').value = '';
175-
document.querySelector('#endpointError').classList.add('invisible');
176177
} else {
177-
document.querySelector('#endpointError').classList.remove('invisible');
178-
}
178+
document.querySelector('#endpointStatus').innerHTML = "Endpoint must include http:// or https://";
179+
document.querySelector('#endpointStatus').classList.remove('invisible');
180+
}
179181
}
180182

181183
useEffect(() => {
@@ -185,6 +187,7 @@ useEffect(() => {
185187
}
186188
document.getElementById("queriesDisplay").innerHTML = display;
187189
});
190+
188191

189192
/*-------------------- Functional Component Rendering --------------------*/
190193
//FOR FUTURE IMPLEMENTATION: Check the user input and maybe ping the endpoint to check that it is live.
@@ -200,7 +203,7 @@ return(
200203
</div>
201204
<div style={{ flexBasis: "80%", lineHeight: ".01em" }}>
202205
<Input type='text' id='url' placeholder='Enter Your Custom GraphQL Endpoint URL here'></Input><Button style={{ width: "20%" }} onClick={updateURL}>Add URL</Button>
203-
<p className="invisible" id="endpointError">That is not a valid endpoint. If no valid endpoint is entered, the endpoint will remain unchanged. The initial value is set to http://localhost:3000/GraphQL</p>
206+
<p className="invisible" id="endpointStatus">Current endpoint: </p>
204207
</div>
205208
</div>
206209
</Column>

src/utils/buildGQLInputTypes.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const buildGQLInputTypes = tables => {
1111
// Iterate through each table field and define its respective GQL property
1212
for (let fieldIndex in table.fields) {
1313
const field = table.fields[fieldIndex];
14-
gqlTypes += addScalarField(field);
14+
gqlTypes += field.relationSelected ? addObjectInput(tables, field) : addScalarField(field);
1515
gqlTypes += `,\n`;
1616
}
1717
gqlTypes += `${tabs(1)}}\n\n`; // Close GQL type definition
@@ -22,6 +22,17 @@ const buildGQLInputTypes = tables => {
2222

2323
/********************************** HELPER FUNCTIONS **********************************/
2424

25+
// Returns a string of a GQL object field
26+
const addObjectInput = (tables, field) => {
27+
const { tableIndex, refType } = field.relation;
28+
const linkedTableName = tables[tableIndex].type;
29+
// Wrap linked field in curly braces if we have an 'xxx to many' relationship
30+
let objectField = refType.slice(-4) === `many` ?
31+
`${tabs(2)}${linkedTableName.toLowerCase()}: [${linkedTableName}Input]` :
32+
`${tabs(2)}${linkedTableName.toLowerCase()}: ${linkedTableName}Input`;
33+
return objectField;
34+
}
35+
2536
// Returns a string of a GQL scalar field
2637
const addScalarField = field => {
2738
let scalarField = `${tabs(2)}${field.name}: ${field.type}`;

src/utils/buildGQLResolvers.js

-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ const buildGQLResolvers = tables => {
9494
gqlResolvers += `${tabs(3)}let valuesStr = \` VALUES (\`;\n`;
9595
gqlResolvers += `${tabs(3)}let values = [];\n`;
9696
gqlResolvers += `${tabs(3)}let columnsStr = \`(\`\n`;
97-
gqlResolvers += `${tabs(3)}const returning = \` RETURNING *\`\n`;
9897
gqlResolvers += `${tabs(3)}Object.keys(args.input).forEach((fieldName, i, arr) => {\n`;
9998
gqlResolvers += `${tabs(4)}if(i == arr.length - 1){\n`;
10099
gqlResolvers += `${tabs(5)}columnsStr += \`\${fieldName})\`\n`;

src/utils/utils.test.js

-5
This file was deleted.

0 commit comments

Comments
 (0)