Skip to content

Commit

Permalink
Merge pull request #3 from malcolm-kee/v2
Browse files Browse the repository at this point in the history
v2: Support Join
  • Loading branch information
malcolm-kee authored May 19, 2019
2 parents 9535e8c + bea7b42 commit 7f6a56c
Show file tree
Hide file tree
Showing 10 changed files with 4,619 additions and 102 deletions.
14 changes: 14 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": ["eslint:recommended"],
"parserOptions": {
"ecmaVersion": 2017
},
"env": {
"node": true,
"es6": true,
"jest": true
},
"rules": {
"no-console": ["error", { "allow": ["error"] }]
}
}
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
language: node_js
node_js:
- '8'
149 changes: 117 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,82 +19,167 @@ module.exports = {
password: 'db-password',
database: 'world'
},
query: 'SELECT * FROM city',
idFieldName: 'ID'
queries: [
{
statement: 'SELECT * FROM country',
idFieldName: 'Code',
name: 'country'
}
]
}
}
// ... other plugins
]
};
```

And then you can query via GraphQL with the type `allMysql<Name>` where `<Name>` is the `name` for your query.

Below is a sample query, however, it is probably different from yours as it would dependent on your configuration and your SQL query results.

Use [GraphiQL](https://www.gatsbyjs.org/docs/introducing-graphiql/) to explore the available fields.

```graphql
query {
allMysqlCountry {
edges {
node {
Code
Name
Population
}
}
}
}
```

### multiple queries

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

```javascript
// In your gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-source-mysql',
resolve: `gatsby-source-mysql`,
options: {
connectionDetails: {
host: 'localhost',
user: 'malcolm',
password: 'password',
user: 'db-username',
password: 'db-password',
database: 'world'
},
query: 'SELECT * FROM city',
idFieldName: 'ID',
typePrefix: 'City'
queries: [
{
statement: 'SELECT * FROM country',
idFieldName: 'Code',
name: 'country'
},
{
statement: 'SELECT * FROM city',
idFieldName: 'ID',
name: 'city'
}
]
}
},
}
// ... other plugins
]
};
```

### joining queries

It's possible to join the results of the queries by providing `parentName`, `foreignKey`, and `cardinality` to the query object.

> 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.
```javascript
// In your gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-source-mysql',
resolve: `gatsby-source-mysql`,
options: {
connectionDetails: {
host: 'localhost',
user: 'malcolm',
password: 'password',
user: 'db-username',
password: 'db-password',
database: 'world'
},
query: 'SELECT * FROM country',
idFieldName: 'Code',
typePrefix: 'Country'
queries: [
{
statement: 'SELECT * FROM country',
idFieldName: 'Code',
name: 'country'
},
{
statement: 'SELECT * FROM city',
idFieldName: 'ID',
name: 'city',
parentName: 'country',
foreignKey: 'CountryCode',
cardinality: 'OneToMany'
}
]
}
}
// ... other plugins
]
};
```

## Plugin options

As this plugin is a wrapper of the popular [`mysql`](https://www.npmjs.com/package/mysql) library, the options are based on the library.

- **connectionDetails** (required): options when establishing the connection. Refer to [`mysql` connection options](https://www.npmjs.com/package/mysql#connection-options)
- **query** (required): the SQL query statement to be executed.
- **idFieldName** (required): column that is unique for each record. This column must be included in the `query`.
- **typePrefix** (optional): the prefix of the data source in the GraphQL schema. Default to `MySql`.

## How to query your data using GraphQL

The GraphQL type would be follow the format of `all<typePrefix>Results`.

Below is a sample query, however, it is probably different from yours as it would dependent on your configuration and your SQL query results.
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`.

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

```graphql
query {
allCountryResults {
allMysqlCountry {
edges {
node {
Code
Name
Population
cities {
Name
}
}
}
}
}
```

It also works the other way, i.e. you can query the country when getting the city

```graphql
query {
allMysqlCity {
edges {
node {
Name
country {
Name
}
}
}
}
}
```

## Plugin options

- **connectionDetails** (required): options when establishing the connection. Refer to [`mysql` connection options](https://www.npmjs.com/package/mysql#connection-options)
- **queries** (required): an array of object for your query. Each object could have the following fields:

| Field | Required? | Description |
| ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `statement` | Required | the SQL query statement to be executed. |
| `idFieldName` | Required | column that is unique for each record. This column must be returned by the `statement`. |
| `name` | Required | name for the query. Will impact the value for the graphql type |
| `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). |
| `foreignKey` | Optional | foreign key to join the parent entity. |
| `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.) |

[raise-issue]: https://github.com/malcolm-kee/gatsby-source-mysql/issues/new
51 changes: 18 additions & 33 deletions gatsby-node.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,24 @@
const createNodeHelpers = require('gatsby-node-helpers').default;
const mysql = require('mysql');
const queryDb = require('./src/db');
const createMysqlNodes = require('./src/create-mysql-nodes');

exports.sourceNodes = ({ actions }, configOptions) => {
exports.sourceNodes = async ({ actions }, configOptions) => {
const { createNode } = actions;
const {
connectionDetails,
query,
idFieldName = 'id',
typePrefix = 'MySql'
} = configOptions;
const { createNodeFactory } = createNodeHelpers({
typePrefix
});
const { connectionDetails, queries } = configOptions;

const MySqlNode = createNodeFactory('Results');
const { db, queryResults } = await queryDb(connectionDetails, queries);

const dbConnection = mysql.createConnection(connectionDetails);
try {
queries
.map((query, index) =>
Object.assign({}, query, { __sqlResult: queryResults[index] })
)
.forEach((sqlResult, _, sqlResults) =>
createMysqlNodes(sqlResult, sqlResults, createNode)
);

return new Promise((fulfill, reject) => {
dbConnection.query(query, (error, results, fields) => {
if (error) return reject(error);

if (Array.isArray(results)) {
results.forEach((result, index) => {
const sanitizedResult = Object.assign({}, result, {
id: result[idFieldName]
});
const resultNode = MySqlNode(sanitizedResult);
createNode(resultNode);
});
}

fulfill();
});

dbConnection.end();
});
db.end();
} catch (e) {
console.error(e);
db.end();
}
};
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"name": "gatsby-source-mysql",
"version": "1.0.0",
"version": "2.0.0",
"description": "Source plugin for pulling data into Gatsby from MySQL database.",
"author": "Malcolm Kee <[email protected]>",
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"lint": "eslint src"
},
"keywords": [
"gatsby",
"gatsby-plugin",
Expand All @@ -11,7 +16,8 @@
"license": "MIT",
"dependencies": {
"gatsby-node-helpers": "^0.3.0",
"mysql": "^2.16.0"
"mysql": "^2.16.0",
"pluralize": "^7.0.0"
},
"peerDependencies": {
"gatsby": ">2.0.0"
Expand All @@ -21,5 +27,10 @@
"homepage": "https://github.com/malcolm-kee/gatsby-source-mysql#readme",
"bugs": {
"url": "https://github.com/malcolm-kee/gatsby-source-mysql/issues"
},
"devDependencies": {
"@types/jest": "^24.0.12",
"eslint": "^5.16.0",
"jest": "^24.8.0"
}
}
Loading

0 comments on commit 7f6a56c

Please sign in to comment.