├── .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 |
9 |
10 |
11 |
12 |
13 |
14 | ## Help & Community [](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 | 
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 |
--------------------------------------------------------------------------------