Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] multi-node types #121

Merged
merged 5 commits into from
Feb 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ plugins: [
baseId: `YOUR_AIRTABLE_BASE_ID`,
tableName: `YOUR_TABLE_NAME`,
tableView: `YOUR_TABLE_VIEW_NAME`, // optional
queryName: `OPTIONAL_NAME_TO_IDENTIFY_TABLE`, // optional
queryName: `OPTIONAL_NAME_TO_IDENTIFY_TABLE`, // optionally default is false - makes all records in this table a separate node type, based on your tableView, or if not present, tableName, e.g. a table called "Fruit" would become "allAirtableFruit". Useful when pulling many airtables with similar structures or fields that have different types. See https://github.com/jbolda/gatsby-source-airtable/pull/52.
mapping: { `CASE_SENSITIVE_COLUMN_NAME`: `VALUE_FORMAT` }, // optional, e.g. "text/markdown", "fileNode"
tableLinks: [`CASE`, `SENSITIVE`, `COLUMN`, `NAMES`] // optional, for deep linking to records across tables.
createSeparateNodeType: false, // boolean, default is false, see the documentation on naming conflicts for more information
separateMapType: false, // boolean, default is false, see the documentation on using markdown and attachments for more information
},
{
baseId: `YOUR_AIRTABLE_BASE_ID`,
Expand Down Expand Up @@ -108,6 +110,8 @@ For an example of a markdown-and-airtable-driven site using `gatsby-transformer-

If you are using the `Attachment` type field in Airtable, you may specify a column name with `fileNode` and the plugin will bring in these files. Using this method, it will create "nodes" for each of the files and expose this to all of the transformer plugins. A good use case for this would be attaching images in Airtable, and being able to make these available for use with the `sharp` plugins and `gatsby-image`. Specifying a `fileNode` does require a peer dependency of `gatsby-source-filesystem` otherwise it will fall back as a non-mapped field. The locally available files and any ecosystem connections will be available on the node as `localFiles`.

If you are specifying more than one type of `mapping`, you may potentially run into issues with data types clashing and throwing errors. An additional option that you may specify is `separateMapType` which will create a gatsby node type for each type of data. This should prevent issues with your data types clashing.

When using the Attachment type field, this plugin governs requests to download the associated files from Airtable to 5 concurrent requests to prevent excessive requests on Airtable's servers - which can result in refused / hanging connections. You can adjust this limit with the concurrency option in your gatsby-config.js file. Set the option with an integer value for your desired limit on attempted concurrent requests. A value of 0 will allow requests to be made without any limit.

### The power of views
Expand All @@ -120,6 +124,8 @@ For example, if you are creating a blog or documentation site, specify a `publis

You may have a situation where you are including two separate bases, each with a table that has the exact same name. With the data structure of this repo, both bases would fall into allAirtable and you wouldn't be able to tell them apart when building graphQL queries. This is what the optional `queryName` setting is for-- simply to provide an alternate name for a table.

If you would like to have the query names for tables be different from the default `allAirtable` or `airtable`, you may specify `createSeparateNodeType` as `true`.

### Column Names

Within graphql (the language you query information from and that this plugin puts nodes into), there are character limitations. Most specifically we cannot have spaces in field names. We don't want to force you to change your Airtable names, so we will "clean" the keys and replace the spaces with an underscore (e.g. The Column Name becomes The_Column_Name). We use the cleaned name everywhere including `gatsby-config.js` and within your queries. We don't warn you when this happens to cut down on the verbosity of the output.
Expand Down
59 changes: 59 additions & 0 deletions examples/recipes-with-multi-type/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module.exports = {
siteMetadata: {
title: "Gatsby Recipes"
},
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `pages`,
path: `${__dirname}/src/pages/`
}
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `assets`,
path: `${__dirname}/src/assets/`
}
},
{
resolve: `gatsby-source-airtable`,
options: {
apiKey: process.env.AIRTABLE_API_KEY_DEV, //(set via environment variable for this example)
tables: [
{
baseId: `appM8D8wmSJX9WJDE`,
tableName: `Recipes`,
queryName: `Recipes`,
tableView: `List`,
mapping: {
Attachments: `fileNode`,
Ingredients: "text/markdown",
Directions: "text/markdown"
},
tableLinks: [`Cooking_Method`, `Style`],
separateNodeType: true,
separateMapType: true
},
{
baseId: `appM8D8wmSJX9WJDE`,
tableName: `Cooking Method`,
tableView: `Main View`,
tableLinks: [`Recipes`]
},
{
baseId: `appM8D8wmSJX9WJDE`,
tableName: `Style`,
tableView: `Main View`,
tableLinks: [`Recipes`]
}
]
}
},
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
`gatsby-plugin-mdx`,
`gatsby-plugin-react-helmet`
]
};
67 changes: 67 additions & 0 deletions examples/recipes-with-multi-type/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const path = require(`path`);

exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
let slug;

if (node.internal.type === `AirtableRecipes` && node.table === `Recipes`) {
slug = `/${node.data.Name.replace(/ /g, "-")
.replace(/[,&]/g, "")
.toLowerCase()}/`;

// Add slug as a field on the node.
createNodeField({ node, name: `slug`, value: slug });
}
};

exports.createPages = ({ graphql, actions }) => {
const { createPage, createRedirect } = actions;

return new Promise((resolve, reject) => {
const pages = [];
const atRecipes = path.resolve(`src/templates/recipeTemplate.js`);

// Query for all markdown "nodes" and for the slug we previously created.
resolve(
graphql(
`
{
allAirtableRecipes(filter: { table: { eq: "Recipes" } }) {
edges {
node {
id
data {
Name
}
fields {
slug
}
}
}
}
}
`
).then(result => {
if (result.errors) {
result.errors.forEach(error => {
console.log(error);
});

reject(result.errors);
}

result.data.allAirtableRecipes.edges.forEach(edge => {
createPage({
path: edge.node.fields.slug, // required, we don't have frontmatter for this page hence separate if()
component: atRecipes,
context: {
name: edge.node.data.Name
}
});
});

return;
})
);
});
};
Loading