├── .babelrc ├── .env.default ├── .eslintrc.json ├── .gitignore ├── .snyk ├── LICENSE.md ├── README.md ├── doc ├── CHANGELOG.md ├── README.md └── ROADMAP.md ├── knexfile.js ├── package.json ├── scripts ├── populate.js ├── reset.js └── utilities │ ├── apollo.js │ ├── cards.js │ ├── colors.js │ ├── index.js │ ├── languages.js │ ├── sets.js │ └── types.js ├── setup.js ├── src ├── config │ ├── bookshelf.config.js │ ├── graphql.config.js │ └── server.config.js ├── models │ ├── index.js │ ├── lists │ │ ├── abilityTypeCards.js │ │ ├── abilityTypes.js │ │ ├── artistCards.js │ │ ├── blockSets.js │ │ ├── cardColors.js │ │ ├── categories.js │ │ ├── categoryCards.js │ │ ├── colors.js │ │ ├── formatSets.js │ │ ├── icons.js │ │ ├── images.js │ │ ├── index.js │ │ ├── keywordCards.js │ │ ├── keywords.js │ │ ├── legalities.js │ │ ├── legalityCards.js │ │ ├── nameCards.js │ │ ├── names.js │ │ ├── printings.js │ │ ├── rulingCards.js │ │ ├── rulings.js │ │ ├── sides.js │ │ ├── subtypes.js │ │ ├── supertypes.js │ │ ├── types.js │ │ └── variations.js │ └── tables │ │ ├── abilityType.js │ │ ├── artist.js │ │ ├── block.js │ │ ├── booster.js │ │ ├── card.js │ │ ├── category.js │ │ ├── color.js │ │ ├── colorIdentity.js │ │ ├── format.js │ │ ├── icon.js │ │ ├── image.js │ │ ├── index.js │ │ ├── keyword.js │ │ ├── language.js │ │ ├── languageCode.js │ │ ├── layout.js │ │ ├── legality.js │ │ ├── name.js │ │ ├── printing.js │ │ ├── rarity.js │ │ ├── ruling.js │ │ ├── set.js │ │ ├── setType.js │ │ ├── subtype.js │ │ ├── supertype.js │ │ └── type.js ├── routes │ ├── example │ │ └── example.js │ ├── index.js │ ├── login │ │ └── login.js │ ├── ping │ │ └── ping.js │ └── signup │ │ └── signup.js ├── schema.js ├── server.js └── types │ ├── abilityType.js │ ├── artist.js │ ├── block.js │ ├── booster.js │ ├── card.js │ ├── category.js │ ├── color.js │ ├── colorIdentity.js │ ├── format.js │ ├── icon.js │ ├── image.js │ ├── index.js │ ├── keyword.js │ ├── language.js │ ├── languageCode.js │ ├── layout.js │ ├── legality.js │ ├── name.js │ ├── printing.js │ ├── rarity.js │ ├── ruling.js │ ├── set.js │ ├── setType.js │ ├── subtype.js │ ├── supertype.js │ ├── type.js │ └── utilities │ ├── create.js │ ├── destroy.js │ ├── index.js │ ├── order.js │ ├── read.js │ ├── sort.js │ └── update.js ├── test └── karma.conf.js ├── wallaby.config.js ├── webpack.config.babel.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-es2015-shorthand-properties", 4 | "transform-decorators-legacy", 5 | "transform-object-rest-spread", 6 | "transform-class-properties", 7 | "import-glob" 8 | ], 9 | "presets": [ 10 | "es2015", 11 | [ 12 | "env", 13 | { 14 | "targets": { 15 | "node": "current" 16 | }, 17 | "modules": false, 18 | "loose": true, 19 | "useBuiltIns": true 20 | } 21 | ] 22 | ], 23 | "sourceMaps": "both" 24 | } 25 | -------------------------------------------------------------------------------- /.env.default: -------------------------------------------------------------------------------- 1 | JWT_PUBLIC_KEY="rsa_public_key" 2 | JWT_PRIVATE_KEY="rsa_private_key" 3 | DB_HOST="database_host" 4 | DB_USERNAME="database_username" 5 | DB_PASSWORD="database_password" 6 | DB_NAME="database_name" 7 | HTTP="1337" 8 | HTTPS="8080" 9 | LOGLEVEL="info" 10 | LOGGLY_TOKEN="token" 11 | LOGGLY_SUBDOMAIN="subdomain" 12 | OPBEAT_APP_ID="app id" 13 | OPBEAT_ORGANIZATION_ID="org id" 14 | OPBEAT_SECRET_TOKEN="token" 15 | DD_API_KEY="datadog_api_key" 16 | NODE_ENV="development" 17 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "babel-eslint", 4 | "env": { 5 | "node": true 6 | }, 7 | "ecmaFeatures": { 8 | "arrowFunctions": true, 9 | "blockBindings": true, 10 | "classes": true, 11 | "defaultParams": true, 12 | "destructuring": true, 13 | "forOf": true, 14 | "generators": false, 15 | "modules": true, 16 | "objectLiteralComputedProperties": true, 17 | "objectLiteralDuplicateProperties": false, 18 | "objectLiteralShorthandMethods": true, 19 | "objectLiteralShorthandProperties": true, 20 | "spread": true, 21 | "superInFunctions": true, 22 | "templateStrings": true, 23 | "jsx": false 24 | }, 25 | "rules": { 26 | "strict": [2, "never"], 27 | 28 | "no-var": 2, 29 | "prefer-const": 0, 30 | 31 | "no-shadow": 2, 32 | "no-shadow-restricted-names": 2, 33 | "no-unused-vars": [2, { 34 | "vars": "local", 35 | "args": "none" 36 | }], 37 | "no-use-before-define": 0, 38 | 39 | "comma-dangle": [2, "never"], 40 | "no-cond-assign": [2, "always"], 41 | "no-debugger": 1, 42 | "no-alert": 1, 43 | "no-constant-condition": 1, 44 | "no-dupe-keys": 2, 45 | "no-duplicate-case": 2, 46 | "no-empty": 2, 47 | "no-ex-assign": 2, 48 | "no-extra-boolean-cast": 0, 49 | "no-extra-semi": 2, 50 | "no-func-assign": 2, 51 | "no-inner-declarations": 2, 52 | "no-invalid-regexp": 2, 53 | "no-irregular-whitespace": 2, 54 | "no-obj-calls": 2, 55 | "no-sparse-arrays": 2, 56 | "no-unreachable": 2, 57 | "use-isnan": 2, 58 | "block-scoped-var": 0, 59 | 60 | "consistent-return": 0, 61 | "curly": [2, "multi-line"], 62 | "default-case": 2, 63 | "dot-notation": [2, { 64 | "allowKeywords": true 65 | }], 66 | "eqeqeq": 2, 67 | "guard-for-in": 0, 68 | "no-caller": 2, 69 | "no-else-return": 2, 70 | "no-eq-null": 2, 71 | "no-eval": 2, 72 | "no-extend-native": 2, 73 | "no-extra-bind": 2, 74 | "no-fallthrough": 2, 75 | "no-floating-decimal": 2, 76 | "no-implied-eval": 2, 77 | "no-lone-blocks": 2, 78 | "no-loop-func": 2, 79 | "no-multi-str": 2, 80 | "no-native-reassign": 2, 81 | "no-new": 2, 82 | "no-new-func": 2, 83 | "no-new-wrappers": 2, 84 | "no-octal": 2, 85 | "no-octal-escape": 2, 86 | "no-param-reassign": 0, 87 | "no-proto": 2, 88 | "no-redeclare": 2, 89 | "no-script-url": 2, 90 | "no-self-compare": 2, 91 | "no-sequences": 2, 92 | "no-throw-literal": 2, 93 | "no-with": 2, 94 | "radix": 2, 95 | "vars-on-top": 2, 96 | "wrap-iife": [2, "any"], 97 | "yoda": 2, 98 | 99 | "indent": [2, 2], 100 | "brace-style": [2, 101 | "1tbs", { 102 | "allowSingleLine": true 103 | }], 104 | "quotes": [ 105 | 2, "backtick", "avoid-escape" 106 | ], 107 | "camelcase": [2, { 108 | "properties": "never" 109 | }], 110 | "comma-spacing": [2, { 111 | "before": false, 112 | "after": true 113 | }], 114 | "comma-style": [2, "last"], 115 | "eol-last": 2, 116 | "func-names": 0, 117 | "new-cap": [2, { 118 | "newIsCap": true 119 | }], 120 | "no-multiple-empty-lines": [2, { 121 | "max": 2 122 | }], 123 | "no-nested-ternary": 2, 124 | "no-new-object": 2, 125 | "no-spaced-func": 2, 126 | "no-trailing-spaces": 2, 127 | "no-extra-parens": [2, "functions"], 128 | "no-underscore-dangle": 0, 129 | "one-var": [2, "never"], 130 | "padded-blocks": [2, "never"], 131 | "semi": ["error", "never"], 132 | "semi-spacing": [2, { 133 | "before": false, 134 | "after": true 135 | }], 136 | "keyword-spacing": [2, { 137 | "before": true, 138 | "after": true 139 | }], 140 | "space-before-blocks": 2, 141 | "space-before-function-paren": [2, "never"], 142 | "space-infix-ops": 2, 143 | "spaced-comment": [0, "always", { 144 | "exceptions": ["*"], 145 | "markers": ["*"] 146 | }] 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_STORE 3 | npm-debug.log* 4 | .env 5 | /dist 6 | /build 7 | /typings 8 | /.awcache 9 | /.ssh 10 | /electron.js* 11 | /release 12 | /test/coverage 13 | /src/scribe.sqlite 14 | /src/images 15 | -------------------------------------------------------------------------------- /.snyk: -------------------------------------------------------------------------------- 1 | # Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. 2 | version: v1.7.1 3 | ignore: {} 4 | # patches apply the minimum changes required to fix a vulnerability 5 | patch: 6 | 'npm:debug:20170905': 7 | - karma > socket.io > socket.io-adapter > debug: 8 | patched: '2017-10-12T13:05:35.644Z' 9 | - karma > socket.io > engine.io > debug: 10 | patched: '2017-10-12T13:05:35.644Z' 11 | - karma > socket.io > socket.io-client > debug: 12 | patched: '2017-10-12T13:05:35.644Z' 13 | - karma > socket.io > socket.io-client > engine.io-client > debug: 14 | patched: '2017-10-12T13:05:35.644Z' 15 | - karma > socket.io > socket.io-client > socket.io-parser > debug: 16 | patched: '2017-10-12T13:05:35.644Z' 17 | - karma > socket.io > socket.io-parser > debug: 18 | patched: '2017-10-12T13:05:35.644Z' 19 | - hapijs-status-monitor > socket.io > socket.io-adapter > socket.io-parser > debug: 20 | patched: '2017-10-12T13:05:35.644Z' 21 | - karma > socket.io > socket.io-adapter > socket.io-parser > debug: 22 | patched: '2017-10-12T13:05:35.644Z' 23 | - karma > socket.io > debug: 24 | patched: '2017-10-12T13:05:35.644Z' 25 | 'npm:ms:20170412': 26 | - karma > socket.io > socket.io-adapter > socket.io-parser > debug > ms: 27 | patched: '2017-10-12T13:05:35.644Z' 28 | - karma > socket.io > debug > ms: 29 | patched: '2017-10-12T13:05:35.644Z' 30 | - karma > socket.io > engine.io > debug > ms: 31 | patched: '2017-10-12T13:05:35.644Z' 32 | - karma > socket.io > socket.io-client > debug > ms: 33 | patched: '2017-10-12T13:05:35.644Z' 34 | - karma > socket.io > socket.io-client > engine.io-client > debug > ms: 35 | patched: '2017-10-12T13:05:35.644Z' 36 | - karma > socket.io > socket.io-client > socket.io-parser > debug > ms: 37 | patched: '2017-10-12T13:05:35.644Z' 38 | - karma > socket.io > socket.io-parser > debug > ms: 39 | patched: '2017-10-12T13:05:35.644Z' 40 | - hapijs-status-monitor > socket.io > socket.io-adapter > socket.io-parser > debug > ms: 41 | patched: '2017-10-12T13:05:35.644Z' 42 | - karma > socket.io > socket.io-adapter > debug > ms: 43 | patched: '2017-10-12T13:05:35.644Z' 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017 Drake Costa drake@saeris.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scribe 2 | *A GraphQL Magic: The Gathering API Server* 3 | 4 | ## Table of Contents 5 | 6 | - [Getting Started](#start) 7 | - [Installation](#install) 8 | - [Running the Server Locally](#run) 9 | - [Running the Server in Production](#production) 10 | - [Resetting the Database](#reset) 11 | - [License Information](#license) 12 | - [Prior Art](#priorart) 13 | - [Further Reading](doc/README.md) 14 | 15 | ## Getting Started 16 | 17 | > *[Back to Top](#contents)* 18 | 19 | ## Installation 20 | 21 | Before you start, make sure you have a working [NodeJS](http://nodejs.org/) environment, with NPM 3. Preferably use [Yarn](https://yarnpkg.com/) instead of NPM for installation of packages to ensure that you'll use exactly the same dependencies as the project. 22 | 23 | From the project folder, execute the following command: 24 | 25 | ```shell 26 | npm install 27 | ``` 28 | 29 | Or if you are using Yarn, execute this command instead: 30 | 31 | ```shell 32 | yarn 33 | ``` 34 | 35 | Once installation of project dependencies completes, run the following command to set up your local development environment: 36 | 37 | ```shell 38 | npm run setup 39 | ``` 40 | 41 | First this will create a default `.env` file in which you can define various environment variables such as your MySQL connection details, should you like to use it instead of SQLite3. `.env` is used to store sensitive information you do not want to commit. 42 | 43 | Second, it will create a new database file under `src/scribe.sqlite` to serve as your default local development database. It will then run a set of Knex.js migrations to set up the default database schema. 44 | 45 | Your development environment is now ready to go! 46 | 47 | > *[Back to Top](#contents)* 48 | 49 | ## Running the Server Locally 50 | 51 | To start the server, simply run the following command: 52 | 53 | ```shell 54 | npm start 55 | ``` 56 | 57 | The server should now be listening on port `1337`. To access GraphiQL and begin exploring the API documentation, navigate to [http://127.0.0.1:1337/graphiql](http://127.0.0.1:1337/graphiql) in your browser of choice. 58 | 59 | Next, you can begin to populate your newly created database by running the following in a second terminal window: 60 | 61 | ```shell 62 | npm run populate 63 | ``` 64 | 65 | This will populate the database with data from the [Magic: The Gathering API](https://docs.magicthegathering.io/) and download all card images to `src/images`. 66 | 67 | > **Please note:** `populate` may take many hours to fully run! You can cancel the script at any time during execution. It is recommended that you at least allow it to run until some cards from the first set are added to the database in order to have a decent amount of seed data to play with. Execution may run faster using MySQL instead of SQlite3. Please refer to [Running the Server in Production](#production) for more information. 68 | 69 | > *[Back to Top](#contents)* 70 | 71 | ## Running the Server in Production 72 | 73 | If you would like to run the server in "production" mode, you will first need to install and setup [MySQL](https://dev.mysql.com/downloads/mysql/) on your local machine. Once complete, set your connection details in `.env`. Scribe uses this file to configure the database connection, otherwise it will use defaults defined in `src/config/server.config.js`. 74 | 75 | To reset your production database schema, run: 76 | 77 | ```shell 78 | npm run resetdb:prod 79 | ``` 80 | 81 | > **Warning:** this will first attempt to **drop** any database named 'scribe'. 82 | 83 | When completed, you can then run the server in production using: 84 | 85 | ```shell 86 | npm run start:prod 87 | ``` 88 | 89 | To switch back to development, simply run: 90 | 91 | ```shell 92 | npm run start:dev 93 | ``` 94 | 95 | > *[Back to Top](#contents)* 96 | 97 | ## Resetting the Database 98 | 99 | To delete all the data in the database and start from scratch, run one of the following commands: 100 | 101 | **Development (Sqlite3):** 102 | ```shell 103 | npm run resetdb 104 | ``` 105 | 106 | **Production (MySQL):** 107 | ```shell 108 | npm run resetdb:prod 109 | ``` 110 | 111 | This is useful when making changes to the database schema, the populate script, or simply when you need to clear out existing data. 112 | 113 | > *[Back to Top](#contents)* 114 | 115 | ## License Information 116 | 117 | This application uses images and data that are copyright of Wizards of the Coast (http://magic.wizards.com/en) 118 | 119 | Scribe is made available under the MIT License (https://opensource.org/licenses/mit-license.html) 120 | 121 | Attribution is greatly appreciated! Please feel free to fork the project and submit pull requests. 122 | 123 | > *[Back to Top](#contents)* 124 | 125 | ## Prior Art 126 | 127 | Scribe would not be possible without the fantastic work of 128 | Andrew Backes @adback03 on his [Magic: The Gathering API](https://magicthegathering.io/) project. 129 | 130 | > *[Back to Top](#contents)* 131 | -------------------------------------------------------------------------------- /doc/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Project Changelog 2 | 3 | > *[Return to Directory](README.md)* 4 | 5 | ## v0.1.1 6 | 7 | - Fixed the outstanding errors with SQLite3 migrations. Because SQLite3 does not supposrt adding foreign keys after a table is created, foreign key creation is now conditionally added based on the environment. 8 | - Another issue with migrations was fixed by moving all table definitions back to a subfolder, because Knex's migrations API doesn't seem to allow you to exclude files. 9 | - Added some documentation, including a project Roadmap and a Changelog. 10 | - Added missing dependency Winston-Loggly-Bulk. 11 | - Removed leftover references to previous express server implementation in routes. 12 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Scribe Documentation 2 | 3 | ## Table of Contents 4 | 5 | - [Project Roadmap](ROADMAP.md) 6 | - [Changelog](CHANGELOG.md) 7 | -------------------------------------------------------------------------------- /doc/ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Project Roadmap 2 | 3 | > *[Return to Directory](README.md)* 4 | 5 | ## v0.2.0 6 | 7 | - [ ] ~~Refactor Types/Models to condense data schema into one place per table.~~ 8 | - [ ] Write basic project documentation (setup, getting started, etc) ie: [README](../README.md) 9 | - [ ] Wire-up Hapi Routes 10 | - [X] Troubleshoot remaining issues with SQLite Migrations / Knex schema 11 | - [ ] Add remaining Bookshelf Model Relations 12 | - [X] Add pagination query arguments for lists 13 | 14 | ## v0.3.0 15 | 16 | - [X] Add remaining mutations to enable populating the database via the API 17 | - [ ] Add private tables / type definitions 18 | - [ ] Tables: Account, Collection, Binders, Decks, OwnedCards, misc 19 | - [ ] Type definitions/queries/mutations for above 20 | 21 | ## v0.4.0 22 | 23 | - [ ] Setup login/signup REST API 24 | - [ ] Add authentication layer to GraphQL API for private Tables 25 | - [ ] Add rate-limiting to public GraphQL API 26 | 27 | ## v0.5.0 28 | 29 | - [ ] Add application state history table / frontend utility APIs 30 | - [ ] Add trading API / services 31 | - [ ] Create service to grab pricing data from public API sources 32 | - [ ] Add GraphQL types/queries to expose pricing data 33 | - [ ] Add tables / type definitions for Trading platform 34 | 35 | ## v0.6.0 36 | 37 | - [ ] Refactor GraphQL resolvers to use batch SQL querying (speculative) 38 | - [ ] ...? 39 | -------------------------------------------------------------------------------- /knexfile.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | const config = require('./src/config/server.config').default 3 | 4 | module.exports = config.db 5 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scribe", 3 | "version": "0.1.1", 4 | "description": "A GraphQL Magic: The Gathering API Server", 5 | "main": "src/app.js", 6 | "productName": "Scribe", 7 | "scripts": { 8 | "setup": "node setup.js && npm run resetdb", 9 | "lint": "eslint .", 10 | "test": "", 11 | "clean": "npm cache clean && del-cli node_modules", 12 | "clean:dist": "del-cli dist", 13 | "start": "nodemon --watch src src/server.js --exec babel-node --color", 14 | "start:dev": "cross-env NODE_ENV=development npm run start", 15 | "start:prod": "cross-env NODE_ENV=production npm run start", 16 | "build": "npm run build:dev", 17 | "prebuild:dev": "npm run clean:dist", 18 | "build:dev": "cross-env NODE_ENV=development npm run webpack -- --progress --profile", 19 | "prebuild:prod": "npm run clean:dist", 20 | "build:prod": "cross-env NODE_ENV=production npm run webpack -- --progress --profile", 21 | "serve": "nodemon --watch dist dist/server.bundle.js --exec babel-node -- color --inspect=1338", 22 | "migrate:latest": "./node_modules/.bin/knex migrate:latest", 23 | "migrate:latest:dev": "cross-env NODE_ENV=development npm run migrate:latest", 24 | "migrate:latest:prod": "cross-env NODE_ENV=production npm run migrate:latest", 25 | "resetdb": "del-cli src/scribe.sqlite && touch src/scribe.sqlite && npm run migrate:latest", 26 | "resetdb:dev": "cross-env NODE_ENV=development npm run resetdb", 27 | "resetdb:prod": "cross-env NODE_ENV=production && babel-node scripts/reset.js && npm run migrate:latest:prod", 28 | "populate": "nodemon --watch scripts scripts/populate.js --exec babel-node --color --inspect=1338", 29 | "webpack": "./node_modules/.bin/webpack", 30 | "snyk-protect": "snyk protect", 31 | "prepublish": "npm run snyk-protect" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "git+ssh://git@github.com:Saeris/Scribe.git" 36 | }, 37 | "license": "MIT", 38 | "author": "Drake Costa (http://saeris.github.io/)", 39 | "engines": { 40 | "node": "6.9.1" 41 | }, 42 | "dependencies": { 43 | "@easy-webpack/config-babel": "^4.0.2", 44 | "@easy-webpack/config-env-development": "^2.1.4", 45 | "@easy-webpack/core": "^2.0.0", 46 | "apollo-client": "^1.2.0", 47 | "babel-cli": "^6.18.0", 48 | "babel-eslint": "^7.1.1", 49 | "babel-plugin-import-glob": "^1.0.1", 50 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 51 | "babel-preset-env": "^1.4.0", 52 | "babel-preset-es2015": "^6.18.0", 53 | "babel-preset-stage-2": "^6.18.0", 54 | "body-parser": "^1.15.2", 55 | "bookshelf": "^0.10.2", 56 | "bookshelf-modelbase": "^2.10.2", 57 | "chalk": "^1.1.3", 58 | "cors": "^2.8.3", 59 | "cross-env": "^4.0.0", 60 | "dataloader": "^1.3.0", 61 | "del-cli": "^0.2.1", 62 | "dotenv": "^4.0.0", 63 | "errorhandler": "^1.5.0", 64 | "eslint": "^3.19.0", 65 | "glob": "^7.1.1", 66 | "good": "^7.1.0", 67 | "good-winston": "^3.1.0", 68 | "graphql": "^0.9.3", 69 | "graphql-iso-date": "^3.1.1", 70 | "graphql-server-hapi": "^0.7.1", 71 | "graphql-tag": "^2.0.0", 72 | "hapi": "^16.1.1", 73 | "hapi-auth-jwt2": "^7.2.3", 74 | "hapi-boom-decorators": "^2.2.0", 75 | "hapijs-status-monitor": "^0.6.0", 76 | "ignore-loader": "^0.1.2", 77 | "isomorphic-fetch": "^2.2.1", 78 | "jasmine": "^2.5.2", 79 | "jasmine-core": "^2.5.2", 80 | "jsonwebtoken": "^7.1.9", 81 | "karma": "^1.6.0", 82 | "karma-jasmine": "^1.0.2", 83 | "karma-mocha-reporter": "^2.2.1", 84 | "knex": "^0.13.0", 85 | "minimist": "^1.2.0", 86 | "mkdirp": "^0.5.1", 87 | "moment": "^2.18.1", 88 | "morgan": "^1.7.0", 89 | "mysql": "^2.12.0", 90 | "nodemon": "^1.11.0", 91 | "passport": "^0.3.2", 92 | "passport-http-bearer": "^1.0.1", 93 | "passport-local": "^1.0.0", 94 | "passport-oauth2": "^1.1.2", 95 | "present": "^1.0.0", 96 | "source-map-support": "^0.4.15", 97 | "sqlite3": "^3.1.8", 98 | "test-runner-config": "^0.5.0", 99 | "webpack": "^2.5.1", 100 | "winston": "^2.3.0", 101 | "winston-loggly-bulk": "^2.0.0", 102 | "snyk": "^1.42.6" 103 | }, 104 | "snyk": true 105 | } 106 | -------------------------------------------------------------------------------- /scripts/populate.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk' 2 | import present from 'present' 3 | import moment from 'moment' 4 | import { 5 | insertTypes, fetchTypes, 6 | insertColors, 7 | insertSets, fetchSets, 8 | insertLanguages, 9 | insertCards, fetchCards 10 | } from './utilities' 11 | 12 | const { log, error } = console 13 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 14 | 15 | async function populate() { 16 | try { 17 | const start = present() 18 | const prefix = `${chalk.green(`[populate]: `)}` 19 | log(`${prefix}Begin populating database...`) 20 | await insertTypes(await fetchTypes()) 21 | log(`${prefix}Successfully added type data!`) 22 | await insertColors() 23 | log(`${prefix}Successfully added set data!`) 24 | await insertLanguages() 25 | log(`${prefix}Successfully added color data!`) 26 | const sets = await insertSets(await fetchSets()) 27 | log(`${prefix}Successfully added language data!`) 28 | for (let set of sets) { 29 | await insertCards(await fetchCards(set.code), set) 30 | log(`${prefix}Successfully added cards for set ${set.code}`) 31 | } 32 | const end = present() 33 | log(`${prefix}Finished populating database! (${duration(end - start)})`) 34 | } catch (err) { 35 | error(err) 36 | } 37 | } 38 | 39 | populate() 40 | -------------------------------------------------------------------------------- /scripts/reset.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv' 2 | import knex from 'knex' 3 | 4 | dotenv.config() 5 | 6 | // connect without database selected 7 | const db = knex({ 8 | client: `mysql`, 9 | connection: { 10 | host: process.env.DB_HOST || `127.0.0.1`, 11 | user: process.env.DB_USERNAME || `root`, 12 | password: process.env.DB_PASSWORD || `password`, 13 | charset: `utf8` 14 | } 15 | }) 16 | 17 | async function resetdb() { 18 | await db.raw(`DROP DATABASE IF EXISTS scribe;`).then(res => res) 19 | await db.raw(`CREATE DATABASE IF NOT EXISTS scribe;`).then(res => res) 20 | db.destroy() 21 | } 22 | 23 | resetdb() 24 | -------------------------------------------------------------------------------- /scripts/utilities/apollo.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import ApolloClient, { createBatchingNetworkInterface } from 'apollo-client' 3 | 4 | const client = new ApolloClient({ 5 | networkInterface: createBatchingNetworkInterface({ 6 | uri: `http://localhost:1337/api`, 7 | batchInterval: 10 8 | }), 9 | queryDeduplication: true 10 | }) 11 | 12 | export default client 13 | -------------------------------------------------------------------------------- /scripts/utilities/cards.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import fs from 'fs' 3 | import mkdirp from 'mkdirp' 4 | import client from './apollo' 5 | import gql from 'graphql-tag' 6 | import chalk from 'chalk' 7 | import present from 'present' 8 | import moment from 'moment' 9 | import minimist from 'minimist' 10 | import { getSupertype, getType, getSubtype } from './types' 11 | import { getColor, getColorIdentity } from './colors' 12 | import { getLanguageCode } from './languages' 13 | 14 | const BaseUrl = `https://api.magicthegathering.io/v1` 15 | const { info, log, error } = console 16 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 17 | 18 | const updateCard = async input => await client 19 | .mutate({ 20 | mutation: gql`mutation updateCard($input: CardInput) { 21 | updateCard(input: $input) { 22 | id 23 | } 24 | }`, 25 | variables: { input } 26 | }) 27 | .then(res => res.data.updateCard.id) 28 | .catch(err => log(`Failed to update Card.`, input, err)) 29 | 30 | const updatePrinting = async input => await client 31 | .mutate({ 32 | mutation: gql`mutation updatePrinting($input: PrintingInput) { 33 | updatePrinting(input: $input) { 34 | id 35 | } 36 | }`, 37 | variables: { input } 38 | }) 39 | .then(res => res.data.updatePrinting.id) 40 | .catch(err => log(`Failed to update Printing.`, input, err)) 41 | 42 | const updateName = async input => await client 43 | .mutate({ 44 | mutation: gql`mutation updateName($input: NameInput) { 45 | updateName(input: $input) { 46 | id 47 | } 48 | }`, 49 | variables: { input: input } 50 | }) 51 | .then(res => res.data.updateName.id) 52 | .catch(err => log(`Failed to update Name.`, input, err)) 53 | 54 | const fetchImage = async (url, set, num, language) => { 55 | if (!!!minimist(process.argv.slice(2)).getImages) return url 56 | 57 | const dir = `./src/images/sets/${set}` 58 | const image = `${dir}/${set}_${num}_${language}.jpg` 59 | 60 | if (fs.existsSync(image)) return image 61 | if (!fs.existsSync(dir)) mkdirp.sync(dir) 62 | 63 | await fetch(url).then(resp => resp.body.pipe(fs.createWriteStream(image))) 64 | 65 | return image 66 | } 67 | 68 | const updateImage = async input => await client 69 | .mutate({ 70 | mutation: gql`mutation updateImage($input: ImageInput) { 71 | updateImage(input: $input) { 72 | id 73 | } 74 | }`, 75 | variables: { input } 76 | }) 77 | .then(res => res.data.updateImage.id) 78 | .catch(err => log(`Failed to update Image.`, input, err)) 79 | 80 | const updateArtist = async input => await client 81 | .mutate({ 82 | mutation: gql`mutation updateArtist($input: ArtistInput) { 83 | updateArtist(input: $input) { 84 | id 85 | } 86 | }`, 87 | variables: { input } 88 | }) 89 | .then(res => res.data.updateArtist.id) 90 | .catch(err => log(`Failed to update Artist.`, input, err)) 91 | 92 | const updateLayout = async input => await client 93 | .mutate({ 94 | mutation: gql`mutation updateLayout($input: LayoutInput) { 95 | updateLayout(input: $input) { 96 | id 97 | } 98 | }`, 99 | variables: { input } 100 | }) 101 | .then(res => res.data.updateLayout.id) 102 | .catch(err => log(`Failed to update Layout.`, input, err)) 103 | 104 | const updateRarity = async input => await client 105 | .mutate({ 106 | mutation: gql`mutation updateRarity($input: RarityInput) { 107 | updateRarity(input: $input) { 108 | id 109 | } 110 | }`, 111 | variables: { input } 112 | }) 113 | .then(res => res.data.updateRarity.id) 114 | .catch(err => log(`Failed to update Rarity.`, input, err)) 115 | 116 | export { updateCard, updateName, updateImage, updateArtist, updateLayout, updateRarity } 117 | 118 | export async function fetchCards(setCode) { 119 | const start = present() 120 | const prefix = `${chalk.cyan(`[fetchCards]: `)}` 121 | try { 122 | let page = 1 123 | let remaining 124 | let done = true 125 | let cards = [] 126 | log(`${prefix}Fetching card data for set ${chalk.green(setCode)}...`) 127 | do { 128 | let response = await fetch(`${BaseUrl}/cards?set=${setCode}&page=${page}`).then(resp => resp) 129 | let data = await response.json() 130 | cards.push(...data.cards) 131 | let total = response.headers.get(`total-count`) 132 | remaining = total - (page * 100) 133 | info(`${prefix}Retrieved page ${page}: ${cards.length} of ${total} cards.`) 134 | remaining <= 0 ? done = false : page++ 135 | } while (done) 136 | const end = present() 137 | log(`${prefix}Finished fetching cards for set ${chalk.green(setCode)}! (${duration(end - start)})`) 138 | return cards 139 | } catch (err) { 140 | const end = present() 141 | error(`${prefix}Failed to fetch all cards. (${duration(end - start)})`, err) 142 | } 143 | } 144 | 145 | export async function insertCards(cards, set) { 146 | const start = present() 147 | const prefix = `${chalk.magenta(`[insertCards]: `)}` 148 | log(`${prefix}Adding card data for set ${chalk.green(set.code)}`) 149 | try { 150 | let i = 1 151 | for (let card of await cards) { 152 | info(`${prefix}Adding card ${chalk.green(card.name)}`) 153 | const number = (!!card.number && card.number !== 0) ? card.number : i++ 154 | 155 | let names = [] 156 | let srcImages = [] 157 | 158 | if (!!card.multiverseid) { 159 | names.push(await updateName({ name: card.name, language: 1 })) 160 | srcImages.push({ url: card.imageUrl, multiverseid: card.multiverseid, code: `en-US`, codeID: 1 }) 161 | } 162 | if (!!card.foreignNames) { 163 | for (let name of card.foreignNames) { 164 | if (!!name.multiverseid) { 165 | const languageCode = await getLanguageCode([`${name.language}`]) 166 | log(`Adding name: ${name.name}, language: ${name.language}, code: ${languageCode.code}`) 167 | names.push(await updateName({ name: name.name, language: languageCode.id })) 168 | srcImages.push({ url: name.imageUrl, multiverseid: name.multiverseid, code: languageCode.code, codeID: languageCode.id }) 169 | } 170 | } 171 | } 172 | 173 | let images = [] 174 | for (let image of srcImages) { 175 | images.push(await updateImage({ 176 | url: await fetchImage(image.url, set.code, number, image.code), 177 | multiverseid: image.multiverseid, 178 | language: image.codeID 179 | })) 180 | } 181 | 182 | let colorIdentity = `` 183 | if (!!card.colorIdentity && !!card.colors) { 184 | for (let identity of card.colors) colorIdentity = `${colorIdentity}/${identity}` 185 | } 186 | 187 | const cardID = await updateCard({ 188 | name: card.name, 189 | names: names, 190 | border: !!card.border ? card.border : null, 191 | layout: await updateLayout({ name:card.layout }), 192 | watermark: null, 193 | manaCost: !!card.manaCost ? card.manaCost : null, 194 | cmc: !!card.cmc ? card.cmc : 0, 195 | colors: !!card.colorIdentity ? await getColor(card.colorIdentity.map(color => `{${color}}`)) : null, 196 | colorIdentity: colorIdentity !== `` ? await getColorIdentity([colorIdentity.substring(1)]) : 6, 197 | typeLine: card.type, 198 | supertypes: !!card.supertypes ? await getSupertype(card.supertypes.map(name => `${name}`)) : null, 199 | types: !!card.types ? await getType(card.types.map(name => `${name}`)) : null, 200 | subtypes: !!card.subtypes ? await getSubtype(card.subtypes.map(name => `${name}`)) : null, 201 | rarity: await updateRarity({ name: card.rarity, class: `ss-${card.rarity.toLowerCase()}` }), 202 | text: !!card.text ? card.text : null, 203 | categories: null, 204 | abilityTypes: null, 205 | keywords: null, 206 | hand: !!card.hand ? card.hand : null, 207 | life: !!card.life ? card.life : null, 208 | power: !!card.power ? card.power : null, 209 | toughness: !!card.toughness ? card.toughness : null, 210 | loyalty: !!card.loyalty ? card.loyalty : null, 211 | legalities: [], 212 | rulings: [] 213 | }) 214 | 215 | await updatePrinting({ 216 | card: cardID, 217 | set: set.id, 218 | images: images, 219 | artist: await updateArtist({ name: card.artist }), 220 | sides: [], 221 | variations: [], 222 | originalType: card.originalType, 223 | originalText: !!card.originalText ? card.originalText : null, 224 | flavor: !!card.flavor ? card.flavor : null, 225 | number: number, 226 | timeshifted: !!card.timeshifted ? card.timeshifted : false, 227 | starter: !!card.starter ? card.starter : false, 228 | reserved: !!card.reserved ? card.reserved : false, 229 | source: !!card.source ? card.source : null 230 | }) 231 | } 232 | const end = present() 233 | log(`${prefix}Finished inserting cards for set ${chalk.green(set.code)}! (${duration(end - start)})`) 234 | } catch (err) { 235 | const end = present() 236 | error(`${prefix}Failed to insert all cards for set ${chalk.green(set.code)}! (${duration(end - start)})`, err) 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /scripts/utilities/colors.js: -------------------------------------------------------------------------------- 1 | import client from './apollo' 2 | import gql from 'graphql-tag' 3 | import chalk from 'chalk' 4 | import present from 'present' 5 | import moment from 'moment' 6 | 7 | const { info, log, error } = console 8 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 9 | 10 | const getColor = async input => await client 11 | .query({ 12 | query: gql`query getColor($input: [String]) { 13 | color(filter: {symbol: $input}) { 14 | id 15 | } 16 | }`, 17 | variables: { input }, 18 | fetchPolicy: `cache-first` 19 | }) 20 | .then(res => res.data.color.map(color => color.id)) 21 | .catch(err => log(`Failed to get Color.`, input, err)) 22 | 23 | const getColorIdentity = async input => await client 24 | .query({ 25 | query: gql`query getColorIdentity($input: [String]) { 26 | colorIdentity(filter: { name: $input }) { 27 | id 28 | } 29 | }`, 30 | variables: { input }, 31 | fetchPolicy: `cache-first` 32 | }) 33 | .then(res => res.data.colorIdentity.map(identity => identity.id)) 34 | .catch(err => log(`Failed to get Color Identity.`, input, err)) 35 | 36 | const updateColorIcon = input => client 37 | .mutate({ 38 | mutation: gql`mutation updateColorIcon($input: IconInput) { 39 | updateIcon(input: $input) { 40 | id 41 | } 42 | }`, 43 | variables: { input } 44 | }) 45 | .then(res => res.data.updateIcon.id) 46 | .catch(err => log(`Failed to update Color Icon.`, input, err)) 47 | 48 | const updateColorIdentity = input => client 49 | .mutate({ 50 | mutation: gql`mutation updateColorIdentity($input: ColorIdentityInput) { 51 | updateColorIdentity(input: $input) { 52 | id 53 | } 54 | }`, 55 | variables: { input } 56 | }) 57 | .then(res => res.data.updateColorIdentity.id) 58 | .catch(err => log(`Failed to update Color Identity.`, input, err)) 59 | 60 | const updateColor = input => client 61 | .mutate({ 62 | mutation: gql`mutation updateColor($input: ColorInput) { 63 | updateColor(input: $input) { 64 | id 65 | } 66 | }`, 67 | variables: { input } 68 | }) 69 | .then(res => res.data.updateColor.id) 70 | .catch(err => log(`Failed to update Color.`, input, err)) 71 | 72 | export { getColor, getColorIdentity, updateColorIcon, updateColorIdentity, updateColor } 73 | 74 | export async function insertColors() { 75 | const start = present() 76 | const prefix = `${chalk.red(`[insertColors]: `)}` 77 | try { 78 | log(`${prefix}Adding all colors and identities to database...`) 79 | const colorIdentities = [ 80 | { name: `White`, alias: `White`, colorList: [1], multicolored: false, devoid: false }, 81 | { name: `Blue`, alias: `Blue`, colorList: [2], multicolored: false, devoid: false }, 82 | { name: `Black`, alias: `Black`, colorList: [3], multicolored: false, devoid: false }, 83 | { name: `Red`, alias: `Red`, colorList: [4], multicolored: false, devoid: false }, 84 | { name: `Green`, alias: `Green`, colorList: [5], multicolored: false, devoid: false }, 85 | { name: `Colorless`, alias: `Colorless`, colorList: Array(33 - 6 + 1).fill().map((_, i) => 6 + i), multicolored: false, devoid: false }, 86 | { name: `Devoid`, alias: `Devoid`, colorList: [6], multicolored: false, devoid: true }, 87 | { name: `Snow`, alias: `Snow`, colorList: [34], multicolored: false, devoid: false }, 88 | { name: `White/Blue`, alias: `Azorius Senate`, colorList: [1, 2], multicolored: true, devoid: false }, 89 | { name: `Blue/Black`, alias: `House Dimir`, colorList: [2, 3], multicolored: true, devoid: false }, 90 | { name: `Black/Red`, alias: `Cult of Rakdos`, colorList: [3, 4], multicolored: true, devoid: false }, 91 | { name: `Red/Green`, alias: `Gruul Clans`, colorList: [4, 5], multicolored: true, devoid: false }, 92 | { name: `White/Green`, alias: `Selesnya Conclave`, colorList: [5, 1], multicolored: true, devoid: false }, 93 | { name: `White/Black`, alias: `Orzhov Syndicate`, colorList: [1, 3], multicolored: true, devoid: false }, 94 | { name: `Blue/Red`, alias: `Izzet League`, colorList: [2, 4], multicolored: true, devoid: false }, 95 | { name: `Black/Green`, alias: `Golgari Swarm`, colorList: [3, 5], multicolored: true, devoid: false }, 96 | { name: `White/Red`, alias: `Boros Legion`, colorList: [4, 1], multicolored: true, devoid: false }, 97 | { name: `Blue/Green`, alias: `Simic Combine`, colorList: [5, 2], multicolored: true, devoid: false }, 98 | { name: `White/Blue/Green`, alias: `Bant`, colorList: [5, 1, 2], multicolored: true, devoid: false }, 99 | { name: `White/Blue/Black`, alias: `Esper`, colorList: [1, 2, 3], multicolored: true, devoid: false }, 100 | { name: `Blue/Black/Red`, alias: `Grixis`, colorList: [2, 3, 4], multicolored: true, devoid: false }, 101 | { name: `Black/Red/Green`, alias: `Jund`, colorList: [3, 4, 5], multicolored: true, devoid: false }, 102 | { name: `White/Red/Green`, alias: `Naya`, colorList: [4, 5, 1], multicolored: true, devoid: false }, 103 | { name: `White/Black/Green`, alias: `Abzan Houses`, colorList: [1, 3, 5], multicolored: true, devoid: false }, 104 | { name: `White/Blue/Red`, alias: `Jeskai Way`, colorList: [2, 4, 1], multicolored: true, devoid: false }, 105 | { name: `Blue/Black/Green`, alias: `Sultai Brood`, colorList: [3, 5, 2], multicolored: true, devoid: false }, 106 | { name: `White/Black/Red`, alias: `Mardu Horde`, colorList: [4, 1, 3], multicolored: true, devoid: false }, 107 | { name: `Blue/Red/Green`, alias: `Temur Frontier`, colorList: [5, 2, 4], multicolored: true, devoid: false }, 108 | { name: `White/Blue/Black/Red`, alias: `Artifice`, colorList: [1, 2, 3, 4], multicolored: true, devoid: false }, 109 | { name: `Blue/Black/Red/Green`, alias: `Chaos`, colorList: [2, 3, 4, 5], multicolored: true, devoid: false }, 110 | { name: `White/Black/Red/Green`, alias: `Aggression`, colorList: [3, 4, 5, 1], multicolored: true, devoid: false }, 111 | { name: `White/Blue/Red/Green`, alias: `Altruism`, colorList: [4, 5, 1, 2], multicolored: true, devoid: false }, 112 | { name: `White/Blue/Black/Green`, alias: `Growth`, colorList: [5, 1, 2, 3], multicolored: true, devoid: false }, 113 | { name: `White/Blue/Black/Red/Green`, alias: `Chromatic`, colorList: [1, 2, 3, 4, 5], multicolored: true, devoid: false } 114 | ] 115 | 116 | const colors = [ 117 | { symbol: `{W}`, className: `ms-w`, identity: 1 }, 118 | { symbol: `{U}`, className: `ms-u`, identity: 2 }, 119 | { symbol: `{B}`, className: `ms-b`, identity: 3 }, 120 | { symbol: `{R}`, className: `ms-r`, identity: 4 }, 121 | { symbol: `{G}`, className: `ms-g`, identity: 5 }, 122 | { symbol: `{C}`, className: `ms-c`, identity: 7 }, 123 | { symbol: `{0}`, className: `ms-0`, identity: 6 }, 124 | { symbol: `{1}`, className: `ms-1`, identity: 6 }, 125 | { symbol: `{2}`, className: `ms-2`, identity: 6 }, 126 | { symbol: `{3}`, className: `ms-3`, identity: 6 }, 127 | { symbol: `{4}`, className: `ms-4`, identity: 6 }, 128 | { symbol: `{5}`, className: `ms-5`, identity: 6 }, 129 | { symbol: `{6}`, className: `ms-6`, identity: 6 }, 130 | { symbol: `{7}`, className: `ms-7`, identity: 6 }, 131 | { symbol: `{8}`, className: `ms-8`, identity: 6 }, 132 | { symbol: `{9}`, className: `ms-9`, identity: 6 }, 133 | { symbol: `{10}`, className: `ms-10`, identity: 6 }, 134 | { symbol: `{11}`, className: `ms-11`, identity: 6 }, 135 | { symbol: `{12}`, className: `ms-12`, identity: 6 }, 136 | { symbol: `{13}`, className: `ms-13`, identity: 6 }, 137 | { symbol: `{14}`, className: `ms-14`, identity: 6 }, 138 | { symbol: `{15}`, className: `ms-15`, identity: 6 }, 139 | { symbol: `{16}`, className: `ms-16`, identity: 6 }, 140 | { symbol: `{17}`, className: `ms-17`, identity: 6 }, 141 | { symbol: `{18}`, className: `ms-18`, identity: 6 }, 142 | { symbol: `{19}`, className: `ms-19`, identity: 6 }, 143 | { symbol: `{20}`, className: `ms-20`, identity: 6 }, 144 | { symbol: `{100}`, className: `ms-100`, identity: 6 }, 145 | { symbol: `{1000000}`, className: `ms-1000000`, identity: 6 }, 146 | { symbol: `{infinity}`, className: `ms-infinity`, identity: 6 }, 147 | { symbol: `{X}`, className: `ms-x`, identity: 6 }, 148 | { symbol: `{Y}`, className: `ms-y`, identity: 6 }, 149 | { symbol: `{Z}`, className: `ms-z`, identity: 6 }, 150 | { symbol: `{S}`, className: `ms-s`, identity: 8 }, 151 | { symbol: `{W/U}`, className: `ms-wu ms-split`, identity: 9 }, 152 | { symbol: `{U/B}`, className: `ms-ub ms-split`, identity: 10 }, 153 | { symbol: `{B/R}`, className: `ms-br ms-split`, identity: 11 }, 154 | { symbol: `{R/G}`, className: `ms-rg ms-split`, identity: 12 }, 155 | { symbol: `{G/W}`, className: `ms-gw ms-split`, identity: 13 }, 156 | { symbol: `{W/B}`, className: `ms-wb ms-split`, identity: 14 }, 157 | { symbol: `{U/R}`, className: `ms-ur ms-split`, identity: 15 }, 158 | { symbol: `{B/G}`, className: `ms-bg ms-split`, identity: 16 }, 159 | { symbol: `{R/W}`, className: `ms-rw ms-split`, identity: 17 }, 160 | { symbol: `{G/U}`, className: `ms-gu ms-split`, identity: 18 }, 161 | { symbol: `{2/W}`, className: `ms-2w ms-split`, identity: 1 }, 162 | { symbol: `{2/U}`, className: `ms-2u ms-split`, identity: 2 }, 163 | { symbol: `{2/B}`, className: `ms-2b ms-split`, identity: 3 }, 164 | { symbol: `{2/R}`, className: `ms-2r ms-split`, identity: 4 }, 165 | { symbol: `{2/G}`, className: `ms-2g ms-split`, identity: 5 }, 166 | { symbol: `{W/P}`, className: `ms-wp ms-split`, identity: 1 }, 167 | { symbol: `{U/P}`, className: `ms-up ms-split`, identity: 2 }, 168 | { symbol: `{B/P}`, className: `ms-bp-split`, identity: 3 }, 169 | { symbol: `{R/P}`, className: `ms-rp ms-split`, identity: 4 }, 170 | { symbol: `{G/P}`, className: `ms-gp ms-split`, identity: 5 } 171 | ] 172 | 173 | await Promise.all(colorIdentities.map(({ name, alias, colorList, multicolored, devoid }) => { 174 | info(`${prefix}Adding color identity ${chalk.green(alias)}`) 175 | updateColorIdentity({ name, alias, colors: colorList, multicolored, devoid }) 176 | })) 177 | .then(info(`${prefix}Finished adding Color Identities.`)) 178 | .catch(err => error(`${prefix}Failed to add Color Identities.`, { err })) 179 | 180 | await Promise.all(colors.map(async ({ symbol, className, identity }) => { 181 | info(`${prefix}Adding color ${chalk.green(symbol)}`) 182 | const icon = await updateColorIcon({ name: symbol, class: className }) 183 | updateColor({ symbol, icon, identity }) 184 | })) 185 | .then(info(`${prefix}Finished adding Colors.`)) 186 | .catch(err => error(`${prefix}Failed to add Colors.`, { err })) 187 | const end = present() 188 | log(`${prefix}Finished inserting all colors and identities! (${duration(end - start)})`) 189 | } catch (err) { 190 | const end = present() 191 | error(`${prefix}Failed to add all colors and identities to the database. (${duration(end - start)})`, err) 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /scripts/utilities/index.js: -------------------------------------------------------------------------------- 1 | export * from './colors' 2 | export * from './cards' 3 | export * from './languages' 4 | export * from './sets' 5 | export * from './types' 6 | -------------------------------------------------------------------------------- /scripts/utilities/languages.js: -------------------------------------------------------------------------------- 1 | import client from './apollo' 2 | import gql from 'graphql-tag' 3 | import chalk from 'chalk' 4 | import present from 'present' 5 | import moment from 'moment' 6 | 7 | const { info, log, error } = console 8 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 9 | 10 | const updateLanguageCode = input => client 11 | .mutate({ 12 | mutation: gql`mutation updateLanguageCode($input: LanguageCodeInput) { 13 | updateLanguageCode(input: $input) { 14 | id 15 | } 16 | }`, 17 | variables: { input } 18 | }) 19 | .then(res => res.data.updateLanguageCode) 20 | .catch(err => log(`Failed to update Language Code.`, input, err)) 21 | 22 | const getLanguageCode = async input => await client 23 | .query({ 24 | query: gql`query getLanguageCode($input: [String]) { 25 | language(filter: { name: $input }) { 26 | id 27 | code { 28 | id 29 | code 30 | } 31 | } 32 | }`, 33 | variables: { input }, 34 | fetchPolicy: `cache-first` 35 | }) 36 | .then(res => res.data.language[0].code) 37 | .catch(err => log(`Failed to get Language Code.`, input, err)) 38 | 39 | const updateLanguage = input => client 40 | .mutate({ 41 | mutation: gql`mutation updateLangauge($input: LanguageInput) { 42 | updateLanguage(input: $input) { 43 | id 44 | } 45 | }`, 46 | variables: { input } 47 | }) 48 | .then(res => res.data.updateLanguage) 49 | .catch(err => log(`Failed to update Language.`, input, err)) 50 | 51 | export { updateLanguageCode, getLanguageCode, updateLanguage } 52 | 53 | export async function insertLanguages() { 54 | const start = present() 55 | const prefix = `${chalk.green(`[insertLanguages]: `)}` 56 | try { 57 | log(`${prefix}Begin adding languages to database...`) 58 | const languages = [ 59 | { code: `en-US`, language: `English`}, 60 | { code: `zh-Hans`, language: `Chinese Simplified`}, 61 | { code: `zh-Hant`, language: `Chinese Traditional`}, 62 | { code: `fr`, language: `French`}, 63 | { code: `de`, language: `German`}, 64 | { code: `it`, language: `Italian`}, 65 | { code: `ja`, language: `Japanese`}, 66 | { code: `ko`, language: `Korean`}, 67 | { code: `pt`, language: `Portuguese`}, 68 | { code: `ru`, language: `Russian`}, 69 | { code: `es`, language: `Spanish`}, 70 | { code: `pt-br`, language: `Portuguese (Brazil)`} 71 | ] 72 | await Promise.all(languages.map(({code, language}, index) => { 73 | info(`${prefix}Adding language ${chalk.green(language)}`) 74 | updateLanguageCode({ code, language: index }) 75 | updateLanguage({ name: language, code: index }) 76 | })) 77 | .then(info(`${prefix}Finished adding Languages.`)) 78 | .catch(err => error(`${prefix}Failed to add Languages.`, { err })) 79 | const end = present() 80 | log(`${prefix}Finished inserting languages! (${duration(end - start)})`) 81 | } catch (err) { 82 | const end = present() 83 | error(`${prefix}Failed to add languages to the database. (${duration(end - start)})`, err) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /scripts/utilities/sets.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import client from './apollo' 3 | import gql from 'graphql-tag' 4 | import chalk from 'chalk' 5 | import present from 'present' 6 | import moment from 'moment' 7 | 8 | const { info, log, error } = console 9 | const BaseUrl = `https://api.magicthegathering.io/v1` 10 | 11 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 12 | 13 | const updateSet = async input => await client 14 | .mutate({ 15 | mutation: gql`mutation updateSet($input: SetInput) { 16 | updateSet(input: $input) { 17 | id 18 | code 19 | } 20 | }`, 21 | variables: { input } 22 | }) 23 | .then(res => res.data.updateSet) 24 | .catch(err => log(`Failed to update Set.`, input, err)) 25 | 26 | const updateSetType = async input => await client 27 | .mutate({ 28 | mutation: gql`mutation updateSetType($input: SetTypeInput) { 29 | updateSetType(input: $input) { 30 | id 31 | } 32 | }`, 33 | variables: { input } 34 | }) 35 | .then(res => res.data.updateSetType.id) 36 | .catch(err => log(`Failed to update Set Type.`, input, err)) 37 | 38 | const updateSetIcon = async input => await client 39 | .mutate({ 40 | mutation: gql`mutation updateIcon($input: IconInput) { 41 | updateIcon(input: $input) { 42 | id 43 | } 44 | }`, 45 | variables: { input } 46 | }) 47 | .then(res => res.data.updateIcon.id) 48 | .catch(err => log(`Failed to update Set Icon.`, input, err)) 49 | 50 | const updateBlock = async input => await client 51 | .mutate({ 52 | mutation: gql`mutation updateBlock($input: BlockInput) { 53 | updateBlock(input: $input) { 54 | id 55 | } 56 | }`, 57 | variables: { input } 58 | }) 59 | .then(res => res.data.updateBlock.id) 60 | .catch(err => log(`Failed to update Block.`, input, err)) 61 | 62 | export { updateSet, updateSetType, updateSetIcon, updateBlock } 63 | 64 | export async function fetchSets() { 65 | try { 66 | let data = await fetch(`${BaseUrl}/sets`).then(response => response.json()) 67 | return data.sets 68 | } catch (err) { 69 | error(err) 70 | } 71 | } 72 | 73 | export async function insertSets(sets) { 74 | const start = present() 75 | const prefix = `${chalk.blue(`[insertSets]: `)}` 76 | try { 77 | log(`${prefix}Adding all sets to database`) 78 | let results = [] 79 | for (let set of await sets) { 80 | info(`${prefix}Adding set ${chalk.green(set.name)}`) 81 | const code = set.code.toLowerCase() 82 | set.type = await updateSetType({ name: set.type }) 83 | set.icon = await updateSetIcon({ name: code, class: `ss-${code}` }) 84 | if (!!set.block) set.block = await updateBlock({ name: set.block.toString() }) 85 | results.push(await updateSet(new Set(set))) 86 | } 87 | const end = present() 88 | log(`${prefix}Finished inserting all sets! (${duration(end - start)})`) 89 | return results 90 | } catch (err) { 91 | const end = present() 92 | error(`${prefix}Failed to add all sets to the database. (${duration(end - start)})`, err) 93 | } 94 | } 95 | 96 | class Set { 97 | constructor(data) { 98 | this.name = data.name 99 | this.code = data.code 100 | this.block = !!data.block ? data.block : null 101 | this.type = data.type 102 | this.icon = data.icon 103 | this.border = data.border 104 | this.releaseDate = moment(data.releaseDate).format(`YYYY-MM-DD`) 105 | this.booster = null 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /scripts/utilities/types.js: -------------------------------------------------------------------------------- 1 | import 'isomorphic-fetch' 2 | import client from './apollo' 3 | import gql from 'graphql-tag' 4 | import chalk from 'chalk' 5 | import present from 'present' 6 | import moment from 'moment' 7 | 8 | const BaseUrl = `https://api.magicthegathering.io/v1` 9 | const { info, log, error } = console 10 | const duration = ms => moment.utc(ms).format(`HH:mm:ss.SSS`) 11 | 12 | const updateType = input => client 13 | .mutate({ 14 | mutation: gql`mutation updateType($input: TypeInput) { 15 | updateType(input: $input) { 16 | id 17 | } 18 | }`, 19 | variables: { input } 20 | }) 21 | .then(res => res.data.updateType.id) 22 | .catch(err => log(`Failed to update Type.`, input, err)) 23 | 24 | const getType = async input => await client 25 | .query({ 26 | query: gql`query getType($input: [String]) { 27 | type(filter: { name: $input }) { 28 | id 29 | } 30 | }`, 31 | variables: { input }, 32 | fetchPolicy: `cache-first` 33 | }) 34 | .then(res => res.data.type.map(type => type.id)) 35 | .catch(err => log(`Failed to get Type.`, input, err)) 36 | 37 | const updateSubtype = input => client 38 | .mutate({ 39 | mutation: gql`mutation updateSubtype($input: SubtypeInput) { 40 | updateSubtype(input: $input) { 41 | id 42 | } 43 | }`, 44 | variables: { input } 45 | }) 46 | .then(res => res.data.updateSubtype.id) 47 | .catch(err => log(`Failed to update Subtype.`, input, err)) 48 | 49 | const getSubtype = async input => await client 50 | .query({ 51 | query: gql`query getSubtype($input: [String]) { 52 | subtype(filter: { name: $input }) { 53 | id 54 | } 55 | }`, 56 | variables: { input }, 57 | fetchPolicy: `cache-first` 58 | }) 59 | .then(res => res.data.subtype.map(subtype => subtype.id)) 60 | .catch(err => log(`Failed to get Subtype.`, input, err)) 61 | 62 | const updateSupertype = input => client 63 | .mutate({ 64 | mutation: gql`mutation updateSupertype($input: SupertypeInput) { 65 | updateSupertype(input: $input) { 66 | id 67 | } 68 | }`, 69 | variables: { input } 70 | }) 71 | .then(res => res.data.updateSupertype.id) 72 | .catch(err => log(`Failed to update Supertype.`, input, err)) 73 | 74 | const getSupertype = async input => await client 75 | .query({ 76 | query: gql`query getSupertype($input: [String]) { 77 | supertype(filter: { name: $input }) { 78 | id 79 | } 80 | }`, 81 | variables: { input }, 82 | fetchPolicy: `cache-first` 83 | }) 84 | .then(res => res.data.supertype.map(supertype => supertype.id)) 85 | .catch(err => log(`Failed to get Supertype.`, input, err)) 86 | 87 | export { updateSupertype, updateType, updateSubtype, getSupertype, getType, getSubtype } 88 | 89 | export async function fetchTypes() { 90 | try { 91 | let supertypes = await fetch(`${BaseUrl}/supertypes`).then(response => response.json()) 92 | let types = await fetch(`${BaseUrl}/types`).then(response => response.json()) 93 | let subtypes = await fetch(`${BaseUrl}/subtypes`).then(response => response.json()) 94 | return { ...supertypes, ...types, ...subtypes } 95 | } catch (err) { 96 | error(err) 97 | } 98 | } 99 | 100 | export async function insertTypes(data) { 101 | const start = present() 102 | const prefix = `${chalk.yellow(`[insertTypes]: `)}` 103 | try { 104 | let results = { 105 | subtypes: [], 106 | supertypes: [], 107 | types: [] 108 | } 109 | let types = await data 110 | log(`${prefix}Adding all types to database.`) 111 | 112 | results.supertypes = await Promise 113 | .all(types.supertypes.map(supertype => { 114 | info(`${prefix}Adding Supertype ${chalk.green(supertype)}`) 115 | return updateSupertype({ name: supertype }) 116 | })) 117 | .then(info(`${prefix}Finished adding Supertypes`)) 118 | .catch(err => error(`${prefix}Failed to add Supertypes.`, { err })) 119 | 120 | results.types = await Promise 121 | .all(types.types.map(type => { 122 | info(`${prefix}Adding Type ${chalk.green(type)}`) 123 | return updateType({ name: type }) 124 | })) 125 | .then(info(`${prefix}Finished adding Types`)) 126 | .catch(err => error(`${prefix}Failed to add Types.`, { err })) 127 | 128 | results.types = await Promise 129 | .all(types.subtypes.map(subtype => { 130 | info(`${prefix}Adding Subtype ${chalk.green(subtype)}`) 131 | return updateSubtype({ name: subtype }) 132 | })) 133 | .then(info(`${prefix}Finished adding Subtypes`)) 134 | .catch(err => error(`${prefix}Failed to add Subtypes.`, { err })) 135 | 136 | const end = present() 137 | log(`${prefix}Finished inserting all types! (${duration(end - start)})`) 138 | return results 139 | } catch (err) { 140 | const end = present() 141 | error(`${prefix}Failed to add all types to the database. (${duration(end - start)})`, err) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var fs = require('fs'); 3 | fs.createReadStream('.env.default') 4 | .pipe(fs.createWriteStream('.env')); 5 | -------------------------------------------------------------------------------- /src/config/bookshelf.config.js: -------------------------------------------------------------------------------- 1 | import knex from 'knex'// http://knexjs.org/ 2 | import bookshelf from 'bookshelf' // http://bookshelfjs.org/ 3 | import modelbase from 'bookshelf-modelbase' // https://github.com/bsiddiqui/bookshelf-modelbase 4 | import config from './server.config' 5 | 6 | const db = bookshelf(knex(config.db)) 7 | 8 | db.plugin(modelbase.pluggable) 9 | db.plugin(`registry`) // https://github.com/tgriesser/bookshelf/wiki/Plugin:-Model-Registry 10 | db.plugin(`visibility`) // https://github.com/tgriesser/bookshelf/wiki/Plugin:-Visibility 11 | db.plugin(`pagination`) // https://github.com/tgriesser/bookshelf/wiki/Plugin:-Pagination 12 | 13 | export default db 14 | -------------------------------------------------------------------------------- /src/config/graphql.config.js: -------------------------------------------------------------------------------- 1 | import Schema from '../schema' 2 | 3 | class Graphql { 4 | // API Endpoint Settings 5 | api = { 6 | path: `/api`, 7 | graphqlOptions: (request) => { 8 | let options = { 9 | schema: Schema, 10 | root_value: Schema, 11 | debug: true 12 | } 13 | return options 14 | } 15 | } 16 | 17 | // GraphiQL Editor Settings 18 | graphiql = { 19 | path: `/graphiql`, 20 | graphiqlOptions: { 21 | endpointURL: `/api` 22 | } 23 | } 24 | } 25 | 26 | export default new Graphql() 27 | -------------------------------------------------------------------------------- /src/config/server.config.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv' // https://github.com/motdotla/dotenv 2 | import Winston from 'winston' // https://github.com/winstonjs/winston 3 | import 'winston-loggly-bulk' // https://github.com/loggly/winston-loggly-bulk 4 | 5 | dotenv.config() 6 | 7 | class Config { 8 | ENV = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() || (process.env.NODE_ENV === `development`) 9 | 10 | // HTTP Server Settings 11 | http = { 12 | host: `127.0.0.1`, 13 | port: process.env.HTTP || 1337, 14 | routes: { 15 | cors: true 16 | } 17 | } 18 | 19 | // HTTPS Server Settings 20 | https = { 21 | host: `127.0.0.1`, 22 | port: process.env.HTTPS || 8080, 23 | routes: { 24 | cors: true 25 | } 26 | } 27 | 28 | // Sets the server's log level 29 | level = process.env.LOGLEVEL || `info` 30 | 31 | // Winston Logger Settings 32 | winston = { 33 | transports: [ 34 | new (Winston.transports.Loggly)({ 35 | token: process.env.LOGGLY_TOKEN, 36 | subdomain: process.env.LOGGLY_SUBDOMAIN, 37 | tags: [`Winston-NodeJS`, `Scribe`], 38 | json: true 39 | }), 40 | new (Winston.transports.Console)({ 41 | level: this.level, 42 | prettyPrint: true, 43 | handleExceptions: true, 44 | humanReadableUnhandledException: true, 45 | json: false, 46 | colorize: true 47 | }) 48 | ] 49 | } 50 | 51 | // Good Logger Settings 52 | good = { 53 | ops: { 54 | interval: 1000 55 | }, 56 | reporters: { 57 | winston: [{ 58 | module: `good-winston`, 59 | args: [new Winston.Logger(this.winston), { 60 | error_level: `error`, 61 | ops_level: `debug`, 62 | request_level: `debug`, 63 | response_level: `info`, 64 | other_level: `info` 65 | }] 66 | }] 67 | } 68 | } 69 | 70 | // Settings for MySQL Database 71 | mysql = { 72 | host: process.env.DB_HOST || `127.0.0.1`, 73 | user: process.env.DB_USERNAME || `root`, 74 | password: process.env.DB_PASSWORD || `password`, 75 | database: process.env.DB_NAME || `scribe`, 76 | charset: `utf8` 77 | } 78 | 79 | // Settings for SQLite3 Database 80 | sqlite = { 81 | filename: `./src/scribe.sqlite` 82 | } 83 | 84 | // Settings for Knex 85 | db = { 86 | client: this.ENV === `test` || this.ENV === `development` ? `sqlite` : `mysql`, 87 | connection: this.ENV === `test` || this.ENV === `development` ? this.sqlite : this.mysql, 88 | migrations: { 89 | directory: `./src/models`, 90 | tableName: `migrations` 91 | }, 92 | useNullAsDefault: this.ENV === `test` || this.ENV === `development` ? true : false 93 | } 94 | } 95 | 96 | export default new Config() 97 | -------------------------------------------------------------------------------- /src/models/index.js: -------------------------------------------------------------------------------- 1 | import config from '../config/server.config' 2 | import * as Tables from './tables' 3 | import * as Lists from './lists' 4 | const { log, error } = console 5 | 6 | export const Models = { ...Tables, ...Lists } 7 | 8 | export default Models 9 | 10 | const create = (knex) => Object.values(Models) 11 | .filter(migration => (!!migration.fields || !!migration.foreignKeys)) 12 | .map(migration => knex.schema.createTableIfNotExists(migration.name, (table) => { 13 | migration.fields(table) 14 | if (config.ENV === `test` || config.ENV === `development` && !!migration.foreignKeys) migration.foreignKeys(table) 15 | }) 16 | .then(() => log(`Created table: ${migration.name}`)) 17 | .catch(err => error(`Failed to create table: ${migration.name}`, err))) 18 | 19 | const update = (knex) => Object.values(Models) 20 | .filter(migration => !!migration.foreignKeys) 21 | .map(migration => knex.schema.table(migration.name, table => migration.foreignKeys(table)) 22 | .then(() => log(`Set Foreign Keys on table: ${migration.name}`)) 23 | .catch(err => error(`Failed to alter table: ${migration.name}`, err))) 24 | 25 | const destroy = (knex) => Object.values(Models) 26 | .map(migration => knex.schema.dropTableIfExists(migration.name) 27 | .then(() => log(`Destroyed table: ${migration.name}`)) 28 | .catch(err => error(`Failed to destroy table: ${migration.name}`, err))) 29 | 30 | // http://knexjs.org/#Migrations-API 31 | 32 | const pragma = ` 33 | PRAGMA foreign_keys = ON; 34 | PRAGMA synchronous = OFF; 35 | PRAGMA journal_mode = MEMORY; 36 | PRAGMA temp_store = MEMORY; 37 | PRAGMA count_changes = OFF; 38 | ` 39 | 40 | export const up = (knex, Promise) => knex 41 | .raw(`${ config.ENV === `production` ? `SET foreign_key_checks = 0;` : pragma }`) 42 | .then(() => Promise.all(create(knex))) 43 | .then(() => config.ENV === `production` ? Promise.all(update(knex)) : null) 44 | .then(() => config.ENV === `production` ? knex.raw(`SET foreign_key_checks = 1;`) : null) 45 | 46 | export const down = (knex, Promise) => knex 47 | .raw(`${ config.ENV === `production` ? `SET foreign_key_checks = 0;` : `` }`) 48 | .then(() => Promise.all(destroy(knex))) 49 | .then(() => config.ENV === `production` ? knex.raw(`SET foreign_key_checks = 1;`) : null) 50 | -------------------------------------------------------------------------------- /src/models/lists/abilityTypeCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card, AbilityType } from '../tables' 3 | 4 | export default class AbilityTypeCards extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigInteger(`abilitytype`) 9 | .comment(`The abilityType associated with this card.`) 10 | .notNullable() 11 | .unsigned() 12 | .index(`abilitytypecards_abilitytype`) 13 | 14 | table.bigInteger(`card`) 15 | .comment(`The card associated with this abilityType.`) 16 | .notNullable() 17 | .unsigned() 18 | .index(`abilitytypecards_card`) 19 | 20 | // Timestamps 21 | table.timestamps() 22 | 23 | // Keys 24 | table.primary([`abilitytype`, `card`]) 25 | } 26 | 27 | // Bookshelf Relation Definitions 28 | get tableName() { return `abilitytypecards` } 29 | 30 | get hasTimestamps() { return true } 31 | 32 | abilityType() { 33 | return this.belongsTo(AbilityType) 34 | } 35 | 36 | card() { 37 | return this.hasMany(Card) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/models/lists/abilityTypes.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class AbilityTypes extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this abilityType.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`abilitytypes_card`) 12 | 13 | table.bigInteger(`abilitytype`) 14 | .comment(`The abilityType associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`abilitytypes_abilitytype`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `abilitytype`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `abilitytypes` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/artistCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class ArtistCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`artist`) 8 | .comment(`The artist associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`artistcards_artist`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this artist.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`artistcards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`artist`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `artistcards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/blockSets.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class BlockSets extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`block`) 8 | .comment(`The block associated with this set.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`blocksets_block`) 12 | 13 | table.bigInteger(`set`) 14 | .comment(`The set associated with this block.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`blocksets_set`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`block`, `set`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `blocksets` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/cardColors.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class CardColors extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with the color.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`cardColors_card`) 12 | 13 | table.bigInteger(`color`) 14 | .comment(`The color associated with the card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`cardColors_color`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `color`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `cardColors` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/categories.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Categories extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this category.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`categories_card`) 12 | 13 | table.bigInteger(`category`) 14 | .comment(`The category associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`categories_category`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `category`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `categories` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/categoryCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class CategoryCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`category`) 8 | .comment(`The category associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`categorycards_category`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this category.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`categorycards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`category`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `categorycards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/colors.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Colors extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`coloridentity`) 8 | .comment(`The colorIdentity associated with the color.`) 9 | .notNullable() 10 | .unsigned() 11 | 12 | table.bigInteger(`color`) 13 | .comment(`The color associated with the colorIdentity.`) 14 | .notNullable() 15 | .unsigned() 16 | 17 | // Timestamps 18 | table.timestamps() 19 | 20 | // Keys 21 | table.primary([`coloridentity`, `color`]) 22 | } 23 | 24 | // Bookshelf Relation Definitions 25 | get tableName() { return `colors` } 26 | 27 | get hasTimestamps() { return true } 28 | } 29 | -------------------------------------------------------------------------------- /src/models/lists/formatSets.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class FormatSets extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`format`) 8 | .comment(`The format associated with this set.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`formatsets_format`) 12 | 13 | table.bigInteger(`set`) 14 | .comment(`The set associated with this format.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`formatsets_set`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`format`, `set`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `formatsets` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/icons.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Icons extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`layout`) 8 | .comment(`The layout associated with this icon.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`icons_layout`) 12 | 13 | table.bigInteger(`icon`) 14 | .comment(`The icon associated with this layout.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`icons_icon`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`layout`, `icon`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `icons` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/images.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Images extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`printing`) 8 | .comment(`The printing associated with this image.`) 9 | .notNullable() 10 | .unsigned() 11 | 12 | table.bigInteger(`image`) 13 | .comment(`The image associated with this printing.`) 14 | .notNullable() 15 | .unsigned() 16 | 17 | // Timestamps 18 | table.timestamps() 19 | 20 | // Keys 21 | table.primary([`printing`, `image`]) 22 | } 23 | 24 | // Bookshelf Relation Definitions 25 | get tableName() { return `images` } 26 | 27 | get hasTimestamps() { return true } 28 | } 29 | -------------------------------------------------------------------------------- /src/models/lists/index.js: -------------------------------------------------------------------------------- 1 | export { default as AbilityTypeCards } from './abilityTypeCards' 2 | export { default as AbilityTypes } from './abilityTypes' 3 | export { default as ArtistCards } from './artistCards' 4 | export { default as BlockSets } from './blockSets' 5 | export { default as CardColors } from './cardColors' 6 | export { default as Categories } from './categories' 7 | export { default as Colors } from './colors' 8 | export { default as FormatSets } from './formatSets' 9 | export { default as Icons } from './icons' 10 | export { default as Images } from './images' 11 | export { default as KeywordCards } from './keywordCards' 12 | export { default as Keywords } from './keywords' 13 | export { default as Legalities } from './legalities' 14 | export { default as LegalityCards } from './legalityCards' 15 | export { default as NameCards } from './nameCards' 16 | export { default as Names } from './names' 17 | export { default as Printings } from './printings' 18 | export { default as RulingCards } from './rulingCards' 19 | export { default as Rulings } from './rulings' 20 | export { default as Sides } from './sides' 21 | export { default as Subtypes } from './subtypes' 22 | export { default as Supertypes } from './supertypes' 23 | export { default as Types } from './types' 24 | export { default as Variations } from './variations' 25 | -------------------------------------------------------------------------------- /src/models/lists/keywordCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class KeywordCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`keyword`) 8 | .comment(`The keyword associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`keywordcards_keyword`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this keyword.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`keywordcards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`keyword`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `keywordcards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/keywords.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Keywords extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this keyword.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`keywords_card`) 12 | 13 | table.bigInteger(`keyword`) 14 | .comment(`The keyword associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`keywords_keyword`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `keyword`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `keywords` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/legalities.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Legalities extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this legality.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`legalities_card`) 12 | 13 | table.bigInteger(`legality`) 14 | .comment(`The legality associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`legalities_legality`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `legality`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `legalities` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/legalityCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class LegalityCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`legality`) 8 | .comment(`The legality associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`legalitycards_legality`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this legality.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`legalitycards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`legality`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `legalitycards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/nameCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class NameCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`name`) 8 | .comment(`The name associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`namecards_name`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this name.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`namecards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`name`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `namecards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/names.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Names extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this name.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`names_card`) 12 | 13 | table.bigInteger(`name`) 14 | .comment(`The name associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`names_name`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `name`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `names` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/printings.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Printings extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this printing.`) 9 | .notNullable() 10 | .unsigned() 11 | 12 | table.bigInteger(`printing`) 13 | .comment(`The printing associated with this card.`) 14 | .notNullable() 15 | .unsigned() 16 | 17 | // Timestamps 18 | table.timestamps() 19 | 20 | // Keys 21 | table.primary([`card`, `printing`]) 22 | } 23 | 24 | // Bookshelf Relation Definitions 25 | get tableName() { return `printings` } 26 | 27 | get hasTimestamps() { return true } 28 | } 29 | -------------------------------------------------------------------------------- /src/models/lists/rulingCards.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class RulingCards extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`ruling`) 8 | .comment(`The ruling associated with this card.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`rulingcards_ruling`) 12 | 13 | table.bigInteger(`card`) 14 | .comment(`The card associated with this ruling.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`rulingcards_card`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`ruling`, `card`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `rulingcards` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/rulings.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Rulings extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this ruling.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`rulings_card`) 12 | 13 | table.bigInteger(`ruling`) 14 | .comment(`The ruling associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`rulings_ruling`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `ruling`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `rulings` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/sides.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Sides extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this side.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`sides_card`) 12 | 13 | table.bigInteger(`side`) 14 | .comment(`The side associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`sides_side`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `side`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `sides` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/subtypes.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Subtypes extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this subtype.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`subtypes_card`) 12 | 13 | table.bigInteger(`subtype`) 14 | .comment(`The subtype associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`subtypes_subtype`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `subtype`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `subtypes` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/supertypes.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Supertypes extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this supertype.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`supertypes_card`) 12 | 13 | table.bigInteger(`supertype`) 14 | .comment(`The supertype associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`supertypes_supertype`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `supertype`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `supertypes` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/types.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Types extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this type.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`types_card`) 12 | 13 | table.bigInteger(`type`) 14 | .comment(`The type associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`types_type`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `type`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `types` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/lists/variations.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Variations extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigInteger(`card`) 8 | .comment(`The card associated with this variation.`) 9 | .notNullable() 10 | .unsigned() 11 | .index(`variations_card`) 12 | 13 | table.bigInteger(`variation`) 14 | .comment(`The variation associated with this card.`) 15 | .notNullable() 16 | .unsigned() 17 | .index(`variations_variation`) 18 | 19 | // Timestamps 20 | table.timestamps() 21 | 22 | // Keys 23 | table.primary([`card`, `variation`]) 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `variations` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/tables/abilityType.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card } from './' 3 | import { AbilityTypes, AbilityTypeCards } from '../lists' 4 | 5 | export default class AbilityType extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The name of the ability type.`) 17 | .notNullable() 18 | .unique() 19 | 20 | table.text(`description`) 21 | .comment(`Description of the ability type.`) 22 | 23 | table.bigInteger(`cards`) 24 | .comment(`The cards associated with this abilityType.`) 25 | .notNullable() 26 | .unsigned() 27 | .index(`abilitytype_cards`) 28 | 29 | // Timestamps 30 | table.timestamps() 31 | } 32 | 33 | // Bookshelf Relation Definitions 34 | get tableName() { return `abilitytype` } 35 | 36 | get hasTimestamps() { return true } 37 | 38 | abilityTypes = () => this.belongsTo(AbilityTypes) 39 | 40 | cards = () => this.hasMany(Card, `card`).through(AbilityTypeCards) 41 | } 42 | -------------------------------------------------------------------------------- /src/models/tables/artist.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card } from './' 3 | import { ArtistCards } from '../lists' 4 | 5 | export default class Artist extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The name of the artist.`) 17 | .notNullable() 18 | .unique() 19 | 20 | table.text(`website`) 21 | .comment(`The website of the artist, if they have one.`) 22 | 23 | table.bigInteger(`cards`) 24 | .comment(`The cards associated with this artist.`) 25 | .unsigned() 26 | .index(`artist_cards`) 27 | 28 | // Timestamps 29 | table.timestamps() 30 | } 31 | 32 | // Bookshelf Relation Definitions 33 | get tableName() { return `artist` } 34 | 35 | get hasTimestamps() { return true } 36 | 37 | cards = () => this.hasMany(Card, `cards`).through(ArtistCards) 38 | } 39 | -------------------------------------------------------------------------------- /src/models/tables/block.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Set } from './' 3 | import { BlockSets } from '../lists' 4 | 5 | export default class Block extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The name of the block.`) 17 | .notNullable() 18 | .unique() 19 | 20 | // Timestamps 21 | table.timestamps() 22 | } 23 | 24 | // Bookshelf Relation Definitions 25 | get tableName() { return `block` } 26 | 27 | get hasTimestamps() { return true } 28 | 29 | sets = () => this.hasMany(Set, `id`).through(BlockSets, `id`, `block`, `set`) 30 | } 31 | -------------------------------------------------------------------------------- /src/models/tables/booster.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Booster extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | // Timestamps 14 | table.timestamps() 15 | } 16 | 17 | // Bookshelf Relation Definitions 18 | get tableName() { return `booster` } 19 | 20 | get hasTimestamps() { return true } 21 | } 22 | -------------------------------------------------------------------------------- /src/models/tables/card.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Name, Layout, Color, ColorIdentity, Supertype, Type, Subtype, Rarity, Category, AbilityType, Keyword, Legality, Ruling, Printing } from './' 3 | import { Names, CardColors, Supertypes, Types, Subtypes, Categories, AbilityTypes, Keywords, Legalities, Rulings, Printings } from '../lists' 4 | 5 | export default class Card extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The English name of the card.`) 17 | .notNullable() 18 | .unique() 19 | 20 | table.string(`border`) 21 | .comment(`If the border for this specific card is DIFFERENT than the border specified in the top level set JSON, then it will be specified here. (Example: Unglued has silver borders, except for the lands which are black bordered)`) 22 | 23 | table.bigInteger(`layout`) 24 | .comment(`The card layout.`) 25 | .notNullable() 26 | .unsigned() 27 | 28 | table.string(`watermark`) 29 | .comment(`The watermark on the card. Note: Split cards don’t currently have this field set, despite having a watermark on each side of the split card.`) 30 | 31 | table.string(`manacost`) 32 | .comment(`The mana cost of this card. Consists of one or more mana symbols. (use cmc and colors to query)`) 33 | 34 | table.integer(`cmc`) 35 | .comment(`Converted mana cost.`) 36 | .notNullable() 37 | 38 | table.bigInteger(`colorIdentity`) 39 | .comment(`The card colors by color code. [“Red”, “Blue”] becomes [“R”, “U”]`) 40 | .notNullable() 41 | .unsigned() 42 | 43 | table.string(`typeLine`) 44 | .comment(`The card type. This is the type you would see on the card if printed today. Note: The dash is a UTF8 long dash as per the MTG rules.`) 45 | .notNullable() 46 | 47 | table.bigInteger(`rarity`) 48 | .comment(`The rarity of the card.`) 49 | .notNullable() 50 | .unsigned() 51 | 52 | table.text(`text`) 53 | .comment(`The text of the card.`) 54 | 55 | table.string(`hand`) 56 | .comment(`Maximum hand size modifier. Only exists for Vanguard cards.`) 57 | 58 | table.string(`life`) 59 | .comment(`Starting life total modifier. Only exists for Vanguard cards.`) 60 | 61 | table.string(`power`) 62 | .comment(`The power of the card. This is only present for creatures. This is a string, not an integer, because some cards have powers like: “1+*”`) 63 | 64 | table.string(`toughness`) 65 | .comment(`The toughness of the card. This is only present for creatures. This is a string, not an integer, because some cards have toughness like: “1+*”`) 66 | 67 | table.integer(`loyalty`) 68 | .comment(`The loyalty of the card. This is only present for planeswalkers.`) 69 | // Timestamps 70 | table.timestamps() 71 | } 72 | 73 | // Bookshelf Relation Definitions 74 | get tableName() { return `card` } 75 | 76 | get hasTimestamps() { return true } 77 | 78 | names = () => this.hasMany(Name, `id`).through(Names, `id`, `card`, `name`) 79 | 80 | layout = () => this.hasOne(Layout, `id`, `layout`) 81 | 82 | colors = () => this.hasMany(Color, `id`).through(CardColors, `id`, `card`, `color`) 83 | 84 | colorIdentity = () => this.hasOne(ColorIdentity, `id`, `colorIdentity`) 85 | 86 | supertypes = () => this.hasMany(Supertype, `id`).through(Supertypes, `id`, `card`, `supertype`) 87 | 88 | types = () => this.hasMany(Type, `id`).through(Types, `id`, `card`, `type`) 89 | 90 | subtypes = () => this.hasMany(Subtype, `id`).through(Subtypes, `id`, `card`, `subtype`) 91 | 92 | categories = () => this.hasMany(Category, `id`).through(Categories, `id`, `card`, `category`) 93 | 94 | keywords = () => this.hasMany(Keyword, `id`).through(Keywords, `id`, `card`, `keyword`) 95 | 96 | abilityTypes = () => this.hasMany(AbilityType, `id`).through(AbilityTypes, `id`, `card`, `abilityType`) 97 | 98 | legalities = () => this.hasMany(Legality, `id`).through(Legalities, `id`, `card`, `legality`) 99 | 100 | rulings = () => this.hasMany(Ruling, `id`).through(Rulings, `id`, `card`, `ruling`) 101 | 102 | printings = () => this.hasMany(Printing, `id`).through(Printings, `id`, `card`, `printing`) 103 | 104 | rarity = () => this.hasOne(Rarity, `id`, `rarity`) 105 | } 106 | -------------------------------------------------------------------------------- /src/models/tables/category.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card } from './' 3 | import { CategoryCards } from '../lists' 4 | 5 | export default class Category extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The name of the category.`) 17 | .notNullable() 18 | .unique() 19 | 20 | table.text(`description`) 21 | .comment(`The description of the category.`) 22 | 23 | table.bigInteger(`cards`) 24 | .comment(`A list of cards that have this category.`) 25 | .notNullable() 26 | .unsigned() 27 | .index(`category_cards`) 28 | 29 | // Timestamps 30 | table.timestamps() 31 | } 32 | 33 | // Bookshelf Relation Definitions 34 | get tableName() { return `category` } 35 | 36 | get hasTimestamps() { return true } 37 | 38 | cards = () => this.hasMany(Card).through(CategoryCards, `category`) 39 | } 40 | -------------------------------------------------------------------------------- /src/models/tables/color.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Icon, ColorIdentity } from './' 3 | import { Colors } from '../lists' 4 | 5 | export default class Color extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`symbol`) 16 | .comment(`The color symbol code for this color.`) 17 | .notNullable() 18 | .notNullable() 19 | .unique() 20 | 21 | table.bigInteger(`icon`) 22 | .comment(`The icon associated with the color.`) 23 | .unsigned() 24 | .references(`id`) 25 | .inTable(`icon`) 26 | .onDelete(`NO ACTION`) 27 | .onUpdate(`NO ACTION`) 28 | 29 | table.bigInteger(`identity`) 30 | .comment(`The color identity associated with the color.`) 31 | .unsigned() 32 | .references(`id`) 33 | .inTable(`coloridentity`) 34 | .onDelete(`NO ACTION`) 35 | .onUpdate(`NO ACTION`) 36 | 37 | // Timestamps 38 | table.timestamps() 39 | } 40 | 41 | // Bookshelf Relation Definitions 42 | get tableName() { return `color` } 43 | 44 | get hasTimestamps() { return true } 45 | 46 | icon = () => this.hasOne(Icon, `id`, `icon`) 47 | 48 | identity = () => this.hasOne(ColorIdentity, `id`, `identity`) 49 | 50 | identities = () => this.belongsToMany(ColorIdentity, `id`).through(Colors, `id`, `coloridentity`, `color`) 51 | } 52 | -------------------------------------------------------------------------------- /src/models/tables/colorIdentity.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Color } from './' 3 | import { Colors } from '../lists' 4 | 5 | export default class ColorIdentity extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.string(`name`) 16 | .comment(`The name of the color identity.`) 17 | .notNullable() 18 | .unique() 19 | 20 | table.string(`alias`) 21 | .comment(`The alias of the color identity. Examples: Bant, Jeskai`) 22 | 23 | table.boolean(`multicolored`) 24 | .comment(`True if the color identity has more than one color.`) 25 | .notNullable() 26 | 27 | table.boolean(`devoid`) 28 | .comment(`True if the color identity is ruled to be colorless.`) 29 | .notNullable() 30 | 31 | // Timestamps 32 | table.timestamps() 33 | } 34 | 35 | // Bookshelf Relation Definitions 36 | get tableName() { return `colorIdentity` } 37 | 38 | get hasTimestamps() { return true } 39 | 40 | colors = () => this.hasMany(Color, `id`).through(Colors, `id`, `coloridentity`, `color`) 41 | } 42 | -------------------------------------------------------------------------------- /src/models/tables/format.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Set } from './' 3 | 4 | export default class Format extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`name`) 15 | .comment(`The name of the format.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.bigInteger(`sets`) 20 | .comment(`List of sets that are included in this format.`) 21 | .notNullable() 22 | .unsigned() 23 | .index(`format_sets`) 24 | 25 | // Timestamps 26 | table.timestamps() 27 | } 28 | 29 | // Bookshelf Relation Definitions 30 | get tableName() { return `format` } 31 | 32 | get hasTimestamps() { return true } 33 | 34 | sets = () => this.hasMany(Set, `sets`) 35 | } 36 | -------------------------------------------------------------------------------- /src/models/tables/icon.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Icon extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the icon.`) 15 | .notNullable() 16 | 17 | table.text(`image`) 18 | .comment(`A URL pointing to an image of the icon.`) 19 | 20 | table.string(`class`) 21 | .comment(`CSS class name used to display the icon.`) 22 | 23 | // Timestamps 24 | table.timestamps() 25 | } 26 | 27 | // Bookshelf Relation Definitions 28 | get tableName() { return `icon` } 29 | 30 | get hasTimestamps() { return true } 31 | } 32 | -------------------------------------------------------------------------------- /src/models/tables/image.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { LanguageCode } from './' 3 | 4 | export default class Image extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`multiverseid`) 15 | .comment(`The multiverseid of the printing on Wizard’s Gatherer web page. Cards from sets that do not exist on Gatherer will NOT have a multiverseid.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.text(`url`) 20 | .comment(`A URL pointing to an image of the card.`) 21 | .notNullable() 22 | 23 | table.bigInteger(`language`) 24 | .comment(`The language code of the language the image is localized in.`) 25 | .notNullable() 26 | .unsigned() 27 | 28 | // Timestamps 29 | table.timestamps() 30 | } 31 | 32 | // Bookshelf Relation Definitions 33 | get tableName() { return `image` } 34 | 35 | get hasTimestamps() { return true } 36 | 37 | language = () => this.hasOne(LanguageCode, `language`) 38 | } 39 | -------------------------------------------------------------------------------- /src/models/tables/index.js: -------------------------------------------------------------------------------- 1 | export { default as AbilityType } from './abilityType' 2 | export { default as Artist } from './artist' 3 | export { default as Block } from './block' 4 | export { default as Booster } from './booster' 5 | export { default as Card } from './card' 6 | export { default as Category } from './category' 7 | export { default as Color } from './color' 8 | export { default as ColorIdentity } from './colorIdentity' 9 | export { default as Format } from './format' 10 | export { default as Icon } from './icon' 11 | export { default as Image } from './image' 12 | export { default as Keyword } from './keyword' 13 | export { default as Language } from './language' 14 | export { default as LanguageCode } from './languageCode' 15 | export { default as Layout } from './layout' 16 | export { default as Legality } from './legality' 17 | export { default as Name } from './name' 18 | export { default as Printing } from './printing' 19 | export { default as Rarity } from './rarity' 20 | export { default as Ruling } from './ruling' 21 | export { default as Set } from './set' 22 | export { default as SetType } from './setType' 23 | export { default as Subtype } from './subtype' 24 | export { default as Supertype } from './supertype' 25 | export { default as Type } from './type' 26 | -------------------------------------------------------------------------------- /src/models/tables/keyword.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card, LanguageCode } from './' 3 | 4 | export default class Keyword extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`name`) 15 | .comment(`The name of the keyword.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.text(`reminderText`) 20 | .comment(`A short description of the keyword rules.`) 21 | 22 | table.bigInteger(`languageCode`) 23 | .comment(`The language code the reminder text of keyword is localized in.`) 24 | .notNullable() 25 | .unsigned() 26 | .index(`keyword_code`) 27 | 28 | table.bigInteger(`cards`) 29 | .comment(`A list of cards that have this keyword.`) 30 | .notNullable() 31 | .unsigned() 32 | .index(`keyword_cards`) 33 | 34 | // Timestamps 35 | table.timestamps() 36 | } 37 | 38 | // Bookshelf Relation Definitions 39 | get tableName() { return `keyword` } 40 | 41 | get hasTimestamps() { return true } 42 | 43 | languageCode = () => this.hasOne(LanguageCode, `languageCode`) 44 | 45 | cards = () => this.belongsToMany(Card, `cards`) 46 | } 47 | -------------------------------------------------------------------------------- /src/models/tables/language.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { LanguageCode } from './' 3 | 4 | export default class Language extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`name`) 15 | .comment(`The name of the language.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.bigInteger(`code`) 20 | .comment(`The language code associated with this language.`) 21 | .notNullable() 22 | .unsigned() 23 | .index(`language_code`) 24 | 25 | // Timestamps 26 | table.timestamps() 27 | } 28 | 29 | // Bookshelf Relation Definitions 30 | get tableName() { return `language` } 31 | 32 | get hasTimestamps() { return true } 33 | 34 | code = () => this.hasOne(LanguageCode, `id`, `code`) 35 | } 36 | -------------------------------------------------------------------------------- /src/models/tables/languageCode.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Language } from './' 3 | 4 | export default class LanguageCode extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`code`) 15 | .comment(`The language code.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.bigInteger(`language`) 20 | .comment(`The language associated with the language code.`) 21 | .notNullable() 22 | .unsigned() 23 | .index(`languagecode_language`) 24 | 25 | // Timestamps 26 | table.timestamps() 27 | } 28 | 29 | // Bookshelf Relation Definitions 30 | get tableName() { return `languagecode` } 31 | 32 | get hasTimestamps() { return true } 33 | 34 | language = () => this.belongsTo(Language, `language`) 35 | } 36 | -------------------------------------------------------------------------------- /src/models/tables/layout.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Icon } from './' 3 | 4 | export default class Layout extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`name`) 15 | .comment(`The name of the layout.`) 16 | .notNullable() 17 | .unique() 18 | 19 | table.bigInteger(`watermark`) 20 | .comment(`Watermark icon used in this layout.`) 21 | .unsigned() 22 | .index(`layout_watermark`) 23 | 24 | table.bigInteger(`icons`) 25 | .comment(`List of icons used in this layout.`) 26 | .unsigned() 27 | .index(`layout_icons`) 28 | 29 | // Timestamps 30 | table.timestamps() 31 | } 32 | 33 | // Bookshelf Relation Definitions 34 | get tableName() { return `layout` } 35 | 36 | get hasTimestamps() { return true } 37 | 38 | icons = () => this.hasMany(Icon, `icons`) 39 | } 40 | -------------------------------------------------------------------------------- /src/models/tables/legality.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Format, Card } from './' 3 | 4 | export default class Legality extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Indexes 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | // Fields 15 | table.bigInteger(`format`) 16 | .comment(`The format associated with this legality.`) 17 | .notNullable() 18 | .unsigned() 19 | .index(`legality_format`) 20 | 21 | table.boolean(`legal`) 22 | .comment(`True if the card is legal in the associated format.`) 23 | .notNullable() 24 | 25 | table.boolean(`restricted`) 26 | .comment(`True if the card is restricted in the associated format.`) 27 | .notNullable() 28 | 29 | table.bigInteger(`cards`) 30 | .comment(`List of cards that have this legality ruling.`) 31 | .notNullable() 32 | .unsigned() 33 | .index(`legality_cards`) 34 | 35 | // Timestamps 36 | table.timestamps() 37 | } 38 | 39 | // Bookshelf Relation Definitions 40 | get tableName() { return `legality` } 41 | 42 | get hasTimestamps() { return true } 43 | 44 | format = () => this.hasOne(Format, `format`) 45 | 46 | cards = () => this.belongsToMany(Card, `cards`) 47 | } 48 | -------------------------------------------------------------------------------- /src/models/tables/name.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card, Language } from './' 3 | 4 | export default class Name extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Fields 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | table.string(`name`) 15 | .comment(`The localized name of the card.`) 16 | .notNullable() 17 | 18 | table.bigInteger(`language`) 19 | .comment(`The language code of the language the name is localized in.`) 20 | .notNullable() 21 | .unsigned() 22 | .index(`name_language`) 23 | 24 | table.bigInteger(`cards`) 25 | .comment(`A list of cards that have this name.`) 26 | .unsigned() 27 | .index(`name_cards`) 28 | 29 | // Timestamps 30 | table.timestamps() 31 | } 32 | 33 | // Bookshelf Relation Definitions 34 | get tableName() { return `name` } 35 | 36 | get hasTimestamps() { return true } 37 | 38 | cards = () => this.belongsTo(Card, `id`, `card`) 39 | 40 | language = () => this.hasOne(Language, `id`, `language`) 41 | } 42 | -------------------------------------------------------------------------------- /src/models/tables/printing.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card, Set, Image, Artist } from './' 3 | import { Images, Sides, Variations } from '../lists' 4 | 5 | export default class Printing extends db.Model { 6 | // Knex Schema Definitions 7 | static fields(table) { 8 | // Fields 9 | table.bigIncrements(`id`) 10 | .notNullable() 11 | .unsigned() 12 | .primary() 13 | .unique() 14 | 15 | table.bigInteger(`card`) 16 | .comment(`The card this is a printing of.`) 17 | .notNullable() 18 | .unsigned() 19 | 20 | table.bigInteger(`set`) 21 | .comment(`The set the card printed in.`) 22 | .notNullable() 23 | .unsigned() 24 | 25 | table.bigInteger(`artist`) 26 | .comment(`The artist of the card on this printing.`) 27 | .notNullable() 28 | .unsigned() 29 | 30 | table.string(`originaltype`) 31 | .comment(`The original type on the card at the time it was printed.`) 32 | 33 | table.text(`originaltext`) 34 | .comment(`The original text on the card at the time it was printed.`) 35 | 36 | table.text(`flavor`) 37 | .comment(`The flavor text on the card for this printing.`) 38 | 39 | table.string(`number`) 40 | .comment(`The card number. This is printed at the bottom-center of the card in small text. This is a string, not an integer, because some cards have letters in their numbers.`) 41 | .notNullable() 42 | 43 | table.boolean(`timeshifted`) 44 | .comment(`If this card was a timeshifted card in the set.`) 45 | 46 | table.boolean(`starter`) 47 | .comment(`Set to true if this card was only released as part of a core box set. These are technically part of the core sets and are tournament legal despite not being available in boosters.`) 48 | 49 | table.boolean(`reserved`) 50 | .comment(`Set to true if this card is reserved by Wizards Official Reprint Policy.`) 51 | 52 | table.string(`source`) 53 | .comment(`For promo cards, this is where this card was originally obtained. For box sets that are theme decks, this is which theme deck the card is from.`) 54 | 55 | // Timestamps 56 | table.timestamps() 57 | } 58 | 59 | // Bookshelf Relation Definitions 60 | get tableName() { return `printing` } 61 | 62 | get hasTimestamps() { return true } 63 | 64 | card = () => this.belongsTo(Card, `card`, `id`) 65 | 66 | set = () => this.belongsTo(Set, `set`, `id`) 67 | 68 | images = () => this.hasMany(Image, `id`).through(Images, `id`, `printing`, `image`) 69 | 70 | artist = () => this.hasOne(Artist, `artist`) 71 | 72 | sides = () => this.hasMany(Card, `id`).through(Sides, `id`, `printing`, `side`) 73 | 74 | variations = () => this.hasMany(Card, `id`).through(Variations, `id`, `printing`, `variation`) 75 | } 76 | -------------------------------------------------------------------------------- /src/models/tables/rarity.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Rarity extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the rarity.`) 15 | .notNullable() 16 | .unique() 17 | 18 | table.string(`class`) 19 | .comment(`CSS class name used to display the rarity.`) 20 | .notNullable() 21 | 22 | // Timestamps 23 | table.timestamps() 24 | } 25 | 26 | // Bookshelf Relation Definitions 27 | get tableName() { return `rarity` } 28 | 29 | get hasTimestamps() { return true } 30 | } 31 | -------------------------------------------------------------------------------- /src/models/tables/ruling.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | import { Card, LanguageCode } from './' 3 | 4 | export default class Ruling extends db.Model { 5 | // Knex Schema Definitions 6 | static fields(table) { 7 | // Indexes 8 | table.bigIncrements(`id`) 9 | .notNullable() 10 | .unsigned() 11 | .primary() 12 | .unique() 13 | 14 | // Fields 15 | table.text(`text`) 16 | .comment(`The localized text of the ruling.`) 17 | .notNullable() 18 | 19 | table.date(`date`) 20 | .comment(`The date the ruling was issued.`) 21 | .notNullable() 22 | 23 | table.bigInteger(`language`) 24 | .comment(`The language code of this ruling.`) 25 | .notNullable() 26 | .unsigned() 27 | .index(`ruling_language`) 28 | 29 | table.bigInteger(`cards`) 30 | .comment(`List of cards that have this ruling.`) 31 | .notNullable() 32 | .unsigned() 33 | .index(`ruling_cards`) 34 | 35 | // Timestamps 36 | table.timestamps() 37 | } 38 | 39 | // Bookshelf Relation Definitions 40 | get tableName() { return `ruling` } 41 | 42 | get hasTimestamps() { return true } 43 | 44 | language = () => this.hasOne(LanguageCode, `language`) 45 | 46 | cards = () => this.belongsToMany(Card, `cards`) 47 | } 48 | -------------------------------------------------------------------------------- /src/models/tables/set.js: -------------------------------------------------------------------------------- 1 | import moment from 'moment' 2 | import db from '../../config/bookshelf.config' 3 | import { Icon, Block, Booster, SetType } from './' 4 | import { BlockSets } from '../lists' 5 | 6 | export default class Set extends db.Model { 7 | // Knex Schema Definitions 8 | static fields(table) { 9 | // Fields 10 | table.bigIncrements(`id`) 11 | .notNullable() 12 | .unsigned() 13 | .primary() 14 | .unique() 15 | 16 | table.string(`name`) 17 | .comment(`The name of the set.`) 18 | .notNullable() 19 | .unique() 20 | 21 | table.string(`code`) 22 | .comment(`The set code.`) 23 | .notNullable() 24 | .unique() 25 | 26 | table.bigInteger(`block`) 27 | .comment(`The block the set belongs to.`) 28 | .unsigned() 29 | .index(`set_block`) 30 | 31 | table.bigInteger(`type`) 32 | .comment(`The type of the set.`) 33 | .notNullable() 34 | .unsigned() 35 | .index(`set_type`) 36 | 37 | table.bigInteger(`icon`) 38 | .comment(`The icon associated with the set.`) 39 | .notNullable() 40 | .unsigned() 41 | .index(`set_icon`) 42 | 43 | table.string(`border`) 44 | .comment(`The border color of the set.`) 45 | .notNullable() 46 | 47 | table.date(`releaseDate`) 48 | .comment(`The date on which the set was released.`) 49 | .notNullable() 50 | 51 | table.bigInteger(`booster`) 52 | .comment(`Booster pack generation rules for this set.`) 53 | .unsigned() 54 | .index(`set_booster`) 55 | 56 | // Timestamps 57 | table.timestamps() 58 | } 59 | 60 | // Bookshelf Relation Definitions 61 | get tableName() { return `set` } 62 | 63 | get hasTimestamps() { return true } 64 | 65 | block = () => this.belongsTo(Block, `block`).through(BlockSets, `id`, `block`, `set`) 66 | 67 | type = () => this.hasOne(SetType, `id`, `type`) 68 | 69 | icon = () => this.hasOne(Icon, `id`, `icon`) 70 | 71 | booster = () => this.hasOne(Booster, `id`, `booster`) 72 | 73 | toJSON() { 74 | let attrs = db.Model.prototype.toJSON.apply(this, arguments) 75 | attrs.releaseDate = moment(this.get(`releaseDate`)).format(`YYYY-MM-DD`) 76 | return attrs 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/models/tables/setType.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class SetType extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the set type.`) 15 | .notNullable() 16 | .unique() 17 | 18 | table.text(`description`) 19 | .comment(`The description of the set type.`) 20 | 21 | // Timestamps 22 | table.timestamps() 23 | } 24 | 25 | // Bookshelf Relation Definitions 26 | get tableName() { return `setType` } 27 | 28 | get hasTimestamps() { return true } 29 | } 30 | -------------------------------------------------------------------------------- /src/models/tables/subtype.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Subtype extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the subtype.`) 15 | .notNullable() 16 | .unique() 17 | 18 | // Timestamps 19 | table.timestamps() 20 | } 21 | 22 | // Bookshelf Relation Definitions 23 | get tableName() { return `subtype` } 24 | 25 | get hasTimestamps() { return true } 26 | } 27 | -------------------------------------------------------------------------------- /src/models/tables/supertype.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Supertype extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the supertype.`) 15 | .notNullable() 16 | .unique() 17 | 18 | // Timestamps 19 | table.timestamps() 20 | } 21 | 22 | // Bookshelf Relation Definitions 23 | get tableName() { return `supertype` } 24 | 25 | get hasTimestamps() { return true } 26 | } 27 | -------------------------------------------------------------------------------- /src/models/tables/type.js: -------------------------------------------------------------------------------- 1 | import db from '../../config/bookshelf.config' 2 | 3 | export default class Type extends db.Model { 4 | // Knex Schema Definitions 5 | static fields(table) { 6 | // Fields 7 | table.bigIncrements(`id`) 8 | .notNullable() 9 | .unsigned() 10 | .primary() 11 | .unique() 12 | 13 | table.string(`name`) 14 | .comment(`The name of the type.`) 15 | .notNullable() 16 | .unique() 17 | 18 | // Timestamps 19 | table.timestamps() 20 | } 21 | 22 | // Bookshelf Relation Definitions 23 | get tableName() { return `type` } 24 | 25 | get hasTimestamps() { return true } 26 | } 27 | -------------------------------------------------------------------------------- /src/routes/example/example.js: -------------------------------------------------------------------------------- 1 | export default class Example { 2 | 3 | /** GET / - List all entities */ 4 | list(req, res) { 5 | res.json({ 6 | message: `yay I work!` 7 | }) 8 | } 9 | 10 | /** POST / - Create a new entity */ 11 | create(req, res) { 12 | console.log(req.body) 13 | res.json(req.body) 14 | } 15 | 16 | /** GET /:id - Return a given entity */ 17 | read(req, res) { 18 | 19 | } 20 | 21 | /** PUT /:id - Update a given entity */ 22 | update(req, res) { 23 | 24 | } 25 | 26 | /** DELETE /:id - Delete a given entity */ 27 | delete(req, res) { 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/routes/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import glob from 'glob' // https://github.com/isaacs/node-glob 3 | 4 | export default (router) => { 5 | glob.sync(`${__dirname}/**/!(*.spec).js`) 6 | .forEach( file => { 7 | if (file !== `index.js`) { 8 | let filename = path.basename(file) 9 | let basename = filename.split(`.`)[0] 10 | let resource = require(file).default 11 | console.log(`✓ Loaded Resource: /${basename}`) 12 | } 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/routes/login/login.js: -------------------------------------------------------------------------------- 1 | import jwt from 'jsonwebtoken' 2 | import passport from 'passport' 3 | import BearerStrategy from 'passport-http-bearer' 4 | 5 | export default class Login { 6 | payload = { 7 | 8 | } 9 | 10 | secret = process.env.JWT_PRIVATE_KEY 11 | 12 | options = { 13 | algorithm: `RS256`, 14 | expiresIn: `2h` 15 | } 16 | 17 | constructor() { 18 | passport.use(new BearerStrategy((token, cb) => { 19 | db.users.findByToken(token, (err, user) => { 20 | if (err) return cb(err) 21 | if (!user) return cb(null, false) 22 | return cb(null, user) 23 | }) 24 | })) 25 | console.log(`✓ Passport configured with Bearer Strategy`) 26 | } 27 | 28 | list(req, res) { 29 | res.send(`Login`) 30 | } 31 | 32 | createToken(user) { 33 | return jwt.sign(this.payload, this.secret, this.options) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/routes/ping/ping.js: -------------------------------------------------------------------------------- 1 | export default class Ping { 2 | 3 | /** GET / - List all entities */ 4 | list(req, res) { 5 | res.send(`pong`) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/routes/signup/signup.js: -------------------------------------------------------------------------------- 1 | export default class Signup { 2 | 3 | /** GET / - List all entities */ 4 | list(req, res) { 5 | 6 | } 7 | 8 | /** POST / - Create a new entity */ 9 | create(req, res) { 10 | 11 | } 12 | 13 | /** GET /:id - Return a given entity */ 14 | read(req, res) { 15 | 16 | } 17 | 18 | /** PUT /:id - Update a given entity */ 19 | update(req, res) { 20 | 21 | } 22 | 23 | /** DELETE /:id - Delete a given entity */ 24 | delete(req, res) { 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/schema.js: -------------------------------------------------------------------------------- 1 | import { GraphQLSchema, GraphQLObjectType } from 'graphql' 2 | import * as Types from './types' 3 | 4 | export default new GraphQLSchema({ 5 | types: Object.values(Types).filter(type => !!type.Definition).map(type => type.Definition ), 6 | query: new GraphQLObjectType({ 7 | name: `Query`, 8 | description: `The root query handler for Scribe's GraphQL interface.`, 9 | fields: () => Object.assign({}, ...Object.values(Types).filter(type => !!type.Queries).map(type => type.Queries)) 10 | }), 11 | mutation: new GraphQLObjectType({ 12 | name: `Mutation`, 13 | description: `The root query for implementing GraphQL mutations.`, 14 | fields: () => Object.assign({}, ...Object.values(Types).filter(type => !!type.Mutations).map(type => type.Mutations)) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | import hapi from 'hapi' // http://hapijs.com/api 3 | //import jwt from 'hapi-auth-jwt2' // https://github.com/dwyl/hapi-auth-jwt2 4 | import boomDecorators from 'hapi-boom-decorators' // https://github.com/brainsiq/hapi-boom-decorators 5 | import statMon from 'hapijs-status-monitor' // https://github.com/ziyasal/hapijs-status-monitor 6 | import { graphqlHapi, graphiqlHapi } from 'graphql-server-hapi' // http://dev.apollodata.com/tools/graphql-server 7 | import good from 'good' // https://github.com/hapijs/good 8 | import 'good-winston' // https://github.com/lancespeelmon/good-winston 9 | import { configure, info, error } from 'winston' 10 | import config from './config/server.config' // HTTP Server Settings 11 | import graphql from './config/graphql.config' // GraphQL Settings 12 | //import routes from './routes' // REST API Endpoints 13 | 14 | configure(config.winston) 15 | 16 | const server = new hapi.Server() 17 | 18 | // Start the server 19 | server.connection(config.http) 20 | 21 | // Setup Boom Decorators 22 | server.register({ 23 | register: boomDecorators 24 | }) 25 | 26 | server.register({ 27 | register: statMon 28 | }) 29 | 30 | // Register the Public GraphQL API Endpoint 31 | server.register({ 32 | register: graphqlHapi, 33 | options: graphql.api 34 | }) 35 | 36 | // Register the GrahiQL Editor Endpoint 37 | server.register({ 38 | register: graphiqlHapi, 39 | options: graphql.graphiql 40 | }) 41 | 42 | // Setup Logging and Start the Server 43 | server.register({ 44 | register: good, 45 | options: config.good 46 | }, (err) => { 47 | if (err) return error(err) 48 | info(`Bookshelf configured using: ${config.db.client}`) 49 | server.start(() => info(`Server started at ${ server.info.uri }`)) 50 | }) 51 | -------------------------------------------------------------------------------- /src/types/abilityType.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `AbilityTypeInput`, 8 | description: `Required fields for a new Ability Type object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | description: { type: GraphQLString }, 12 | cards: { type: new GraphQLList(GraphQLID) } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `AbilityTypeFilter`, 18 | description: `Queryable fields for AbilityType.`, 19 | fields: () => ({ 20 | name: { type: new GraphQLList(GraphQLString) }, 21 | cards: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `AbilityTypeFields`, 27 | description: `Field names for AbilityType.`, 28 | values: { 29 | name: { value: `name` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `AbilityType`, 35 | description: `An Ability Type object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this ability type.` 40 | }, 41 | name: { 42 | type: GraphQLString, 43 | description: `The name of the ability type.` 44 | }, 45 | description: { 46 | type: GraphQLString, 47 | description: `Description of the ability type.` 48 | }, 49 | cards: { 50 | type: new GraphQLList(Card.Definition), 51 | description: `The cards associated with this abilityType.`, 52 | resolve: (root, { id }) => Models.AbilityType 53 | .forge({ id }) 54 | .fetch({ withRelated: [`cards`] }) 55 | .then(model => model.toJSON().cards) 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | abilityType: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns a AbilityType.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`abilityType`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createAbilityType: { 79 | type: Definition, 80 | description: `Creates a new AbilityType`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateAbilityType: { 85 | type: Definition, 86 | description: `Updates an existing AbilityType, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 89 | }, 90 | deleteAbilityType: { 91 | type: Definition, 92 | description: `Deletes a AbilityType by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/artist.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `ArtistInput`, 8 | description: `Required fields for a new Artist object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | website: { type: GraphQLString }, 12 | cards: { type: new GraphQLList(GraphQLID) } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `ArtistFilter`, 18 | description: `Queryable fields for Artist.`, 19 | fields: () => ({ 20 | name: { type: new GraphQLList(GraphQLString) }, 21 | cards: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `ArtistFields`, 27 | description: `Field names for Artist.`, 28 | values: { 29 | name: { value: `name` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `Artist`, 35 | description: `An Artist object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this artist.` 40 | }, 41 | name: { 42 | type: GraphQLString, 43 | description: `The name of the artist.` 44 | }, 45 | website: { 46 | type: GraphQLString, 47 | description: `A URL to the artist's website, if they have one.` 48 | }, 49 | cards: { 50 | type: new GraphQLList(Card.Definition), 51 | description: `A list of cards featuring art from this artist.`, 52 | resolve: (root, { id }) => Models.Artist 53 | .forge({ id }) 54 | .fetch({ withRelated: [`cards`] }) 55 | .then(model => model.toJSON().cards) 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | artist: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns a Artist.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`artist`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createArtist: { 79 | type: Definition, 80 | description: `Creates a new Artist`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateArtist: { 85 | type: Definition, 86 | description: `Updates an existing Artist, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 89 | }, 90 | deleteArtist: { 91 | type: Definition, 92 | description: `Deletes a Rarity by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/block.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Set } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `BlockInput`, 8 | description: `Required fields for a new Block object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) } 11 | }) 12 | }) 13 | 14 | const Filter = new GraphQLInputObjectType({ 15 | name: `BlockFilter`, 16 | description: `Queryable fields for Block.`, 17 | fields: () => ({ 18 | name: { type: new GraphQLList(GraphQLString) }, 19 | sets: { type: new GraphQLList(GraphQLID) } 20 | }) 21 | }) 22 | 23 | const Fields = new GraphQLEnumType({ 24 | name: `BlockFields`, 25 | description: `Field names for Block.`, 26 | values: { 27 | name: { value: `name` } 28 | } 29 | }) 30 | 31 | export const Definition = new GraphQLObjectType({ 32 | name: `Block`, 33 | description: `A Block object`, 34 | fields: () => ({ 35 | id: { 36 | type: GraphQLID, 37 | description: `A unique id for this block.` 38 | }, 39 | name: { 40 | type: GraphQLString, 41 | description: `The name of the block.` 42 | }, 43 | sets: { 44 | type: new GraphQLList(Set.Definition), 45 | description: `List of sets that are included in this block.`, 46 | resolve: (type) => Models.Block 47 | .findById(type.id, { withRelated: [`sets`] }) 48 | .then(model => model.toJSON().sets) 49 | } 50 | }) 51 | }) 52 | 53 | export const Queries = { 54 | block: { 55 | type: new GraphQLList(Definition), 56 | description: `Returns a Block.`, 57 | args: { 58 | id: { type: new GraphQLList(GraphQLID) }, 59 | filter: { 60 | type: Filter 61 | }, 62 | limit: { type: GraphQLInt }, 63 | offset: { type: GraphQLInt }, 64 | orderBy: { type: order(`block`, Fields) } 65 | }, 66 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 67 | } 68 | } 69 | 70 | export const Mutations = { 71 | createBlock: { 72 | type: Definition, 73 | description: `Creates a new Block`, 74 | args: { input: { type: Input } }, 75 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 76 | }, 77 | updateBlock: { 78 | type: Definition, 79 | description: `Updates an existing Block, creates it if it does not already exist`, 80 | args: { input: { type: Input } }, 81 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 82 | }, 83 | deleteBlock: { 84 | type: Definition, 85 | description: `Deletes a Block by id`, 86 | args: { id: { type: GraphQLID } }, 87 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/types/booster.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLEnumType, GraphQLList, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import Models from '../models' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `BoosterInput`, 6 | description: `Required fields for a new Booster object`, 7 | fields: () => ({ 8 | id: { type: GraphQLID } 9 | }) 10 | }) 11 | 12 | export const Definition = new GraphQLObjectType({ 13 | name: `Booster`, 14 | description: `A Booster object`, 15 | fields: () => ({ 16 | id: { 17 | type: GraphQLID, 18 | description: `A unique id for this booster.` 19 | } 20 | }) 21 | }) 22 | 23 | export const Queries = { 24 | 25 | } 26 | 27 | export const Mutations = { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/types/category.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `CategoryInput`, 8 | description: `Required fields for a new Category object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | description: { type: new GraphQLNonNull(GraphQLString) }, 12 | cards: { type: new GraphQLList(GraphQLID) } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `CategoryFilter`, 18 | description: `Queryable fields for Category.`, 19 | fields: () => ({ 20 | name: { type: new GraphQLList(GraphQLString) }, 21 | cards: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `CategoryFields`, 27 | description: `Field names for Category.`, 28 | values: { 29 | name: { value: `name` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `Category`, 35 | description: `A Category object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this category.` 40 | }, 41 | name: { 42 | type: GraphQLString, 43 | description: `The category name.` 44 | }, 45 | description: { 46 | type: GraphQLString, 47 | description: `The description of the category.` 48 | }, 49 | cards: { 50 | type: new GraphQLList(Card.Definition), 51 | description: `A list of cards that have this category.`, 52 | resolve: (root, { id }) => Models.Category 53 | .forge({ id }) 54 | .fetch({ withRelated: [`cards`] }) 55 | .then(model => model.toJSON().cards) 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | category: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns a Category.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`category`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createCategory: { 79 | type: Definition, 80 | description: `Creates a new Category`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateCategory: { 85 | type: Definition, 86 | description: `Updates an existing Category, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 89 | }, 90 | deleteCategory: { 91 | type: Definition, 92 | description: `Deletes a Category by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/color.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { ColorIdentity, Icon } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `ColorInput`, 8 | description: `Required fields for a new Color object`, 9 | fields: () => ({ 10 | symbol: { type: new GraphQLNonNull(GraphQLString) }, 11 | icon: { type: GraphQLID }, 12 | identity: { type: GraphQLID } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `ColorFilter`, 18 | description: `Queryable fields for Color.`, 19 | fields: () => ({ 20 | symbol: { type: new GraphQLList(GraphQLString) }, 21 | icon: { type: new GraphQLList(GraphQLID) }, 22 | identity: { type: new GraphQLList(GraphQLID) } 23 | }) 24 | }) 25 | 26 | const Fields = new GraphQLEnumType({ 27 | name: `ColorFields`, 28 | description: `Field names for Color.`, 29 | values: { 30 | symbol: { value: `symbol` }, 31 | icon: { value: `icon` } 32 | } 33 | }) 34 | 35 | export const Definition = new GraphQLObjectType({ 36 | name: `Color`, 37 | description: `A Color object`, 38 | fields: () => ({ 39 | id: { 40 | type: GraphQLID, 41 | description: `A unique id for this color.` 42 | }, 43 | symbol: { 44 | type: GraphQLString, 45 | description: `The color symbol code for this color.` 46 | }, 47 | icon: { 48 | type: Icon.Definition, 49 | description: `A CSS class used to display a mana symbol for this color.`, 50 | resolve: (type) => Models.Color 51 | .findById(type.id, { withRelated: [`icon`] }) 52 | .then(model => model.toJSON().icon) 53 | }, 54 | identity: { 55 | type: ColorIdentity.Definition, 56 | description: `The color identity of this color.`, 57 | resolve: (type) => Models.Color 58 | .findById(type.id, { withRelated: [`identity`] }) 59 | .then(model => model.toJSON().identity) 60 | } 61 | }) 62 | }) 63 | 64 | export const Queries = { 65 | color: { 66 | type: new GraphQLList(Definition), 67 | description: `Returns a Color.`, 68 | args: { 69 | id: { type: new GraphQLList(GraphQLID) }, 70 | filter: { 71 | type: Filter 72 | }, 73 | limit: { type: GraphQLInt }, 74 | offset: { type: GraphQLInt }, 75 | orderBy: { type: order(`color`, Fields) } 76 | }, 77 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 78 | } 79 | } 80 | 81 | export const Mutations = { 82 | createColor: { 83 | type: Definition, 84 | description: `Creates a new Color`, 85 | args: { input: { type: Input } }, 86 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 87 | }, 88 | updateColor: { 89 | type: Definition, 90 | description: `Updates an existing Color, creates it if it does not already exist`, 91 | args: { input: { type: Input } }, 92 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `symbol`) 93 | }, 94 | deleteColor: { 95 | type: Definition, 96 | description: `Deletes a Color by id`, 97 | args: { id: { type: GraphQLID } }, 98 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/types/colorIdentity.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLBoolean, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { destroy, order, read } from './utilities' 3 | import Models from '../models' 4 | import { Color } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `ColorIdentityInput`, 8 | description: `Required fields for a new Color Identity object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | alias: { type: GraphQLString }, 12 | colors: { type: new GraphQLList(GraphQLID) }, 13 | multicolored: { type: GraphQLBoolean }, 14 | devoid: { type: GraphQLBoolean } 15 | }) 16 | }) 17 | 18 | const Filter = new GraphQLInputObjectType({ 19 | name: `ColorIdentityFilter`, 20 | description: `Queryable fields for ColorIdentity.`, 21 | fields: () => ({ 22 | name: { type: new GraphQLList(GraphQLString) }, 23 | alias: { type: new GraphQLList(GraphQLString) }, 24 | multicolored: { type: GraphQLBoolean }, 25 | devoid: { type: GraphQLBoolean } 26 | }) 27 | }) 28 | 29 | const Fields = new GraphQLEnumType({ 30 | name: `ColorIdentityFields`, 31 | description: `Field names for ColorIdentity.`, 32 | values: { 33 | name: { value: `name` }, 34 | alias: { value: `alias` }, 35 | multicolored: { value: `multicolored` }, 36 | devoid: { value: `devoid` } 37 | } 38 | }) 39 | 40 | export const Definition = new GraphQLObjectType({ 41 | name: `ColorIdentity`, 42 | description: `A Color Identity object`, 43 | fields: () => ({ 44 | id: { 45 | type: GraphQLID, 46 | description: `A unique id for this color identity.` 47 | }, 48 | name: { 49 | type: GraphQLString, 50 | description: `The color identity name.` 51 | }, 52 | alias: { 53 | type: GraphQLString, 54 | description: `The alias of the color identity. Examples: Bant, Jeskai` 55 | }, 56 | colors: { 57 | type: new GraphQLList(Color.Definition), 58 | description: `A list of colors included in this color identity.`, 59 | resolve: (type) => Models.ColorIdentity 60 | .findById(type.id, { withRelated: [`colors`] }) 61 | .then(model => model.toJSON().colors) 62 | }, 63 | multicolored: { 64 | type: GraphQLBoolean, 65 | description: `Set to True if the color identity counts as multicolored.` 66 | }, 67 | devoid: { 68 | type: GraphQLBoolean, 69 | description: `Set to True if the color identity counts as devoid.` 70 | } 71 | }) 72 | }) 73 | 74 | export const Queries = { 75 | colorIdentity: { 76 | type: new GraphQLList(Definition), 77 | description: `Returns a ColorIdentity.`, 78 | args: { 79 | id: { type: new GraphQLList(GraphQLID) }, 80 | filter: { 81 | type: Filter 82 | }, 83 | limit: { type: GraphQLInt }, 84 | offset: { type: GraphQLInt }, 85 | orderBy: { type: order(`colorIdentity`, Fields) } 86 | }, 87 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 88 | } 89 | } 90 | 91 | export const Mutations = { 92 | createColorIdentity: { 93 | type: Definition, 94 | description: `Creates a new ColorIdentity`, 95 | args: { input: { type: Input } }, 96 | resolve: (root, { input }) => { 97 | let { colors, ...fields } = input 98 | return Models.ColorIdentity 99 | .findOrCreate(fields) 100 | .then(model => { 101 | let identity = model.toJSON() 102 | 103 | if (!!colors) for (let color of colors) Models.Colors.findOrCreate({ coloridentity: identity.id, color }) 104 | 105 | return identity 106 | }) 107 | } 108 | }, 109 | updateColorIdentity: { 110 | type: Definition, 111 | description: `Updates an existing ColorIdentity, creates it if it does not already exist`, 112 | args: { input: { type: Input } }, 113 | resolve: (root, { input }) => { 114 | let { name, colors, ...fields } = input 115 | return Models.ColorIdentity 116 | .upsert({ name }, fields) 117 | .then(model => { 118 | let identity = model.toJSON() 119 | 120 | if (!!colors) for (let color of colors) Models.Colors.findOrCreate({ coloridentity: identity.id, color }) 121 | 122 | return identity 123 | }) 124 | } 125 | }, 126 | deleteColorIdentity: { 127 | type: Definition, 128 | description: `Deletes a ColorIdentity by id`, 129 | args: { id: { type: GraphQLID } }, 130 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/types/format.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Set } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `FormatInput`, 8 | description: `Required fields for a new Format object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | sets: { type: new GraphQLList(GraphQLID) } 12 | }) 13 | }) 14 | 15 | const Filter = new GraphQLInputObjectType({ 16 | name: `FormatFilter`, 17 | description: `Queryable fields for Format.`, 18 | fields: () => ({ 19 | name: { type: new GraphQLList(GraphQLString) } 20 | }) 21 | }) 22 | 23 | const Fields = new GraphQLEnumType({ 24 | name: `FormatFields`, 25 | description: `Field names for Format.`, 26 | values: { 27 | name: { value: `name` } 28 | } 29 | }) 30 | 31 | export const Definition = new GraphQLObjectType({ 32 | name: `Format`, 33 | description: `A Format object`, 34 | fields: () => ({ 35 | id: { 36 | type: GraphQLID, 37 | description: `A unique id for this format.` 38 | }, 39 | name: { 40 | type: GraphQLString, 41 | description: `The format name.` 42 | }, 43 | sets: { 44 | type: new GraphQLList(Set.Definition), 45 | description: `A list of sets included in this format`, 46 | resolve: (root, { id }) => Models.Format 47 | .forge({ id }) 48 | .fetch({ withRelated: [`sets`] }) 49 | .then(model => model.toJSON().sets) 50 | } 51 | }) 52 | }) 53 | 54 | export const Queries = { 55 | format: { 56 | type: new GraphQLList(Definition), 57 | description: `Returns a Format.`, 58 | args: { 59 | id: { type: new GraphQLList(GraphQLID) }, 60 | filter: { 61 | type: Filter 62 | }, 63 | limit: { type: GraphQLInt }, 64 | offset: { type: GraphQLInt }, 65 | orderBy: { type: order(`format`, Fields) } 66 | }, 67 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 68 | } 69 | } 70 | 71 | export const Mutations = { 72 | createFormat: { 73 | type: Definition, 74 | description: `Creates a new Format`, 75 | args: { input: { type: Input } }, 76 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 77 | }, 78 | updateFormat: { 79 | type: Definition, 80 | description: `Updates an existing Format, creates it if it does not already exist`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 83 | }, 84 | deleteFormat: { 85 | type: Definition, 86 | description: `Deletes a Format by id`, 87 | args: { id: { type: GraphQLID } }, 88 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/types/icon.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Image } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `IconInput`, 8 | description: `Required fields for a new Icon object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | image: { type: GraphQLID }, 12 | class: { type: GraphQLString } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `IconFilter`, 18 | description: `Queryable fields for Icon.`, 19 | fields: () => ({ 20 | name: { type: new GraphQLList(GraphQLString) }, 21 | image: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `IconFields`, 27 | description: `Field names for Icon.`, 28 | values: { 29 | name: { value: `name` }, 30 | image: { value: `image` } 31 | } 32 | }) 33 | 34 | export const Definition = new GraphQLObjectType({ 35 | name: `Icon`, 36 | description: `An Icon object`, 37 | fields: () => ({ 38 | id: { 39 | type: GraphQLID, 40 | description: `A unique id for this icon.` 41 | }, 42 | name: { 43 | type: GraphQLString, 44 | description: `The name of the icon.` 45 | }, 46 | image: { 47 | type: Image.Definition, 48 | description: `The language image.`, 49 | resolve: (type) => Models.Icon 50 | .findById(type.id, { withRelated: [`image`] }) 51 | .then(model => model.toJSON().image) 52 | }, 53 | class: { 54 | type: GraphQLString, 55 | description: `A CSS class used to display this icon.` 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | icon: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns an Icon.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`icon`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createIcon: { 79 | type: Definition, 80 | description: `Creates a new Icon`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateIcon: { 85 | type: Definition, 86 | description: `Updates an existing Icon, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 89 | }, 90 | deleteIcon: { 91 | type: Definition, 92 | description: `Deletes a Icon by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/image.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { LanguageCode } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `ImageInput`, 8 | description: `Required fields for a new Name object`, 9 | fields: () => ({ 10 | multiverseid: { type: GraphQLString }, 11 | url: { type: new GraphQLNonNull(GraphQLString) }, 12 | language: { type: new GraphQLNonNull(GraphQLID) } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `ImageFilter`, 18 | description: `Queryable fields for Image.`, 19 | fields: () => ({ 20 | multiverseid: { type: new GraphQLList(GraphQLString) }, 21 | language: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `ImageFields`, 27 | description: `Field names for Image.`, 28 | values: { 29 | multiverseid: { value: `multiverseid` }, 30 | language: { value: `language` } 31 | } 32 | }) 33 | 34 | export const Definition = new GraphQLObjectType({ 35 | name: `Image`, 36 | description: `An Image object`, 37 | fields: () => ({ 38 | id: { 39 | type: GraphQLID, 40 | description: `A unique id for this image.` 41 | }, 42 | multiverseid: { 43 | type: GraphQLString, 44 | description: `The multiverseid of the card on Wizard’s Gatherer web page.` 45 | }, 46 | url: { 47 | type: GraphQLString, 48 | description: `The localized image of a card.` 49 | }, 50 | language: { 51 | type: LanguageCode.Definition, 52 | description: `The language image.`, 53 | resolve: (type) => Models.LanguageCode 54 | .findById(type.language) 55 | .then(model => model.toJSON()) 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | image: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns an Image.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`image`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createImage: { 79 | type: Definition, 80 | description: `Creates a new Image`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateImage: { 85 | type: Definition, 86 | description: `Updates an existing Image, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `multiverseid`) 89 | }, 90 | deleteImage: { 91 | type: Definition, 92 | description: `Deletes a Image by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/index.js: -------------------------------------------------------------------------------- 1 | import * as AbilityType from './abilityType' 2 | import * as Artist from './artist' 3 | import * as Block from './block' 4 | import * as Booster from './booster' 5 | import * as Card from './card' 6 | import * as Category from './category' 7 | import * as Color from './color' 8 | import * as ColorIdentity from './colorIdentity' 9 | import * as Format from './format' 10 | import * as Icon from './icon' 11 | import * as Image from './image' 12 | import * as Keyword from './keyword' 13 | import * as Language from './language' 14 | import * as LanguageCode from './languageCode' 15 | import * as Layout from './layout' 16 | import * as Legality from './legality' 17 | import * as Name from './name' 18 | import * as Printing from './printing' 19 | import * as Rarity from './rarity' 20 | import * as Ruling from './ruling' 21 | import * as Set from './set' 22 | import * as SetType from './setType' 23 | import * as Subtype from './subtype' 24 | import * as Supertype from './supertype' 25 | import * as Type from './type' 26 | 27 | export { 28 | AbilityType, 29 | Artist, 30 | Block, 31 | Booster, 32 | Card, 33 | Category, 34 | Color, 35 | ColorIdentity, 36 | Format, 37 | Icon, 38 | Image, 39 | Keyword, 40 | Language, 41 | LanguageCode, 42 | Layout, 43 | Legality, 44 | Name, 45 | Printing, 46 | Rarity, 47 | Ruling, 48 | Set, 49 | SetType, 50 | Subtype, 51 | Supertype, 52 | Type 53 | } 54 | -------------------------------------------------------------------------------- /src/types/keyword.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card, LanguageCode } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `KeywordInput`, 8 | description: `Required fields for a new Keyword object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | reminderText: { type: GraphQLString }, 12 | languageCode: { type: new GraphQLNonNull(GraphQLID) }, 13 | cards: { type: new GraphQLList(GraphQLID) } 14 | }) 15 | }) 16 | 17 | const Filter = new GraphQLInputObjectType({ 18 | name: `KeywordFilter`, 19 | description: `Queryable fields for Keyword.`, 20 | fields: () => ({ 21 | name: { type: new GraphQLList(GraphQLString) }, 22 | reminderText: { type: GraphQLString }, 23 | languageCode: { type: new GraphQLList(GraphQLID) }, 24 | cards: { type: new GraphQLList(GraphQLID) } 25 | }) 26 | }) 27 | 28 | const Fields = new GraphQLEnumType({ 29 | name: `KeywordFields`, 30 | description: `Field names for Keyword.`, 31 | values: { 32 | name: { value: `name` }, 33 | reminderText: { value: `reminderText` }, 34 | languageCode: { value: `languageCode` } 35 | } 36 | }) 37 | 38 | export const Definition = new GraphQLObjectType({ 39 | name: `Keyword`, 40 | description: `A Keyword object`, 41 | fields: () => ({ 42 | id: { 43 | type: GraphQLID, 44 | description: `A unique id for this keyword.` 45 | }, 46 | name: { 47 | type: GraphQLString, 48 | description: `The name of the keyword.` 49 | }, 50 | reminderText: { 51 | type: GraphQLString, 52 | description: `A short description of the keyword ability's rules.` 53 | }, 54 | languageCode: { 55 | type: LanguageCode.Definition, 56 | description: `The language code the reminder text of keyword is localized in.`, 57 | resolve: (root, { id }) => Models.Keyword 58 | .forge({ id }) 59 | .fetch({ withRelated: [`LanguageCode`] }) 60 | .then(model => model.toJSON().languageCode) 61 | }, 62 | cards: { 63 | type: new GraphQLList(Card.Definition), 64 | description: `A list of cards featuring art from this artist.`, 65 | resolve: (root, { id }) => Models.Keyword 66 | .forge({ id }) 67 | .fetch({ withRelated: [`cards`] }) 68 | .then(model => model.toJSON().cards) 69 | } 70 | }) 71 | }) 72 | 73 | export const Queries = { 74 | keyword: { 75 | type: new GraphQLList(Definition), 76 | description: `Returns a Keyword.`, 77 | args: { 78 | id: { type: new GraphQLList(GraphQLID) }, 79 | filter: { 80 | type: Filter 81 | }, 82 | limit: { type: GraphQLInt }, 83 | offset: { type: GraphQLInt }, 84 | orderBy: { type: order(`keyword`, Fields) } 85 | }, 86 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 87 | } 88 | } 89 | 90 | export const Mutations = { 91 | createKeyword: { 92 | type: Definition, 93 | description: `Creates a new Keyword`, 94 | args: { input: { type: Input } }, 95 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 96 | }, 97 | updateKeyword: { 98 | type: Definition, 99 | description: `Updates an existing Keyword, creates it if it does not already exist`, 100 | args: { input: { type: Input } }, 101 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 102 | }, 103 | deleteKeyword: { 104 | type: Definition, 105 | description: `Deletes a Keyword by id`, 106 | args: { id: { type: GraphQLID } }, 107 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/types/language.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { LanguageCode } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `LanguageInput`, 8 | description: `Required fields for a new language object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | code: { type: new GraphQLNonNull(GraphQLID) } 12 | }) 13 | }) 14 | 15 | const Filter = new GraphQLInputObjectType({ 16 | name: `LanguageFilter`, 17 | description: `Queryable fields for Language.`, 18 | fields: () => ({ 19 | name: { type: new GraphQLList(GraphQLString) }, 20 | code: { type: new GraphQLList(GraphQLID) } 21 | }) 22 | }) 23 | 24 | const Fields = new GraphQLEnumType({ 25 | name: `LanguageFields`, 26 | description: `Field names for Language.`, 27 | values: { 28 | name: { value: `name` }, 29 | code: { value: `code` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `Language`, 35 | description: `A language object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this language.` 40 | }, 41 | name: { 42 | type: GraphQLString, 43 | description: `The name of the language.` 44 | }, 45 | code: { 46 | type: LanguageCode.Definition, 47 | description: `The language code associated with this language.`, 48 | resolve: (type) => Models.LanguageCode 49 | .findById(type.code) 50 | .then(model => model.toJSON()) 51 | } 52 | }) 53 | }) 54 | 55 | export const Queries = { 56 | language: { 57 | type: new GraphQLList(Definition), 58 | description: `Returns a Language.`, 59 | args: { 60 | id: { type: new GraphQLList(GraphQLID) }, 61 | filter: { 62 | type: Filter 63 | }, 64 | limit: { type: GraphQLInt }, 65 | offset: { type: GraphQLInt }, 66 | orderBy: { type: order(`language`, Fields) } 67 | }, 68 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 69 | } 70 | } 71 | 72 | export const Mutations = { 73 | createLanguage: { 74 | type: Definition, 75 | description: `Creates a new Language`, 76 | args: { input: { type: Input } }, 77 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 78 | }, 79 | updateLanguage: { 80 | type: Definition, 81 | description: `Updates an existing Language, creates it if it does not already exist`, 82 | args: { input: { type: Input } }, 83 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 84 | }, 85 | deleteLanguage: { 86 | type: Definition, 87 | description: `Deletes a Language by id`, 88 | args: { id: { type: GraphQLID } }, 89 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/types/languageCode.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Language } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `LanguageCodeInput`, 8 | description: `Required fields for a new language code object`, 9 | fields: () => ({ 10 | code: { type: new GraphQLNonNull(GraphQLString) }, 11 | language: { type: new GraphQLNonNull(GraphQLID) } 12 | }) 13 | }) 14 | 15 | const Filter = new GraphQLInputObjectType({ 16 | name: `LanguageCodeFilter`, 17 | description: `Queryable fields for LanguageCode.`, 18 | fields: () => ({ 19 | code: { type: new GraphQLList(GraphQLString) }, 20 | language: { type: new GraphQLList(GraphQLID) } 21 | }) 22 | }) 23 | 24 | const Fields = new GraphQLEnumType({ 25 | name: `LanguageCodeFields`, 26 | description: `Field names for LanguageCode.`, 27 | values: { 28 | code: { value: `code` }, 29 | language : { value: `language` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `LanguageCode`, 35 | description: `A language code object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this language.` 40 | }, 41 | code: { 42 | type: GraphQLString, 43 | description: `The language code.` 44 | }, 45 | language: { 46 | type: Language.Definition, 47 | description: `The language associated with the language code.`, 48 | resolve: (type) => Models.Language 49 | .findById(type.language) 50 | .then(model => model.toJSON()) 51 | } 52 | }) 53 | }) 54 | 55 | export const Queries = { 56 | languageCode: { 57 | type: new GraphQLList(Definition), 58 | description: `Returns a LanguageCode.`, 59 | args: { 60 | id: { type: new GraphQLList(GraphQLID) }, 61 | filter: { 62 | type: Filter 63 | }, 64 | limit: { type: GraphQLInt }, 65 | offset: { type: GraphQLInt }, 66 | orderBy: { type: order(`languageCode`, Fields) } 67 | }, 68 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 69 | } 70 | } 71 | 72 | export const Mutations = { 73 | createLanguageCode: { 74 | type: Definition, 75 | description: `Creates a new LanguageCode`, 76 | args: { input: { type: Input } }, 77 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 78 | }, 79 | updateLanguageCode: { 80 | type: Definition, 81 | description: `Updates an existing LanguageCode, creates it if it does not already exist`, 82 | args: { input: { type: Input } }, 83 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `code`) 84 | }, 85 | deleteLanguageCode: { 86 | type: Definition, 87 | description: `Deletes a LanguageCode by id`, 88 | args: { id: { type: GraphQLID } }, 89 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/types/layout.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Icon } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `LayoutInput`, 8 | description: `Required fields for a new Layout object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | watermark: { type: GraphQLString }, 12 | icons: { type: new GraphQLList(GraphQLID) } 13 | }) 14 | }) 15 | 16 | const Filter = new GraphQLInputObjectType({ 17 | name: `LayoutFilter`, 18 | description: `Queryable fields for Layout.`, 19 | fields: () => ({ 20 | name: { type: new GraphQLList(GraphQLString) }, 21 | icons: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `LayoutFields`, 27 | description: `Field names for Layout.`, 28 | values: { 29 | name: { value: `name` } 30 | } 31 | }) 32 | 33 | export const Definition = new GraphQLObjectType({ 34 | name: `Layout`, 35 | description: `A Layout object`, 36 | fields: () => ({ 37 | id: { 38 | type: GraphQLID, 39 | description: `A unique id for this layout.` 40 | }, 41 | name: { 42 | type: GraphQLString, 43 | description: `The name of the layout type.` 44 | }, 45 | watermark: { 46 | type: GraphQLString, 47 | description: `Watermark that appears in this layout.` 48 | }, 49 | icons: { 50 | type: new GraphQLList(Icon.Definition), 51 | description: `A list of icons featured on this card.`, 52 | resolve: (root, { id }) => Models.Layout 53 | .forge({ id }) 54 | .fetch({ withRelated: [`icons`] }) 55 | .then(model => model.toJSON().icons) 56 | } 57 | }) 58 | }) 59 | 60 | export const Queries = { 61 | layout: { 62 | type: new GraphQLList(Definition), 63 | description: `Returns a Layout.`, 64 | args: { 65 | id: { type: new GraphQLList(GraphQLID) }, 66 | filter: { 67 | type: Filter 68 | }, 69 | limit: { type: GraphQLInt }, 70 | offset: { type: GraphQLInt }, 71 | orderBy: { type: order(`layout`, Fields) } 72 | }, 73 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 74 | } 75 | } 76 | 77 | export const Mutations = { 78 | createLayout: { 79 | type: Definition, 80 | description: `Creates a new Layout`, 81 | args: { input: { type: Input } }, 82 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 83 | }, 84 | updateLayout: { 85 | type: Definition, 86 | description: `Updates an existing Layout, creates it if it does not already exist`, 87 | args: { input: { type: Input } }, 88 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 89 | }, 90 | deleteLayout: { 91 | type: Definition, 92 | description: `Deletes a Layout by id`, 93 | args: { id: { type: GraphQLID } }, 94 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/types/legality.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLBoolean, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card, Format } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `LegalityInput`, 8 | description: `Required fields for a new Legality object`, 9 | fields: () => ({ 10 | cards: { type: new GraphQLNonNull(new GraphQLList(GraphQLID)) }, 11 | format: { type: new GraphQLNonNull(GraphQLID) }, 12 | legal: { type: new GraphQLNonNull(GraphQLBoolean) }, 13 | restricted: { type: new GraphQLNonNull(GraphQLBoolean) } 14 | }) 15 | }) 16 | 17 | const Filter = new GraphQLInputObjectType({ 18 | name: `LegalityFilter`, 19 | description: `Queryable fields for Legality.`, 20 | fields: () => ({ 21 | cards: { type: new GraphQLList(GraphQLID) }, 22 | format: { type: new GraphQLList(GraphQLID) }, 23 | legal: { type: GraphQLBoolean }, 24 | restricted: { type: GraphQLBoolean } 25 | }) 26 | }) 27 | 28 | const Fields = new GraphQLEnumType({ 29 | name: `LegalityFields`, 30 | description: `Field names for Legality.`, 31 | values: { 32 | format: { value: `format` }, 33 | legal: { value: `legal` }, 34 | restricted: { value: `restricted` } 35 | } 36 | }) 37 | 38 | export const Definition = new GraphQLObjectType({ 39 | name: `Legality`, 40 | description: `A Legality object`, 41 | fields: () => ({ 42 | id: { 43 | type: GraphQLID, 44 | description: `A unique id for this name.` 45 | }, 46 | cards: { 47 | type: new GraphQLList(Card.Definition), 48 | description: `The ID of the card.`, 49 | resolve: (root, { id }) => Models.Legality 50 | .forge({ id }) 51 | .fetch({ withRelated: [`cards`] }) 52 | .then(model => model.toJSON().cards) 53 | }, 54 | format: { 55 | type: Format.Definition, 56 | description: `The format the card is legal in.`, 57 | resolve: (root, { id }) => Models.Legality 58 | .forge({ id }) 59 | .fetch({ withRelated: [`format`] }) 60 | .then(model => model.toJSON().format) 61 | }, 62 | legal: { 63 | type: GraphQLBoolean, 64 | description: `Set to True if the card is Legal to play in the given format.` 65 | }, 66 | restricted: { 67 | type: GraphQLBoolean, 68 | description: `Set to True if the card is restricted in the given format.` 69 | } 70 | }) 71 | }) 72 | 73 | export const Queries = { 74 | legality: { 75 | type: new GraphQLList(Definition), 76 | description: `Returns a Legality.`, 77 | args: { 78 | id: { type: new GraphQLList(GraphQLID) }, 79 | filter: { 80 | type: Filter 81 | }, 82 | limit: { type: GraphQLInt }, 83 | offset: { type: GraphQLInt }, 84 | orderBy: { type: order(`legality`, Fields) } 85 | }, 86 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 87 | } 88 | } 89 | 90 | export const Mutations = { 91 | createLegality: { 92 | type: Definition, 93 | description: `Creates a new Legality`, 94 | args: { input: { type: Input } }, 95 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 96 | }, 97 | updateLegality: { 98 | type: Definition, 99 | description: `Updates an existing Legality, creates it if it does not already exist`, 100 | args: { input: { type: Input } }, 101 | resolve: (parent, args, context) => update(parent, args, context, Definition.name) 102 | }, 103 | deleteLegality: { 104 | type: Definition, 105 | description: `Deletes a Legality by id`, 106 | args: { id: { type: GraphQLID } }, 107 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/types/name.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | import Models from '../models' 4 | import { Card, Language } from './' 5 | 6 | export const Input = new GraphQLInputObjectType({ 7 | name: `NameInput`, 8 | description: `Required fields for a new Name object`, 9 | fields: () => ({ 10 | name: { type: new GraphQLNonNull(GraphQLString) }, 11 | language: { type: new GraphQLNonNull(GraphQLID) } 12 | }) 13 | }) 14 | 15 | const Filter = new GraphQLInputObjectType({ 16 | name: `NameFilter`, 17 | description: `Queryable fields for Name.`, 18 | fields: () => ({ 19 | name: { type: new GraphQLList(GraphQLString) }, 20 | language: { type: new GraphQLList(GraphQLID) }, 21 | cards: { type: new GraphQLList(GraphQLID) } 22 | }) 23 | }) 24 | 25 | const Fields = new GraphQLEnumType({ 26 | name: `NameFields`, 27 | description: `Field names for Name.`, 28 | values: { 29 | name: { value: `name` }, 30 | language: { value: `language` } 31 | } 32 | }) 33 | 34 | export const Definition = new GraphQLObjectType({ 35 | name: `Name`, 36 | description: `A Name object`, 37 | fields: () => ({ 38 | id: { 39 | type: GraphQLID, 40 | description: `A unique id for this name.` 41 | }, 42 | name: { 43 | type: GraphQLString, 44 | description: `The localized name of a card.` 45 | }, 46 | language: { 47 | type: Language.Definition, 48 | description: `The language name.`, 49 | resolve: (type) => Models.Language 50 | .findById(type.language) 51 | .then(model => model.toJSON()) 52 | }, 53 | cards: { 54 | type: new GraphQLList(Card.Definition), 55 | description: `A list of cards featuring art from this artist.`, 56 | resolve: (type) => Models.Name 57 | .findById(type.id, { withRelated: [`cards`] }) 58 | .then(model => model.toJSON().cards) 59 | } 60 | }) 61 | }) 62 | 63 | export const Queries = { 64 | name: { 65 | type: new GraphQLList(Definition), 66 | description: `Returns a Name.`, 67 | args: { 68 | id: { type: new GraphQLList(GraphQLID) }, 69 | filter: { 70 | type: Filter 71 | }, 72 | limit: { type: GraphQLInt }, 73 | offset: { type: GraphQLInt }, 74 | orderBy: { type: order(`name`, Fields) } 75 | }, 76 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 77 | } 78 | } 79 | 80 | export const Mutations = { 81 | createName: { 82 | type: Definition, 83 | description: `Creates a new Name`, 84 | args: { input: { type: Input } }, 85 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 86 | }, 87 | updateName: { 88 | type: Definition, 89 | description: `Updates an existing Name, creates it if it does not already exist`, 90 | args: { input: { type: Input } }, 91 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 92 | }, 93 | deleteName: { 94 | type: Definition, 95 | description: `Deletes a Name by id`, 96 | args: { id: { type: GraphQLID } }, 97 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/types/printing.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLNonNull, GraphQLInt, GraphQLEnumType, GraphQLString, GraphQLBoolean, GraphQLList, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { destroy, order, read } from './utilities' 3 | import { info, error } from 'winston' 4 | import Models from '../models' 5 | import { Card, Set, Image, Artist } from './' 6 | 7 | export const Input = new GraphQLInputObjectType({ 8 | name: `PrintingInput`, 9 | description: `Required fields for a new Printing object`, 10 | fields: () => ({ 11 | card: { type: GraphQLID }, 12 | set: { type: GraphQLID }, 13 | images: { type: new GraphQLList(GraphQLID) }, 14 | sides: { type: new GraphQLList(GraphQLID) }, 15 | variations: { type: new GraphQLList(GraphQLID) }, 16 | originalType: { type: GraphQLString }, 17 | originalText: { type: GraphQLString }, 18 | flavor: { type: GraphQLString }, 19 | artist: { type: new GraphQLNonNull(GraphQLID) }, 20 | number: { type: GraphQLString }, 21 | timeshifted: { type: GraphQLBoolean }, 22 | starter: { type: GraphQLBoolean }, 23 | reserved: { type: GraphQLBoolean }, 24 | source: { type: GraphQLString } 25 | }) 26 | }) 27 | 28 | const Filter = new GraphQLInputObjectType({ 29 | name: `PrintingFilter`, 30 | description: `Queryable fields for Printing.`, 31 | fields: () => ({ 32 | card: { type: new GraphQLList(GraphQLID) }, 33 | set: { type: new GraphQLList(GraphQLID) }, 34 | originalType: { type: GraphQLString }, 35 | originalText: { type: GraphQLString }, 36 | flavor: { type: GraphQLString }, 37 | artist: { type: new GraphQLList(GraphQLID) }, 38 | number: { type: new GraphQLList(GraphQLString) }, 39 | timeshifted: { type: GraphQLBoolean }, 40 | starter: { type: GraphQLBoolean }, 41 | reserved: { type: GraphQLBoolean } 42 | }) 43 | }) 44 | 45 | const Fields = new GraphQLEnumType({ 46 | name: `PrintingFields`, 47 | description: `Field names for Printing.`, 48 | values: { 49 | card: { value: `card` }, 50 | set: { value: `set` }, 51 | originalType: { type: `originalType`}, 52 | originalText: { value: `originalText` }, 53 | artist: { value: `artist` }, 54 | number: { value: `number` }, 55 | timeshifted: { value: `timeshifted` }, 56 | starter: { value: `starter` }, 57 | reserved: { value: `reserved` } 58 | } 59 | }) 60 | 61 | export const Definition = new GraphQLObjectType({ 62 | name: `Printing`, 63 | description: `A Printing object`, 64 | fields: () => ({ 65 | id: { 66 | type: GraphQLID, 67 | description: `A unique id for this card.` 68 | }, 69 | card: { 70 | type: Card.Definition, 71 | description: `The Card represented by this Printing.`, 72 | resolve: (type) => Models.Card 73 | .findById(type.card) 74 | .then(model => model.toJSON()) 75 | }, 76 | set: { 77 | type: Set.Definition, 78 | description: `The set the card belongs to (set code).`, 79 | resolve: (type) => Models.Set 80 | .findById(type.set) 81 | .then(model => model.toJSON()) 82 | }, 83 | images: { 84 | type: new GraphQLList(Image.Definition), 85 | description: `The card images. This includes a list of foreign images indexed by a language code. Example: enUS`, 86 | resolve: (type) => Models.Printing 87 | .findById(type.id, { withRelated: [`images`] }) 88 | .then(model => model.toJSON().images) 89 | }, 90 | artist: { 91 | type: Artist.Definition, 92 | description: `The artist of the image. This may not match what is on the card as MTGJSON corrects many card misprints.`, 93 | resolve: (type) => Models.Artist 94 | .findById(type.artist) 95 | .then(model => model.toJSON()) 96 | }, 97 | sides: { 98 | type: new GraphQLList(Definition), 99 | description: `Only used for split, flip and dual cards. Will contain a lit of cards representing each side of this card, front or back.`, 100 | resolve: (type) => Models.Card 101 | .findById(type.id, { withRelated: [`sides`] }) 102 | .then(model => model.toJSON().sides) 103 | }, 104 | variations: { 105 | type: new GraphQLList(Definition), 106 | description: `If a card has alternate art (for example, 4 different Forests, or the 2 Brothers Yamazaki) then each other variation’s card will be listed here, NOT including the current card.`, 107 | resolve: (type) => Models.Card 108 | .findById(type.id, { withRelated: [`variations`] }) 109 | .then(model => model.toJSON().variations) 110 | }, 111 | originalType: { 112 | type: GraphQLString, 113 | description: `The original type on the card at the time it was printed. This field is not available for promo cards.` 114 | }, 115 | originalText: { 116 | type: GraphQLString, 117 | description: `The original text on the card at the time it was printed. This field is not available for promo cards.` 118 | }, 119 | flavor: { 120 | type: GraphQLString, 121 | description: `The flavor text of the card.` 122 | }, 123 | number: { 124 | type: GraphQLString, 125 | description: `The card number. This is printed at the bottom-center of the card in small text. This is a string, not an integer, because some cards have letters in their numbers.` 126 | }, 127 | timeshifted: { 128 | type: GraphQLBoolean, 129 | description: `If this card was a timeshifted card in the set.` 130 | }, 131 | starter: { 132 | type: GraphQLBoolean, 133 | description: `Set to true if this card was only released as part of a core box set. These are technically part of the core sets and are tournament legal despite not being available in boosters.` 134 | }, 135 | reserved: { 136 | type: GraphQLBoolean, 137 | description: `Set to true if this card is reserved by Wizards Official Reprint Policy` 138 | }, 139 | source: { 140 | type: GraphQLString, 141 | description: `For promo cards, this is where this card was originally obtained. For box sets that are theme decks, this is which theme deck the card is from.` 142 | } 143 | }) 144 | }) 145 | 146 | export const Queries = { 147 | printing: { 148 | type: new GraphQLList(Definition), 149 | description: `Returns a Printing.`, 150 | args: { 151 | id: { type: new GraphQLList(GraphQLID) }, 152 | filter: { 153 | type: Filter 154 | }, 155 | limit: { type: GraphQLInt }, 156 | offset: { type: GraphQLInt }, 157 | orderBy: { type: order(`printing`, Fields) } 158 | }, 159 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 160 | } 161 | } 162 | 163 | export const Mutations = { 164 | createPrinting: { 165 | type: Definition, 166 | description: `Creates a new Printing`, 167 | args: { input: { type: Input } }, 168 | resolve: (parent, { input }, context) => { 169 | let { images, sides, variations, ...fields } = input 170 | return Models.Printing 171 | .findOrCreate(fields) 172 | .then(model => { 173 | let printing = model.toJSON() 174 | 175 | if (!!images) for (let image of images) Models.Images.findOrCreate({ printing: printing.id, image }) 176 | 177 | Models.Printings.findOrCreate({ card: printing.card, printing: printing.id }) 178 | 179 | return printing 180 | }) 181 | .catch(err => error(`Failed to run Mutation: create${Definition.name}`, err)) 182 | .finally(info(`Resolved Mutation: create${Definition.name}`, { parent, input, context})) 183 | } 184 | }, 185 | updatePrinting: { 186 | type: Definition, 187 | description: `Updates an existing Printing, creates it if it does not already exist`, 188 | args: { input: { type: Input } }, 189 | resolve: (parent, { input }, context) => { 190 | const { card, set, number, images, sides, variations, ...fields } = input 191 | return Models.Printing 192 | .upsert({ card, set, number }, fields) 193 | .then(model => { 194 | let printing = model.toJSON() 195 | //console.log(model) 196 | if (!!images) for (let image of images) Models.Images.findOrCreate({ printing: printing.id, image }) 197 | 198 | Models.Printings.findOrCreate({ card: printing.card, printing: printing.id }) 199 | 200 | return printing 201 | }) 202 | .catch(err => error(`Failed to run Mutation: update${Definition.name}`, err)) 203 | .finally(info(`Resolved Mutation: update${Definition.name}`, { parent, input, context})) 204 | } 205 | }, 206 | deleteCard: { 207 | type: Definition, 208 | description: `Deletes a Card by id`, 209 | args: { id: { type: GraphQLID } }, 210 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/types/rarity.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `RarityInput`, 6 | description: `Required fields for a new Rarity object`, 7 | fields: () => ({ 8 | name: { type: new GraphQLNonNull(GraphQLString) }, 9 | class: { type: new GraphQLNonNull(GraphQLString) } 10 | }) 11 | }) 12 | 13 | const Filter = new GraphQLInputObjectType({ 14 | name: `RarityFilter`, 15 | description: `Queryable fields for Rarity.`, 16 | fields: () => ({ 17 | name: { type: new GraphQLList(GraphQLString) } 18 | }) 19 | }) 20 | 21 | const Fields = new GraphQLEnumType({ 22 | name: `RarityFields`, 23 | description: `Field names for Rarity.`, 24 | values: { 25 | name: { value: `name` } 26 | } 27 | }) 28 | 29 | export const Definition = new GraphQLObjectType({ 30 | name: `Rarity`, 31 | description: `A Rarity object`, 32 | fields: () => ({ 33 | id: { 34 | type: GraphQLID, 35 | description: `A unique id for this rarity.` 36 | }, 37 | name: { 38 | type: GraphQLString, 39 | description: `The name of the rarity.` 40 | }, 41 | class: { 42 | type: GraphQLString, 43 | description: `A CSS class used to display this rarity.` 44 | } 45 | }) 46 | }) 47 | 48 | export const Queries = { 49 | rarity: { 50 | type: new GraphQLList(Definition), 51 | description: `Returns a Rarity.`, 52 | args: { 53 | id: { type: new GraphQLList(GraphQLID) }, 54 | filter: { 55 | type: Filter 56 | }, 57 | limit: { type: GraphQLInt }, 58 | offset: { type: GraphQLInt }, 59 | orderBy: { type: order(`rarity`, Fields) } 60 | }, 61 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 62 | } 63 | } 64 | 65 | export const Mutations = { 66 | createRarity: { 67 | type: Definition, 68 | description: `Creates a new Rarity`, 69 | args: { input: { type: Input } }, 70 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 71 | }, 72 | updateRarity: { 73 | type: Definition, 74 | description: `Updates an existing Rarity, creates it if it does not already exist`, 75 | args: { input: { type: Input } }, 76 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 77 | }, 78 | deleteRarity: { 79 | type: Definition, 80 | description: `Deletes a Rarity by id`, 81 | args: { id: { type: GraphQLID } }, 82 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/types/ruling.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { GraphQLDate } from 'graphql-iso-date' 3 | import { create, destroy, order, read, update } from './utilities' 4 | import Models from '../models' 5 | import { Card, LanguageCode } from './' 6 | 7 | export const Input = new GraphQLInputObjectType({ 8 | name: `RulingInput`, 9 | description: `Required fields for a new Ruling object`, 10 | fields: () => ({ 11 | text: { type: new GraphQLNonNull(GraphQLString) }, 12 | date: { type: new GraphQLNonNull(GraphQLDate) }, 13 | language: { type: new GraphQLNonNull(GraphQLID) }, 14 | cards: { type: new GraphQLNonNull(new GraphQLList(GraphQLID)) } 15 | }) 16 | }) 17 | 18 | const Filter = new GraphQLInputObjectType({ 19 | name: `RulingFilter`, 20 | description: `Queryable fields for Ruling.`, 21 | fields: () => ({ 22 | text: { type: GraphQLString }, 23 | date: { type: new GraphQLList(GraphQLDate) }, 24 | language: { type: new GraphQLList(GraphQLID) }, 25 | cards: { type: new GraphQLList(GraphQLID) } 26 | }) 27 | }) 28 | 29 | const Fields = new GraphQLEnumType({ 30 | name: `RulingFields`, 31 | description: `Field names for Ruling.`, 32 | values: { 33 | date: { value: `date` }, 34 | language: { value: `language` } 35 | } 36 | }) 37 | 38 | export const Definition = new GraphQLObjectType({ 39 | name: `Ruling`, 40 | description: `A Ruling object`, 41 | fields: () => ({ 42 | id: { 43 | type: GraphQLID, 44 | description: `A unique id for this ruling.` 45 | }, 46 | text: { 47 | type: GraphQLString, 48 | description: `The text of the ruling.` 49 | }, 50 | date: { 51 | type: GraphQLDate, 52 | description: `The date this ruling was issued.` 53 | }, 54 | language: { 55 | type: LanguageCode.Definition, 56 | description: `The language code of this ruling.`, 57 | resolve: (root, { id }) => Models.Ruling 58 | .forge({ id }) 59 | .fetch({ withRelated: [`language`] }) 60 | .then(model => model.toJSON().language) 61 | }, 62 | cards: { 63 | type: new GraphQLList(Card.Definition), 64 | description: `List of cards that have this ruling.`, 65 | resolve: (root, { id }) => Models.Ruling 66 | .forge({ id }) 67 | .fetch({ withRelated: [`cards`] }) 68 | .then(model => model.toJSON().cards) 69 | } 70 | }) 71 | }) 72 | 73 | export const Queries = { 74 | ruling: { 75 | type: new GraphQLList(Definition), 76 | description: `Returns a Ruling.`, 77 | args: { 78 | id: { type: new GraphQLList(GraphQLID) }, 79 | filter: { 80 | type: Filter 81 | }, 82 | limit: { type: GraphQLInt }, 83 | offset: { type: GraphQLInt }, 84 | orderBy: { type: order(`ruling`, Fields) } 85 | }, 86 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 87 | } 88 | } 89 | 90 | export const Mutations = { 91 | createRuling: { 92 | type: Definition, 93 | description: `Creates a new Ruling`, 94 | args: { input: { type: Input } }, 95 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 96 | }, 97 | updateRuling: { 98 | type: Definition, 99 | description: `Updates an existing Ruling, creates it if it does not already exist`, 100 | args: { input: { type: Input } }, 101 | resolve: (parent, args, context) => update(parent, args, context, Definition.name) 102 | }, 103 | deleteRuling: { 104 | type: Definition, 105 | description: `Deletes a Ruling by id`, 106 | args: { id: { type: GraphQLID } }, 107 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/types/set.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { GraphQLDate } from 'graphql-iso-date' 3 | import { destroy, order, read } from './utilities' 4 | import { info, error } from 'winston' 5 | import Models from '../models' 6 | import { Block, SetType, Icon, Booster } from './' 7 | 8 | export const Input = new GraphQLInputObjectType({ 9 | name: `SetInput`, 10 | description: `Required fields for a new Set object`, 11 | fields: () => ({ 12 | name: { type: new GraphQLNonNull(GraphQLString) }, 13 | code: { type: new GraphQLNonNull(GraphQLString) }, 14 | block: { type: GraphQLID }, 15 | type: { type: new GraphQLNonNull(GraphQLID)}, 16 | icon: { type: new GraphQLNonNull(GraphQLID) }, 17 | border: { type: new GraphQLNonNull(GraphQLString) }, 18 | releaseDate: { type: new GraphQLNonNull(GraphQLDate) }, 19 | booster: { type: GraphQLID } 20 | }) 21 | }) 22 | 23 | const Filter = new GraphQLInputObjectType({ 24 | name: `SetFilter`, 25 | description: `Queryable fields for Set.`, 26 | fields: () => ({ 27 | name: { type: new GraphQLList(GraphQLString) }, 28 | code: { type: new GraphQLList(GraphQLString) }, 29 | block: { type: new GraphQLList(GraphQLID) }, 30 | type: { type: new GraphQLList(GraphQLID) }, 31 | border: { type: new GraphQLList(GraphQLString) }, 32 | releaseDate: { type: new GraphQLList(GraphQLDate) } 33 | }) 34 | }) 35 | 36 | const Fields = new GraphQLEnumType({ 37 | name: `SetFields`, 38 | description: `Field names for Set.`, 39 | values: { 40 | name: { value: `name` }, 41 | code: { value: `code` }, 42 | block: { value: `block` }, 43 | type: { value: `type` }, 44 | border: { value: `border` }, 45 | releaseDate: { value: `releaseDate` } 46 | } 47 | }) 48 | 49 | export const Definition = new GraphQLObjectType({ 50 | name: `Set`, 51 | description: `A Set object`, 52 | fields: () => ({ 53 | id: { 54 | type: GraphQLID, 55 | description: `A unique id for this set.` 56 | }, 57 | name: { 58 | type: GraphQLString, 59 | description: `The set name.` 60 | }, 61 | code: { 62 | type: GraphQLString, 63 | description: `The set code for this set.` 64 | }, 65 | block: { 66 | type: Block.Definition, 67 | description: `The block the set belongs to.`, 68 | resolve: (type) => Models.Set 69 | .findById(type.id, { withRelated: [`block`] }) 70 | .then(model => model.toJSON().block) 71 | }, 72 | type: { 73 | type: SetType.Definition, 74 | description: `The set type.`, 75 | resolve: (type) => Models.SetType 76 | .findById(type.type) 77 | .then(model => model.toJSON()) 78 | }, 79 | icon: { 80 | type: Icon.Definition, 81 | description: `The icon associated with the set.`, 82 | resolve: (type) => Models.Icon 83 | .findById(type.icon) 84 | .then(model => model.toJSON()) 85 | }, 86 | border: { 87 | type: GraphQLString, 88 | description: `The card border color for this set.` 89 | }, 90 | releaseDate: { 91 | type: GraphQLDate, 92 | description: `The date this card was released. This is only set for promo cards. The date may not be accurate to an exact day and month, thus only a partial date may be set (YYYY-MM-DD or YYYY-MM or YYYY). Some promo cards do not have a known release date.` 93 | }, 94 | booster: { 95 | type: Booster.Definition, 96 | description: `A booster pack for this set`, 97 | resolve: (type) => Models.Booster 98 | .findById(type.booster) 99 | .then(model => model.toJSON()) 100 | } 101 | }) 102 | }) 103 | 104 | export const Queries = { 105 | set: { 106 | type: new GraphQLList(Definition), 107 | description: `Returns a Set.`, 108 | args: { 109 | id: { type: new GraphQLList(GraphQLID) }, 110 | filter: { 111 | type: Filter 112 | }, 113 | limit: { type: GraphQLInt }, 114 | offset: { type: GraphQLInt }, 115 | orderBy: { type: order(`set`, Fields) } 116 | }, 117 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 118 | } 119 | } 120 | 121 | export const Mutations = { 122 | createSet: { 123 | type: Definition, 124 | description: `Creates a new Set`, 125 | args: { input: { type: Input } }, 126 | resolve: (parent, { input }, context) => Models.Set 127 | .findOrCreate(input) 128 | .then(model => { 129 | let set = model.toJSON() 130 | 131 | if (!!set.block) Models.BlockSets.findOrCreate({ block: set.block, set: set.id }) 132 | 133 | return set 134 | }) 135 | .catch(err => error(`Failed to run Mutation: create${Definition.name}`, err)) 136 | .finally(info(`Resolved Mutation: create${Definition.name}`, { parent, input, context})) 137 | }, 138 | updateSet: { 139 | type: Definition, 140 | description: `Updates an existing Set, creates it if it does not already exist`, 141 | args: { input: { type: Input } }, 142 | resolve: (parent, { input }, context) => { 143 | const { name, ...fields } = input 144 | return Models.Set 145 | .upsert({ name }, { ...fields }) 146 | .then(model => { 147 | let set = model.toJSON() 148 | 149 | if (!!set.block) Models.BlockSets.findOrCreate({ block: set.block, set: set.id }) 150 | 151 | return set 152 | }) 153 | .catch(err => error(`Failed to run Mutation: update${Definition.name}`, err)) 154 | .finally(info(`Resolved Mutation: update${Definition.name}`, { parent, input, context})) 155 | } 156 | }, 157 | deleteSet: { 158 | type: Definition, 159 | description: `Deletes a Set by id`, 160 | args: { id: { type: GraphQLID } }, 161 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/types/setType.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `SetTypeInput`, 6 | description: `Required fields for a new Set Type object`, 7 | fields: () => ({ 8 | name: { type: new GraphQLNonNull(GraphQLString) }, 9 | description: { type: GraphQLString } 10 | }) 11 | }) 12 | 13 | const Filter = new GraphQLInputObjectType({ 14 | name: `SetTypeFilter`, 15 | description: `Queryable fields for SetType.`, 16 | fields: () => ({ 17 | name: { type: new GraphQLList(GraphQLString) } 18 | }) 19 | }) 20 | 21 | const Fields = new GraphQLEnumType({ 22 | name: `SetTypeFields`, 23 | description: `Field names for SetType.`, 24 | values: { 25 | name: { value: `name` } 26 | } 27 | }) 28 | 29 | export const Definition = new GraphQLObjectType({ 30 | name: `SetType`, 31 | description: `A Set Type object`, 32 | fields: () => ({ 33 | id: { 34 | type: GraphQLID, 35 | description: `A unique id for this Set Type.` 36 | }, 37 | name: { 38 | type: GraphQLString, 39 | description: `The Set Type name.` 40 | }, 41 | description: { 42 | type: GraphQLString, 43 | description: `The description of the Set Type.` 44 | } 45 | }) 46 | }) 47 | 48 | export const Queries = { 49 | setType: { 50 | type: new GraphQLList(Definition), 51 | description: `Returns a Set Type.`, 52 | args: { 53 | id: { type: new GraphQLList(GraphQLID) }, 54 | filter: { 55 | type: Filter 56 | }, 57 | limit: { type: GraphQLInt }, 58 | offset: { type: GraphQLInt }, 59 | orderBy: { type: order(`setType`, Fields) } 60 | }, 61 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 62 | } 63 | } 64 | 65 | export const Mutations = { 66 | createSetType: { 67 | type: Definition, 68 | description: `Creates a new SetType`, 69 | args: { input: { type: Input } }, 70 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 71 | }, 72 | updateSetType: { 73 | type: Definition, 74 | description: `Updates an existing SetType, creates it if it does not already exist`, 75 | args: { input: { type: Input } }, 76 | resolve: (parent, args, context) => update(parent, args, context, Definition.name, `name`) 77 | }, 78 | deleteSetType: { 79 | type: Definition, 80 | description: `Deletes a SetType by id`, 81 | args: { id: { type: GraphQLID } }, 82 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/types/subtype.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `SubtypeInput`, 6 | description: `Required fields for a new Subtype object`, 7 | fields: () => ({ 8 | name: { type: new GraphQLNonNull(GraphQLString) } 9 | }) 10 | }) 11 | 12 | const Filter = new GraphQLInputObjectType({ 13 | name: `SubtypeFilter`, 14 | description: `Queryable fields for Subtype.`, 15 | fields: () => ({ 16 | name: { type: new GraphQLList(GraphQLString) } 17 | }) 18 | }) 19 | 20 | const Fields = new GraphQLEnumType({ 21 | name: `SubtypeFields`, 22 | description: `Field names for Subtype.`, 23 | values: { 24 | name: { value: `name` } 25 | } 26 | }) 27 | 28 | export const Definition = new GraphQLObjectType({ 29 | name: `Subtype`, 30 | description: `A Subtype object`, 31 | fields: () => ({ 32 | id: { 33 | type: GraphQLID, 34 | description: `A unique id for this subtype.` 35 | }, 36 | name: { 37 | type: GraphQLString, 38 | description: `The subtype name.` 39 | } 40 | }) 41 | }) 42 | 43 | export const Queries = { 44 | subtype: { 45 | type: new GraphQLList(Definition), 46 | description: `Returns a Subtype.`, 47 | args: { 48 | id: { type: new GraphQLList(GraphQLID) }, 49 | filter: { 50 | type: Filter 51 | }, 52 | limit: { type: GraphQLInt }, 53 | offset: { type: GraphQLInt }, 54 | orderBy: { type: order(`subtype`, Fields) } 55 | }, 56 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 57 | } 58 | } 59 | 60 | export const Mutations = { 61 | createSubtype: { 62 | type: Definition, 63 | description: `Creates a new Subtype`, 64 | args: { input: { type: Input } }, 65 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 66 | }, 67 | updateSubtype: { 68 | type: Definition, 69 | description: `Updates an existing Subtype, creates it if it does not already exist`, 70 | args: { input: { type: Input } }, 71 | resolve: (parent, args, context) => update(parent, args, context, Definition.name) 72 | }, 73 | deleteSubtype: { 74 | type: Definition, 75 | description: `Deletes a Subtype by id`, 76 | args: { id: { type: GraphQLID } }, 77 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/types/supertype.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `SupertypeInput`, 6 | description: `Required fields for a new Supertype object`, 7 | fields: () => ({ 8 | name: { type: new GraphQLNonNull(GraphQLString) } 9 | }) 10 | }) 11 | 12 | const Filter = new GraphQLInputObjectType({ 13 | name: `SupertypeFilter`, 14 | description: `Queryable fields for Supertype.`, 15 | fields: () => ({ 16 | name: { type: new GraphQLList(GraphQLString) } 17 | }) 18 | }) 19 | 20 | const Fields = new GraphQLEnumType({ 21 | name: `SupertypeFields`, 22 | description: `Field names for Supertype.`, 23 | values: { 24 | name: { value: `name` } 25 | } 26 | }) 27 | 28 | export const Definition = new GraphQLObjectType({ 29 | name: `Supertype`, 30 | description: `A Supertype object`, 31 | fields: () => ({ 32 | id: { 33 | type: GraphQLID, 34 | description: `A unique id for this supertype.` 35 | }, 36 | name: { 37 | type: GraphQLString, 38 | description: `The supertype name.` 39 | } 40 | }) 41 | }) 42 | 43 | export const Queries = { 44 | supertype: { 45 | type: new GraphQLList(Definition), 46 | description: `Returns a Supertype.`, 47 | args: { 48 | id: { type: new GraphQLList(GraphQLID) }, 49 | filter: { 50 | type: Filter 51 | }, 52 | limit: { type: GraphQLInt }, 53 | offset: { type: GraphQLInt }, 54 | orderBy: { type: order(`supertype`, Fields) } 55 | }, 56 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 57 | } 58 | } 59 | 60 | export const Mutations = { 61 | createSupertype: { 62 | type: Definition, 63 | description: `Creates a new Supertype`, 64 | args: { input: { type: Input } }, 65 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 66 | }, 67 | updateSupertype: { 68 | type: Definition, 69 | description: `Updates an existing Supertype, creates it if it does not already exist`, 70 | args: { input: { type: Input } }, 71 | resolve: (parent, args, context) => update(parent, args, context, Definition.name) 72 | }, 73 | deleteSupertype: { 74 | type: Definition, 75 | description: `Deletes a Supertype by id`, 76 | args: { id: { type: GraphQLID } }, 77 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/types/type.js: -------------------------------------------------------------------------------- 1 | import { GraphQLID, GraphQLInt, GraphQLNonNull, GraphQLEnumType, GraphQLList, GraphQLString, GraphQLObjectType, GraphQLInputObjectType } from 'graphql' 2 | import { create, destroy, order, read, update } from './utilities' 3 | 4 | export const Input = new GraphQLInputObjectType({ 5 | name: `TypeInput`, 6 | description: `Required fields for a new Type object`, 7 | fields: () => ({ 8 | id: { type: GraphQLID }, 9 | name: { type: new GraphQLNonNull(GraphQLString) } 10 | }) 11 | }) 12 | 13 | const Filter = new GraphQLInputObjectType({ 14 | name: `TypeFilter`, 15 | description: `Queryable fields for Type.`, 16 | fields: () => ({ 17 | name: { type: new GraphQLList(GraphQLString) } 18 | }) 19 | }) 20 | 21 | const Fields = new GraphQLEnumType({ 22 | name: `TypeFields`, 23 | description: `Field names for Type.`, 24 | values: { 25 | name: { value: `name` } 26 | } 27 | }) 28 | 29 | export const Definition = new GraphQLObjectType({ 30 | name: `Type`, 31 | description: `A Type object`, 32 | fields: () => ({ 33 | id: { 34 | type: GraphQLID, 35 | description: `A unique id for this type.` 36 | }, 37 | name: { 38 | type: GraphQLString, 39 | description: `The type name.` 40 | } 41 | }) 42 | }) 43 | 44 | export const Queries = { 45 | type: { 46 | type: new GraphQLList(Definition), 47 | description: `Returns a Type.`, 48 | args: { 49 | id: { type: new GraphQLList(GraphQLID) }, 50 | filter: { 51 | type: Filter 52 | }, 53 | limit: { type: GraphQLInt }, 54 | offset: { type: GraphQLInt }, 55 | orderBy: { type: order(`type`, Fields) } 56 | }, 57 | resolve: (parent, args, context) => read(parent, args, context, Definition.name) 58 | } 59 | } 60 | 61 | export const Mutations = { 62 | createType: { 63 | type: Definition, 64 | description: `Creates a new Type`, 65 | args: { input: { type: Input } }, 66 | resolve: (parent, args, context) => create(parent, args, context, Definition.name) 67 | }, 68 | updateType: { 69 | type: Definition, 70 | description: `Updates an existing Type, creates it if it does not already exist`, 71 | args: { input: { type: Input } }, 72 | resolve: (parent, args, context) => update(parent, args, context, Definition.name) 73 | }, 74 | destroyType: { 75 | type: Definition, 76 | description: `Deletes a Type by id`, 77 | args: { id: { type: GraphQLID } }, 78 | resolve: (parent, args, context) => destroy(parent, args, context, Definition.name) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/types/utilities/create.js: -------------------------------------------------------------------------------- 1 | import { info, error } from 'winston' 2 | import Models from '../../models' 3 | 4 | const create = (parent, { input }, context, type, callback) => Models[`${type}`] 5 | .findOrCreate(input) 6 | .then(model => !!callback ? callback(model) : model.toJSON()) 7 | .catch(err => error(`Failed to run Mutation: create${type}`, err)) 8 | .finally(info(`Resolved Mutation: create${type}`, { parent, input, context })) 9 | 10 | export default create 11 | -------------------------------------------------------------------------------- /src/types/utilities/destroy.js: -------------------------------------------------------------------------------- 1 | import { info, error } from 'winston' 2 | import Models from '../../models' 3 | 4 | const destroy = (parent, { id }, context, type) => Models[`${type}`] 5 | .destroy({ id }) 6 | .then(model => model.toJSON()) 7 | .catch(err => error(`Failed to run Mutation: destroy${type}`, err)) 8 | .finally(info(`Resolved Mutation: destroy${type}`, { parent, id, context })) 9 | 10 | export default destroy 11 | -------------------------------------------------------------------------------- /src/types/utilities/index.js: -------------------------------------------------------------------------------- 1 | export { default as create } from './create' 2 | export { default as destroy } from './destroy' 3 | export { default as order } from './order' 4 | export { default as read } from './read' 5 | export { default as sort } from './sort' 6 | export { default as update } from './update' 7 | -------------------------------------------------------------------------------- /src/types/utilities/order.js: -------------------------------------------------------------------------------- 1 | import { GraphQLInputObjectType, GraphQLNonNull } from 'graphql' 2 | import { sort } from './' 3 | 4 | const order = (name, fields) => new GraphQLInputObjectType({ 5 | name: `${name}OrderBy`, 6 | fields: () => ({ 7 | order: { type: new GraphQLNonNull(fields) }, 8 | sort: { type: sort } 9 | }) 10 | }) 11 | 12 | export default order 13 | -------------------------------------------------------------------------------- /src/types/utilities/read.js: -------------------------------------------------------------------------------- 1 | import { info, error } from 'winston' 2 | import Models from '../../models' 3 | 4 | const read = (parent, args, context, type) => { 5 | const { id, filter, limit, offset, orderBy } = args 6 | return Models[`${type}`] 7 | .query(qb => { 8 | if (!!id) qb.whereIn(`id`, id) 9 | if (!!filter) for (let field in filter) qb.whereIn(field, filter[field]) 10 | if (!!limit) qb.limit(limit) 11 | if (!!offset) qb.offset(offset) 12 | if (!!orderBy) qb.orderBy(...Object.values(orderBy)) 13 | }) 14 | .fetchAll() 15 | .then(collection => collection.toJSON()) 16 | .catch(err => error(`Failed to resolve Query: ${type}`, err)) 17 | .finally(info(`Resolved Query: ${type}`, { parent, args, context })) 18 | } 19 | 20 | export default read 21 | -------------------------------------------------------------------------------- /src/types/utilities/sort.js: -------------------------------------------------------------------------------- 1 | import { GraphQLEnumType } from 'graphql' 2 | 3 | const sort = new GraphQLEnumType({ 4 | name: `Sort`, 5 | description: `Sort options for OrderBy`, 6 | values: { 7 | ascending: { value: `asc` }, 8 | descending: { value: `desc`} 9 | } 10 | }) 11 | 12 | export default sort 13 | -------------------------------------------------------------------------------- /src/types/utilities/update.js: -------------------------------------------------------------------------------- 1 | import { info, error } from 'winston' 2 | import Models from '../../models' 3 | 4 | const update = (parent, { input }, context, type, selection, callback) => { 5 | if (!!selection && typeof selection === `string`) selection = [`${selection}`] 6 | 7 | const filter = !!selection 8 | ? Object.keys(input) 9 | .filter(key => selection.includes(key)) 10 | .reduce((obj, key) => { 11 | obj[key] = input[key] 12 | return obj 13 | }, {}) 14 | : input 15 | 16 | return Models[`${type}`] 17 | .upsert(filter, input) 18 | .then(model => !!callback ? callback(model) : model.toJSON()) 19 | .catch(err => error(`Failed to run Mutation: update${type}`, err)) 20 | .finally(info(`Resolved Mutation: update${type}`, { parent, input, context, selection })) 21 | } 22 | 23 | export default update 24 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | import testRunnerConfig from 'test-runner-config' 2 | 3 | let karmaFiles = testRunnerConfig.getKarmaFiles(files) 4 | 5 | export default (config) => { 6 | config.set({ 7 | basePath: __dirname, 8 | frameworks: [`jasmine`], 9 | exclude: [ ], 10 | files: karmaFiles.files, 11 | reporters: [ `mocha` ], 12 | port: 47357, 13 | colors: true, 14 | logLevel: config.LOG_INFO, 15 | autoWatch: false, 16 | browsers: [`Chrome_no_sandbox`], 17 | customLaunchers: { 18 | Chrome_no_sandbox: { 19 | base: `Chrome`, 20 | flags: [`--no-sandbox`] 21 | } 22 | }, 23 | singleRun: true 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /wallaby.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (wallaby) { 2 | return { 3 | files: [ 4 | { 5 | pattern: 'src/**/*.js', 6 | load: false 7 | }, 8 | { 9 | pattern: 'src/**/*.spec.js', 10 | ignore: true 11 | } 12 | ], 13 | 14 | tests: [ 15 | 'src/**/*.spec.js' 16 | ], 17 | 18 | compilers: { 19 | 'src/**/*.js': wallaby.compilers.babel({ 20 | babel: require('babel-core'), 21 | babelrc: true 22 | }) 23 | }, 24 | 25 | env: { 26 | type: 'node', 27 | runner: 'node', 28 | params: { 29 | // Specify Environment Variables Here 30 | } 31 | }, 32 | 33 | testFramework: 'jasmine', 34 | 35 | debug: true 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack' 2 | import path from 'path' 3 | import fs from 'fs' 4 | import dotenv from 'dotenv' // https://github.com/motdotla/dotenv 5 | import { generateConfig, stripMetadata } from '@easy-webpack/core' 6 | import envDev from '@easy-webpack/config-env-development' 7 | import babel from '@easy-webpack/config-babel' 8 | 9 | dotenv.config() 10 | 11 | process.env.BABEL_ENV = `webpack` 12 | const ENV = process.env.NODE_ENV && process.env.NODE_ENV.toLowerCase() || (process.env.NODE_ENV = `development`) 13 | 14 | const nodeModules = {} 15 | fs.readdirSync(`node_modules`) 16 | .filter(x => [`.bin`].indexOf(x) === -1) 17 | .forEach(mod => nodeModules[mod] = `commonjs ` + mod) 18 | 19 | // Main Webpack Configuration 20 | const config = generateConfig( 21 | { 22 | entry: { 23 | 'server': `./src/server` 24 | }, 25 | target: `node`, 26 | output: { 27 | path: path.resolve(`dist`), 28 | filename: `server.js` 29 | }, 30 | externals: nodeModules 31 | }, 32 | 33 | ENV === `test` ? envDev({devtool: `inline-source-map`}) : envDev(), 34 | 35 | babel(), 36 | 37 | ENV === `production` ? { 38 | plugins: [ 39 | new webpack.optimize.UglifyJsPlugin({ 40 | compress: { 41 | warnings: false, 42 | conditionals: true, 43 | unused: true, 44 | comparisons: true, 45 | sequences: true, 46 | dead_code: true, 47 | evaluate: true, 48 | join_vars: true, 49 | if_return: true 50 | }, 51 | output: { 52 | comments: false 53 | } 54 | }) 55 | ]} : { plugins: [ 56 | new webpack.optimize.UglifyJsPlugin({ 57 | beautify: true, 58 | mangle: false, 59 | dead_code: true, 60 | unused: true, 61 | compress: { 62 | keep_fnames: true, 63 | drop_debugger: false, 64 | dead_code: true, 65 | unused: true, 66 | warnings: false 67 | }, 68 | comments: true 69 | }) 70 | ]}, 71 | 72 | ENV === `development` ? { performance: { hints: false } } : {}, 73 | 74 | { 75 | module: { 76 | rules: [ 77 | { test: /\.(graphql|gql)$/, exclude: /node_modules/, loader: `graphql-tag/loader` }, 78 | { test: /\src\/images$/, loader: `ignore-loader` } 79 | ] 80 | }, 81 | plugins: [ 82 | new webpack.EnvironmentPlugin([ 83 | `HTTP`, 84 | `HTTPS`, 85 | `LOGLEVEL`, 86 | `DB_HOST`, 87 | `DB_USERNAME`, 88 | `DB_PASSWORD`, 89 | `DB_NAME`, 90 | `LOGGLY_TOKEN`, 91 | `LOGGLY_SUBDOMAIN`, 92 | `DD_API_KEY` 93 | ]), 94 | new webpack.BannerPlugin({ banner: `require("source-map-support").install();`, raw: true, entryOnly: false }) 95 | ] 96 | } 97 | ) 98 | 99 | module.exports = stripMetadata(config) 100 | --------------------------------------------------------------------------------