├── .gitignore ├── README.md ├── delete-nodes ├── README.md ├── delete-nodes.graphql └── delete-nodes.js ├── fetch └── fetch-query.js ├── graphcool-lib └── simple-example.js ├── json-entries ├── README.md ├── json-entries.graphql └── json-entries.js ├── package.json ├── touch-nodes ├── README.md ├── touch-nodes.graphql └── touch-nodes.js ├── unique-import ├── README.md ├── unique-import.graphql └── unique-import.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | 4 | # testing 5 | coverage 6 | # production 7 | build 8 | 9 | # misc 10 | .DS_Store 11 | npm-debug.log 12 | 13 | #IDE 14 | .idea/* 15 | *.swp 16 | 17 | .temp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scripts 2 | 3 | Collection of Graphcool Scripts 📝 4 | 5 | ## Contributions 6 | 7 | 8 | marktani 9 | 10 | 11 | export-mike 12 | 13 | 14 | ## Help & Community [![Slack Status](https://slack.graph.cool/badge.svg)](https://slack.graph.cool) 15 | 16 | Say hello in our [Slack](http://slack.graph.cool/) or visit the [Graphcool Forum](https://www.graph.cool/forum) if you run into issues or have questions. We love talking to you! 17 | 18 | ![](http://i.imgur.com/5RHR6Ku.png) 19 | -------------------------------------------------------------------------------- /delete-nodes/README.md: -------------------------------------------------------------------------------- 1 | # delete-nodes 2 | 3 | A script that deletes 1000 nodes of a type at a time. 4 | 5 | ### 1. Create GraphQL API with [`graphcool`](https://www.npmjs.com/package/graphcool) 6 | 7 | ```sh 8 | # Install Graphcool CLI 9 | npm install -g graphcool 10 | 11 | # Create a new project with example schema 12 | graphcool init --file delete-nodes.graphql 13 | ``` 14 | 15 | Replace the `__PROJECT_ID__` and if needed the `__PERMANENT_AUTH_TOKEN__`. 16 | 17 | ### 2. Install dependencies 18 | 19 | ```sh 20 | yarn 21 | ``` 22 | 23 | Make sure your node version is at least 7.6.0: 24 | 25 | ```sh 26 | node -v 27 | ``` 28 | 29 | ### 3. Bulk Delete 30 | 31 | Run the script to delete your `Post` and `User` nodes. 32 | 33 | ```sh 34 | node delete-nodes.js 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /delete-nodes/delete-nodes.graphql: -------------------------------------------------------------------------------- 1 | type Post { 2 | id: ID! @isUnique 3 | text: String! 4 | } 5 | 6 | type User { 7 | id: ID! @isUnique 8 | name: String! 9 | } 10 | -------------------------------------------------------------------------------- /delete-nodes/delete-nodes.js: -------------------------------------------------------------------------------- 1 | const { GraphQLClient } = require('graphql-request') 2 | const client = new GraphQLClient('https://api.graph.cool/simple/v1/__PROJECT_ID__', { 3 | headers: { 4 | 'Authorization': `Bearer __PERMANENT_AUTH_TOKEN__` 5 | }, 6 | }) 7 | 8 | const query = T => ` 9 | query Get${T}s { 10 | all${T}s { 11 | id 12 | } 13 | } 14 | ` 15 | 16 | const getAll = async (T) => { 17 | const res = await client.request(query(T)) 18 | return toIds(res[`all${T}s`]) 19 | } 20 | 21 | const del = async (T, accounts) => { 22 | await Promise.all(accounts.map(id => { 23 | const query = ` 24 | mutation Delete${T}($id: ID!) { 25 | delete${T}(id: $id) { 26 | id 27 | } 28 | } 29 | ` 30 | const variables = { 31 | id 32 | } 33 | return client.request(query, variables) 34 | })) 35 | } 36 | 37 | const toIds = array => array.map(e => e.id) 38 | 39 | const detroyAllDataIn = async T => { 40 | const allAccounts = await getAll(T) 41 | await del(T, allAccounts) 42 | console.log(`Deleted: ${allAccounts.length} ${T}s`) 43 | } 44 | 45 | async function main() { 46 | await Promise.all([ 47 | detroyAllDataIn('Post'), 48 | detroyAllDataIn('User'), 49 | // Add more 50 | ]) 51 | } 52 | 53 | main().catch((e) => console.error(e)) 54 | -------------------------------------------------------------------------------- /fetch/fetch-query.js: -------------------------------------------------------------------------------- 1 | require('isomorphic-fetch') 2 | 3 | getMovies = async() => { 4 | 5 | const query = ` 6 | query movies($first: Int!) { 7 | allMovies(first: $first) { 8 | title 9 | } 10 | } 11 | ` 12 | 13 | const variables = { 14 | first: 3 15 | } 16 | 17 | const result = await fetch('https://api.graph.cool/simple/v1/cixos23120m0n0173veiiwrjr', { 18 | method: 'post', 19 | headers: { 20 | 'Content-Type': 'application/json', 21 | }, 22 | body: JSON.stringify({query, variables}) 23 | }) 24 | .then(response => response.json()) 25 | .then(data => { 26 | return data 27 | }) 28 | .catch((e) => { 29 | console.log(e) 30 | }) 31 | 32 | return result.data 33 | } 34 | 35 | main = async() => { 36 | const data = await getMovies() 37 | console.log(data) 38 | } 39 | 40 | main() 41 | -------------------------------------------------------------------------------- /graphcool-lib/simple-example.js: -------------------------------------------------------------------------------- 1 | const { fromEvent } = require('graphcool-lib') 2 | 3 | const pat = '__PAT__' 4 | const projectId = 'cixne4sn40c7m0122h8fabni1' 5 | 6 | const event = { 7 | context: { 8 | graphcool: { 9 | projectId, 10 | // include a PAT if you need full read/write access on the server-side 11 | // pat, 12 | } 13 | } 14 | } 15 | 16 | const api = fromEvent(event).api('simple/v1') 17 | 18 | const query = ` 19 | query { 20 | allMovies { 21 | id 22 | title 23 | } 24 | } 25 | ` 26 | 27 | api.request(query) 28 | .then(data => console.log(data)) -------------------------------------------------------------------------------- /json-entries/README.md: -------------------------------------------------------------------------------- 1 | # json-entries 2 | 3 | Shows the usages of [graphql-request](https://github.com/graphcool/graphql-request) to run a GraphQL mutation with JSON and JSON list variables 4 | 5 | ### 1. Create GraphQL API with [`graphcool`](https://www.npmjs.com/package/graphcool) 6 | 7 | ```sh 8 | # Install Graphcool CLI 9 | npm install -g graphcool 10 | 11 | # Create a new project with example schema 12 | graphcool init --schema json-entries.graphql 13 | ``` 14 | 15 | Replace the `__PROJECT_ID__` in `json-entries.js` with your endpoint. 16 | 17 | ### 2. Install dependencies 18 | 19 | ```sh 20 | yarn 21 | ``` 22 | 23 | Make sure your node version is at least 7.6: 24 | 25 | ```sh 26 | node -v 27 | ``` 28 | 29 | ### 3. Create some Json data 30 | 31 | Run the script to create some Json data: 32 | 33 | ```sh 34 | node json-entries.js 35 | ``` 36 | -------------------------------------------------------------------------------- /json-entries/json-entries.graphql: -------------------------------------------------------------------------------- 1 | type Entry { 2 | id: ID! @isUnique 3 | json: Json 4 | jsonList: [Json!] 5 | } 6 | -------------------------------------------------------------------------------- /json-entries/json-entries.js: -------------------------------------------------------------------------------- 1 | const { request } = require('graphql-request') 2 | 3 | const query = `mutation jsons($json: Json!, $jsonList: [Json!]!) { 4 | createEntry( 5 | json: $json 6 | jsonList: $jsonList 7 | ) { 8 | id 9 | json 10 | jsonList 11 | } 12 | }` 13 | 14 | const variables = { 15 | json: {a: 'a'}, 16 | jsonList: [{a: 'a'}] 17 | } 18 | 19 | request('https://api.graph.cool/simple/v1/__PROJECT_ID__', query, variables) 20 | .then(({ createEntry }) => console.log(createEntry)) 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphcool-scripts", 3 | "private": true, 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "bluebird": "^3.4.6", 7 | "graphcool-lib": "^0.0.3", 8 | "graphql-request": "^1.2.0", 9 | "isomorphic-fetch": "^2.2.1", 10 | "lodash": "^4.17.2", 11 | "lokka": "^1.7.0", 12 | "lokka-transport-http": "^1.6.1" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /touch-nodes/README.md: -------------------------------------------------------------------------------- 1 | # touch-nodes 2 | 3 | ### 1. Create GraphQL API with [`graphcool`](https://www.npmjs.com/package/graphcool) 4 | 5 | ```sh 6 | # Install Graphcool CLI 7 | npm install -g graphcool 8 | 9 | # Create a new project with example schema 10 | graphcool init --schema touch-nodes.graphql 11 | ``` 12 | 13 | Replace the `__PROJECT_ID__` and if needed the `__PERMANENT_AUTH_TOKEN__`. 14 | 15 | ### 2. Install dependencies 16 | 17 | ```sh 18 | yarn 19 | ``` 20 | 21 | Make sure your node version is at least 7.6.0: 22 | 23 | ```sh 24 | node -v 25 | ``` 26 | 27 | ### 3. Touch all nodes 28 | 29 | ```sh 30 | node touch-nodes.js 31 | ``` 32 | 33 | ### Notes 34 | 35 | * nodes are queried in *pages* 36 | * for each page of nodes, the according update mutations are generated and divided into equally sized *chunks* 37 | * each chunk of mutations is [*batched* into a single GraphQL document](https://www.graph.cool/docs/faq/graphql-combining-multiple-queries-and-mutations-cahzai2eur/) 38 | * each batch of mutations is executed *concurrently* with a certain concurrency factor 39 | 40 | Tweaking the sizes of a page, a chunk or the concurrency factor can lead to faster results. 41 | 42 | ```sh 43 | time -p node touch-nodes.js 44 | ``` 45 | 46 | For 3000 nodes, page size 1000, batch of 50 and concurrency factor 4: 47 | 48 | ```sh 49 | real 11.39 50 | user 0.56 51 | sys 0.09 52 | ``` 53 | 54 | For 3000 nodes, page size 500, batch of 25 and concurrency factor 8: 55 | 56 | ```sh 57 | real 15.73 58 | user 0.77 59 | sys 0.14 60 | ``` 61 | 62 | If single mutations result in a 502 or 504, then you should probably try a lower batch size or concurrency factor -------------------------------------------------------------------------------- /touch-nodes/touch-nodes.graphql: -------------------------------------------------------------------------------- 1 | type Post implements Node { 2 | id: ID! @isUnique 3 | title: String! 4 | dummy: String! @defaultValue(value: "dummy") 5 | createdAt: DateTime! 6 | updatedAt: DateTime! 7 | } -------------------------------------------------------------------------------- /touch-nodes/touch-nodes.js: -------------------------------------------------------------------------------- 1 | const Bluebird = require('bluebird') 2 | const _ = require('lodash') 3 | const { GraphQLClient } = require('graphql-request') 4 | 5 | const headers = { 6 | // if needed, inject a PAT 7 | // 'Authorization': 'Bearer __PERMANENT_AUTH_TOKEN__' 8 | } 9 | 10 | const client = new GraphQLClient('https://api.graph.cool/simple/v1/__PROJECT_ID__', { headers }) 11 | 12 | const countAll = () => { 13 | return client.request(`{ 14 | meta: _allPostsMeta { 15 | count 16 | } 17 | }`) 18 | } 19 | 20 | const queryBatch = (first, skip = 0) => { 21 | return client.request(` 22 | query getPosts { 23 | posts: allPosts(first: ${first}, skip: ${skip}) { 24 | id 25 | } 26 | } 27 | `) 28 | } 29 | 30 | const touchAll = async (count) => { 31 | console.log(`Updating ${count} posts:`) 32 | 33 | // because it's a simple mutation, we choose fairly high chunk and batch size. use lower ones for nested mutations! 34 | const BATCH_SIZE = 50 35 | const PAGE_SIZE = 1000 36 | const TOTAL = Math.floor(count / PAGE_SIZE) + 1 37 | 38 | let skip = 0 39 | let run = 0 40 | 41 | while(skip <= count) { 42 | console.log(`[${++run}/${TOTAL}] Fetch and update next page in chunks of ${BATCH_SIZE}...`) 43 | const posts = (await queryBatch(PAGE_SIZE, skip)).posts 44 | 45 | // first, generate every update mutation separately 46 | const mutations = _.chain(posts) 47 | .map(post => ( 48 | ` 49 | ${post.id}: updatePost(id: "${post.id}" dummy: "dummy") { 50 | id 51 | } 52 | ` 53 | )) 54 | .value() 55 | 56 | // create equally sized chunks, that are batched into one GraphQL document 57 | const batchedMutations = _.chain(_.chunk(mutations, BATCH_SIZE)) 58 | .map(chunk => 59 | ` 60 | mutation { 61 | ${chunk.join('\n')} 62 | } 63 | ` 64 | ) 65 | .value() 66 | 67 | // run each batch separately 68 | await Bluebird.map(batchedMutations, m => client.request(m), {concurrency: 4}) 69 | 70 | // skip finished nodes 71 | skip = skip + PAGE_SIZE 72 | } 73 | } 74 | 75 | 76 | const createPosts = async () => { 77 | const mutations = _.chain(_.range(1000)) 78 | .map(n => ( 79 | `mutation { 80 | post: createPost(title: "${n}") { 81 | id 82 | } 83 | }` 84 | )) 85 | .value() 86 | 87 | await Bluebird.map(mutations, m => client.request(m), {concurrency: 4}) 88 | } 89 | 90 | 91 | const main = async() => { 92 | // uncomment to create some test data 93 | // await createPosts() 94 | const count = (await countAll()).meta.count 95 | await touchAll(count) 96 | 97 | console.log('Done!') 98 | } 99 | 100 | main().catch((e) => console.error(e)) 101 | -------------------------------------------------------------------------------- /unique-import/README.md: -------------------------------------------------------------------------------- 1 | # unique-import 2 | 3 | Context and further explanations: https://www.graph.cool/forum/t/bulk-add-batch-add-insert/477/ 4 | 5 | ### 1. Create GraphQL API with [`graphcool`](https://www.npmjs.com/package/graphcool) 6 | 7 | ```sh 8 | # Install Graphcool CLI 9 | npm install -g graphcool 10 | 11 | # Create a new project with example schema 12 | graphcool init --schema unique-import.graphql 13 | ``` 14 | 15 | Replace the `__PROJECT_ID__` and if needed the `__PERMANENT_AUTH_TOKEN__`. 16 | 17 | ### 2. Install dependencies 18 | 19 | ```sh 20 | yarn 21 | ``` 22 | 23 | Make sure your node version is at least 7.6.0: 24 | 25 | ```sh 26 | node -v 27 | ``` 28 | 29 | ### 3. Import items with unique keys 30 | 31 | ```sh 32 | node unique-imports.js 33 | ``` 34 | -------------------------------------------------------------------------------- /unique-import/unique-import.graphql: -------------------------------------------------------------------------------- 1 | type Item { 2 | id: ID! 3 | key: String! @isUnique 4 | } -------------------------------------------------------------------------------- /unique-import/unique-import.js: -------------------------------------------------------------------------------- 1 | const Bluebird = require('bluebird') 2 | const _ = require('lodash') 3 | const { GraphQLClient } = require('graphql-request') 4 | 5 | const headers = { 6 | // if needed, inject a PAT 7 | // 'Authorization': 'Bearer __PERMANENT_AUTH_TOKEN__' 8 | } 9 | 10 | const client = new GraphQLClient('https://api.graph.cool/simple/v1/__PROJECT_ID__', { headers }) 11 | 12 | const generateUniqueKeys = (count, max) => { 13 | // use Set to make keys unique 14 | const uniqueKeys = new Set(_.range(count).map( 15 | r => { 16 | // need to use string interpolation because we need GraphQL String variables 17 | return `${Math.floor((Math.random() * max) + 1)}` 18 | } 19 | )) 20 | 21 | return [...uniqueKeys] 22 | } 23 | 24 | const queryExistingKeys = async(keys) => { 25 | const query = ` 26 | query existingItems($keys: [String!]!) { 27 | allItems(filter: { 28 | key_in: $keys 29 | }) { 30 | id 31 | key 32 | } 33 | } 34 | ` 35 | 36 | const variables = { keys } 37 | 38 | const response = await client.request(query, variables) 39 | return response.allItems.map(item => item.key) 40 | } 41 | 42 | const createItems = async(keys) => { 43 | const BATCH_SIZE = 50 44 | 45 | const mutations = _.chain(keys).map(key => { 46 | return ` 47 | k_${key}: createItem(key: "${key}") { 48 | id 49 | } 50 | ` 51 | }) 52 | .chunk(BATCH_SIZE) 53 | .map(chunk => ` 54 | mutation { 55 | ${chunk.join('\n')} 56 | } 57 | `) 58 | .value() 59 | 60 | await Bluebird.map(mutations, mutation => client.request(mutation), {concurrency: 8}) 61 | } 62 | 63 | const main = async() => { 64 | // get maximally 1000 unique keys between 1 and 10000 65 | const keys = generateUniqueKeys(1000, 10000) 66 | 67 | // query existing keys 68 | const existingKeys = await queryExistingKeys(keys) 69 | console.log(`${existingKeys.length} keys already exist!`) 70 | 71 | // filter out existing keys to obtain new keys 72 | const newKeys = keys.filter(key => existingKeys.indexOf(key) < 0) 73 | 74 | // create new items with new keys 75 | console.log(`Creating ${newKeys.length} new items...`) 76 | await createItems(newKeys) 77 | 78 | console.log('Done!') 79 | } 80 | 81 | main().catch((e) => console.error(e)) 82 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/node@^7.0.14": 6 | version "7.0.39" 7 | resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.39.tgz#8aced4196387038113f6f9aa4014ab4c51edab3c" 8 | 9 | babel-runtime@6.x.x: 10 | version "6.23.0" 11 | resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" 12 | dependencies: 13 | core-js "^2.4.0" 14 | regenerator-runtime "^0.10.0" 15 | 16 | bluebird@^3.4.6: 17 | version "3.5.0" 18 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 19 | 20 | core-js@^2.4.0: 21 | version "2.4.1" 22 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" 23 | 24 | encoding@^0.1.11: 25 | version "0.1.12" 26 | resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" 27 | dependencies: 28 | iconv-lite "~0.4.13" 29 | 30 | graphcool-lib@^0.0.3: 31 | version "0.0.3" 32 | resolved "https://registry.yarnpkg.com/graphcool-lib/-/graphcool-lib-0.0.3.tgz#c7277782d975a6dd428c217409f7d8a44be0cc0e" 33 | dependencies: 34 | "@types/node" "^7.0.14" 35 | graphql-request "^1.2.0" 36 | source-map-support "^0.4.15" 37 | 38 | graphql-request@^1.2.0: 39 | version "1.2.0" 40 | resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-1.2.0.tgz#9be0945b2399342f1d495be96939b2421b0823a2" 41 | dependencies: 42 | isomorphic-fetch "^2.2.1" 43 | 44 | iconv-lite@~0.4.13: 45 | version "0.4.15" 46 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" 47 | 48 | is-stream@^1.0.1: 49 | version "1.1.0" 50 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 51 | 52 | isomorphic-fetch@^2.2.1: 53 | version "2.2.1" 54 | resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" 55 | dependencies: 56 | node-fetch "^1.0.1" 57 | whatwg-fetch ">=0.10.0" 58 | 59 | lodash@^4.17.2: 60 | version "4.17.4" 61 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 62 | 63 | lokka-transport-http@^1.6.1: 64 | version "1.6.1" 65 | resolved "https://registry.yarnpkg.com/lokka-transport-http/-/lokka-transport-http-1.6.1.tgz#0dfbc2dc9e825f6e5821830f3f3f7f3f83a4ad65" 66 | dependencies: 67 | babel-runtime "6.x.x" 68 | node-fetch "^1.5.2" 69 | whatwg-fetch "^1.0.0" 70 | 71 | lokka@^1.7.0: 72 | version "1.7.0" 73 | resolved "https://registry.yarnpkg.com/lokka/-/lokka-1.7.0.tgz#ab2e8334612d2afd359aa89047547bd7de21046c" 74 | dependencies: 75 | babel-runtime "6.x.x" 76 | uuid "2.x.x" 77 | 78 | node-fetch@^1.0.1, node-fetch@^1.5.2: 79 | version "1.6.3" 80 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" 81 | dependencies: 82 | encoding "^0.1.11" 83 | is-stream "^1.0.1" 84 | 85 | regenerator-runtime@^0.10.0: 86 | version "0.10.3" 87 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" 88 | 89 | source-map-support@^0.4.15: 90 | version "0.4.15" 91 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" 92 | dependencies: 93 | source-map "^0.5.6" 94 | 95 | source-map@^0.5.6: 96 | version "0.5.6" 97 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" 98 | 99 | uuid@2.x.x: 100 | version "2.0.3" 101 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" 102 | 103 | whatwg-fetch@>=0.10.0, whatwg-fetch@^1.0.0: 104 | version "1.1.1" 105 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-1.1.1.tgz#ac3c9d39f320c6dce5339969d054ef43dd333319" 106 | --------------------------------------------------------------------------------