Skip to content

Commit 7f6a56c

Browse files
authored
Merge pull request #3 from malcolm-kee/v2
v2: Support Join
2 parents 9535e8c + bea7b42 commit 7f6a56c

10 files changed

+4619
-102
lines changed

.eslintrc.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extends": ["eslint:recommended"],
3+
"parserOptions": {
4+
"ecmaVersion": 2017
5+
},
6+
"env": {
7+
"node": true,
8+
"es6": true,
9+
"jest": true
10+
},
11+
"rules": {
12+
"no-console": ["error", { "allow": ["error"] }]
13+
}
14+
}

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
language: node_js
2+
node_js:
3+
- '8'

README.md

+117-32
Original file line numberDiff line numberDiff line change
@@ -19,82 +19,167 @@ module.exports = {
1919
password: 'db-password',
2020
database: 'world'
2121
},
22-
query: 'SELECT * FROM city',
23-
idFieldName: 'ID'
22+
queries: [
23+
{
24+
statement: 'SELECT * FROM country',
25+
idFieldName: 'Code',
26+
name: 'country'
27+
}
28+
]
2429
}
2530
}
2631
// ... other plugins
2732
]
2833
};
2934
```
3035

36+
And then you can query via GraphQL with the type `allMysql<Name>` where `<Name>` is the `name` for your query.
37+
38+
Below is a sample query, however, it is probably different from yours as it would dependent on your configuration and your SQL query results.
39+
40+
Use [GraphiQL](https://www.gatsbyjs.org/docs/introducing-graphiql/) to explore the available fields.
41+
42+
```graphql
43+
query {
44+
allMysqlCountry {
45+
edges {
46+
node {
47+
Code
48+
Name
49+
Population
50+
}
51+
}
52+
}
53+
}
54+
```
55+
3156
### multiple queries
3257

33-
When you have multiple queries, include the plugins multiple times with different `typePrefix`.
58+
When you have multiple queries, add another item in the `queries` option with different `name`.
3459

3560
```javascript
61+
// In your gatsby-config.js
3662
module.exports = {
3763
plugins: [
3864
{
39-
resolve: 'gatsby-source-mysql',
65+
resolve: `gatsby-source-mysql`,
4066
options: {
4167
connectionDetails: {
4268
host: 'localhost',
43-
user: 'malcolm',
44-
password: 'password',
69+
user: 'db-username',
70+
password: 'db-password',
4571
database: 'world'
4672
},
47-
query: 'SELECT * FROM city',
48-
idFieldName: 'ID',
49-
typePrefix: 'City'
73+
queries: [
74+
{
75+
statement: 'SELECT * FROM country',
76+
idFieldName: 'Code',
77+
name: 'country'
78+
},
79+
{
80+
statement: 'SELECT * FROM city',
81+
idFieldName: 'ID',
82+
name: 'city'
83+
}
84+
]
5085
}
51-
},
86+
}
87+
// ... other plugins
88+
]
89+
};
90+
```
91+
92+
### joining queries
93+
94+
It's possible to join the results of the queries by providing `parentName`, `foreignKey`, and `cardinality` to the query object.
95+
96+
> Currently only one-to-one and one-to-many relationship are supported. If you have a use case for many-to-many relationship, [raise an issue][raise-issue], and I'll look into it.
97+
98+
```javascript
99+
// In your gatsby-config.js
100+
module.exports = {
101+
plugins: [
52102
{
53-
resolve: 'gatsby-source-mysql',
103+
resolve: `gatsby-source-mysql`,
54104
options: {
55105
connectionDetails: {
56106
host: 'localhost',
57-
user: 'malcolm',
58-
password: 'password',
107+
user: 'db-username',
108+
password: 'db-password',
59109
database: 'world'
60110
},
61-
query: 'SELECT * FROM country',
62-
idFieldName: 'Code',
63-
typePrefix: 'Country'
111+
queries: [
112+
{
113+
statement: 'SELECT * FROM country',
114+
idFieldName: 'Code',
115+
name: 'country'
116+
},
117+
{
118+
statement: 'SELECT * FROM city',
119+
idFieldName: 'ID',
120+
name: 'city',
121+
parentName: 'country',
122+
foreignKey: 'CountryCode',
123+
cardinality: 'OneToMany'
124+
}
125+
]
64126
}
65127
}
66128
// ... other plugins
67129
]
68130
};
69131
```
70132

71-
## Plugin options
72-
73-
As this plugin is a wrapper of the popular [`mysql`](https://www.npmjs.com/package/mysql) library, the options are based on the library.
74-
75-
- **connectionDetails** (required): options when establishing the connection. Refer to [`mysql` connection options](https://www.npmjs.com/package/mysql#connection-options)
76-
- **query** (required): the SQL query statement to be executed.
77-
- **idFieldName** (required): column that is unique for each record. This column must be included in the `query`.
78-
- **typePrefix** (optional): the prefix of the data source in the GraphQL schema. Default to `MySql`.
79-
80-
## How to query your data using GraphQL
81-
82-
The GraphQL type would be follow the format of `all<typePrefix>Results`.
83-
84-
Below is a sample query, however, it is probably different from yours as it would dependent on your configuration and your SQL query results.
133+
In the example above, `country` and `city` is one-to-many relationship (one country to multiple cities), and they are joined with `country.Code = city.CountryCode`.
85134

86-
Use [GraphiQL](https://www.gatsbyjs.org/docs/introducing-graphiql/) to explore the available fields.
135+
With the configuration above, you can query a country joined with all the related cities with
87136

88137
```graphql
89138
query {
90-
allCountryResults {
139+
allMysqlCountry {
91140
edges {
92141
node {
93142
Code
94143
Name
95144
Population
145+
cities {
146+
Name
147+
}
148+
}
149+
}
150+
}
151+
}
152+
```
153+
154+
It also works the other way, i.e. you can query the country when getting the city
155+
156+
```graphql
157+
query {
158+
allMysqlCity {
159+
edges {
160+
node {
161+
Name
162+
country {
163+
Name
164+
}
96165
}
97166
}
98167
}
99168
}
100169
```
170+
171+
## Plugin options
172+
173+
- **connectionDetails** (required): options when establishing the connection. Refer to [`mysql` connection options](https://www.npmjs.com/package/mysql#connection-options)
174+
- **queries** (required): an array of object for your query. Each object could have the following fields:
175+
176+
| Field | Required? | Description |
177+
| ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
178+
| `statement` | Required | the SQL query statement to be executed. |
179+
| `idFieldName` | Required | column that is unique for each record. This column must be returned by the `statement`. |
180+
| `name` | Required | name for the query. Will impact the value for the graphql type |
181+
| `parentName` | Optional | name for the parent entity. In a one-to-many relationship, this field should be specified on the child entity (entity with many records). |
182+
| `foreignKey` | Optional | foreign key to join the parent entity. |
183+
| `cardinality` | Optional | the relationship between the parent and this entity. Possible values: `"OneToMany"`, `"OneToOne"`. Default to `"OneToMany"`. (Note: many-to-many relationship is currently not supported.) |
184+
185+
[raise-issue]: https://github.com/malcolm-kee/gatsby-source-mysql/issues/new

gatsby-node.js

+18-33
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,24 @@
1-
const createNodeHelpers = require('gatsby-node-helpers').default;
2-
const mysql = require('mysql');
1+
const queryDb = require('./src/db');
2+
const createMysqlNodes = require('./src/create-mysql-nodes');
33

4-
exports.sourceNodes = ({ actions }, configOptions) => {
4+
exports.sourceNodes = async ({ actions }, configOptions) => {
55
const { createNode } = actions;
6-
const {
7-
connectionDetails,
8-
query,
9-
idFieldName = 'id',
10-
typePrefix = 'MySql'
11-
} = configOptions;
12-
const { createNodeFactory } = createNodeHelpers({
13-
typePrefix
14-
});
6+
const { connectionDetails, queries } = configOptions;
157

16-
const MySqlNode = createNodeFactory('Results');
8+
const { db, queryResults } = await queryDb(connectionDetails, queries);
179

18-
const dbConnection = mysql.createConnection(connectionDetails);
10+
try {
11+
queries
12+
.map((query, index) =>
13+
Object.assign({}, query, { __sqlResult: queryResults[index] })
14+
)
15+
.forEach((sqlResult, _, sqlResults) =>
16+
createMysqlNodes(sqlResult, sqlResults, createNode)
17+
);
1918

20-
return new Promise((fulfill, reject) => {
21-
dbConnection.query(query, (error, results, fields) => {
22-
if (error) return reject(error);
23-
24-
if (Array.isArray(results)) {
25-
results.forEach((result, index) => {
26-
const sanitizedResult = Object.assign({}, result, {
27-
id: result[idFieldName]
28-
});
29-
const resultNode = MySqlNode(sanitizedResult);
30-
createNode(resultNode);
31-
});
32-
}
33-
34-
fulfill();
35-
});
36-
37-
dbConnection.end();
38-
});
19+
db.end();
20+
} catch (e) {
21+
console.error(e);
22+
db.end();
23+
}
3924
};

package.json

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
{
22
"name": "gatsby-source-mysql",
3-
"version": "1.0.0",
3+
"version": "2.0.0",
44
"description": "Source plugin for pulling data into Gatsby from MySQL database.",
55
"author": "Malcolm Kee <[email protected]>",
6+
"scripts": {
7+
"test": "jest",
8+
"test:watch": "jest --watch",
9+
"lint": "eslint src"
10+
},
611
"keywords": [
712
"gatsby",
813
"gatsby-plugin",
@@ -11,7 +16,8 @@
1116
"license": "MIT",
1217
"dependencies": {
1318
"gatsby-node-helpers": "^0.3.0",
14-
"mysql": "^2.16.0"
19+
"mysql": "^2.16.0",
20+
"pluralize": "^7.0.0"
1521
},
1622
"peerDependencies": {
1723
"gatsby": ">2.0.0"
@@ -21,5 +27,10 @@
2127
"homepage": "https://github.com/malcolm-kee/gatsby-source-mysql#readme",
2228
"bugs": {
2329
"url": "https://github.com/malcolm-kee/gatsby-source-mysql/issues"
30+
},
31+
"devDependencies": {
32+
"@types/jest": "^24.0.12",
33+
"eslint": "^5.16.0",
34+
"jest": "^24.8.0"
2435
}
2536
}

0 commit comments

Comments
 (0)