Full Code of Tallyb/loopback-graphql for AI

master 5876e5e5ceff cached
71 files
83.8 KB
23.7k tokens
48 symbols
1 requests
Download .txt
Repository: Tallyb/loopback-graphql
Branch: master
Commit: 5876e5e5ceff
Files: 71
Total size: 83.8 KB

Directory structure:
gitextract_knu9ajem/

├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .jsbeautifyrc
├── .npmignore
├── .travis.yml
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .yo-rc.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── __test__/
│   ├── data.json
│   ├── mutation.spec.ts
│   ├── pagination.spec.ts
│   ├── query.spec.ts
│   └── testHelper.ts
├── client/
│   └── README.md
├── common/
│   ├── models/
│   │   ├── account.js
│   │   ├── account.json
│   │   ├── address.js
│   │   ├── address.json
│   │   ├── author.js
│   │   ├── author.json
│   │   ├── book.json
│   │   ├── catalogs.js
│   │   ├── catalogs.json
│   │   ├── customer.js
│   │   ├── customer.json
│   │   ├── email-address.js
│   │   ├── email-address.json
│   │   ├── googlemaps.js
│   │   ├── googlemaps.json
│   │   ├── link.json
│   │   ├── note.js
│   │   ├── note.json
│   │   ├── order.js
│   │   ├── order.json
│   │   ├── products.js
│   │   ├── products.json
│   │   └── reader.json
│   └── types/
│       └── content.json
├── data.json
├── jsconfig.json
├── package.json
├── server/
│   ├── boot/
│   │   ├── authentication.js
│   │   └── root.js
│   ├── component-config.json
│   ├── config.json
│   ├── data.json
│   ├── datasources.json
│   ├── middleware.development.json
│   ├── middleware.json
│   ├── model-config.json
│   └── server.js
├── src/
│   ├── ast.ts
│   ├── boot.ts
│   ├── execution.ts
│   ├── index.ts
│   ├── interfaces.ts
│   ├── methods.ts
│   ├── resolvers.ts
│   ├── typedefs.ts
│   └── utils.ts
├── tsconfig.json
├── tsconfig.release.json
├── tsconfig.test.json
└── tslint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# http://editorconfig.org

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true


================================================
FILE: .eslintignore
================================================
/client/*
/coverage/**
/out/**

================================================
FILE: .eslintrc.json
================================================
{
    "root": true,
    "env": {
        "amd": true,
        "browser": true,
        "mocha": true,
        "es6": true,
        "jasmine": true,
        "node": true
    },
    "globals": {
        "assert": true,
        "browser": true,
        "expect": true,
        "by": true,
        "protractor": true,
        "sinon": true,
        "xdescribe": true,
        "xit": true
    },
    "plugins": [
        "nodeca"
    ],
    "rules": {
        "comma-dangle": [1, "ignore"],
        "camelcase": 0,
        "complexity": [0, 11],
        "consistent-return": 2,
        "consistent-this": [1, "self"],
        "curly": [2, "all"],
        "dot-notation": 2,
        "eol-last": 0,
        "eqeqeq": [2, "smart"],
        "indent": [0, 1, {
            "SwitchCase": 1
        }],
        "keyword-spacing": [2, {
            "before": true,
            "after": true,
            "overrides": {}
        }],
        "nodeca/indent": [2, "spaces", 4],
        "max-depth": [0, 4],
        "max-len": [0, 80, 4],
        "max-nested-callbacks": [0, 2],
        "max-params": [0, 15],
        "max-statements": [0, 10],
        "new-cap": [0],
        "new-parens": 2,
        "no-alert": 2,
        "no-array-constructor": 2,
        "no-caller": 2,
        "no-catch-shadow": 2,
        "no-cond-assign": 2,
        "no-console": 1,
        "no-constant-condition": 2,
        "no-control-regex": 2,
        "no-debugger": 2,
        "no-delete-var": 2,
        "no-dupe-keys": 2,
        "no-empty": 0,
        "no-empty-character-class": 2,
        "no-labels": 2,
        "no-ex-assign": 2,
        "no-extend-native": 2,
        "no-extra-boolean-cast": 2,
        "no-extra-parens": 1,
        "no-extra-semi": 2,
        "no-fallthrough": 2,
        "no-func-assign": 2,
        "no-implied-eval": 2,
        "no-invalid-regexp": 2,
        "no-iterator": 2,
        "no-label-var": 2,
        "no-lone-blocks": 2,
        "no-lonely-if": 0,
        "no-loop-func": 2,
        "no-mixed-spaces-and-tabs": [2, true],
        "no-multi-str": 2,
        "no-multiple-empty-lines": [2, {
            "max": 1
        }],
        "no-native-reassign": 2,
        "no-negated-in-lhs": 2,
        "no-nested-ternary": 0,
        "no-new": 2,
        "no-new-func": 2,
        "no-new-object": 2,
        "no-new-require": 0,
        "no-new-wrappers": 2,
        "no-obj-calls": 2,
        "no-octal": 2,
        "no-octal-escape": 2,
        "no-path-concat": 2,
        "no-process-exit": 1,
        "no-proto": 2,
        "no-redeclare": 2,
        "no-regex-spaces": 2,
        "no-return-assign": 2,
        "no-script-url": 2,
        "no-sequences": 2,
        "no-shadow": 0,
        "no-shadow-restricted-names": 2,
        "no-spaced-func": 2,
        "no-sparse-arrays": 2,
        "no-sync": 0,
        "no-ternary": 0,
        "no-trailing-spaces": 2,
        "no-undef": 2,
        "no-undef-init": 2,
        "no-underscore-dangle": 0,
        "no-unreachable": 2,
        "no-unused-vars": [2, {
            "args": "none",
            "vars": "local"
        }],
        "no-use-before-define": 2,
        "no-warning-comments": [1, {
            "terms": ["todo", "fixme", "xxx"],
            "location": "start"
        }],
        "no-with": 2,
        "quotes": [2, "single"],
        "semi": 2,
        "semi-spacing": 2,
        "space-infix-ops": [2, {
            "int32Hint": false
        }],
        "strict": [2, "global"],
        "use-isnan": 2,
        "valid-jsdoc": [2, {
            "prefer": {
                "return": "returns"
            },
            "requireReturn": false,
            "requireParamDescription": true
        }],
        "valid-typeof": 2,
        "wrap-iife": [2, "any"],
        "yoda": [2, "never", {
            "exceptRange": true
        }]
    }
}


================================================
FILE: .gitignore
================================================
# Logs
logs
*.log
npm-debug.log*

# Dependencies
node_modules/

# Coverage
coverage

# Transpiled files
build/

# VS Code
#.vscode
#!.vscode/tasks.js

# JetBrains IDEs
.idea/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Misc
.DS_Store
data

package-lock.json


================================================
FILE: .jsbeautifyrc
================================================
{
  "html": {
    "allowed_file_extensions": ["htm", "html", "xhtml", "shtml", "xml", "svg"],
    "brace_style": "collapse",
    "indent_char": " ",
    "indent_handlebars": false,
    "indent_inner_html": false,
    "indent_scripts": "keep",
    "indent_size": 4,
    "max_preserve_newlines": 1,
    "preserve_newlines": true,
    "unformatted": ["a", "sub", "sup", "b", "i", "u", "pre"],
    "wrap_line_length": 0
  },
  "css": {
    "allowed_file_extensions": ["css", "scss", "sass", "less"],
    "end_with_newline": false,
    "indent_char": " ",
    "indent_size": 4,
    "selector_separator": " ",
    "selector_separator_newline": false
  },
  "js": {
    "allowed_file_extensions": ["js", "json", "jshintrc", "jsbeautifyrc"],
    "brace_style": "collapse",
    "break_chained_methods": false,
    "e4x": true,
    "eval_code": false,
    "indent_char": " ",
    "indent_level": 0,
    "indent_size": 4,
    "indent_with_tabs": false,
    "jslint_happy": false,
    "keep_array_indentation": false,
    "keep_function_indentation": false,
    "max_preserve_newlines": 2,
    "preserve_newlines": true,
    "space_before_conditional": true,
    "space_in_paren": false,
    "unescape_strings": false,
    "wrap_line_length": 0
  }
}


================================================
FILE: .npmignore
================================================
server
client
test
coverage
resources
common
data.json
.vscode
.github
./data.json
build


================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
  - "6"
  - "7"

cache:
  directories:
    - ${HOME}/.npm

before_install:
  - npm config set spin=false
  - npm install -g npm@4
  - npm install -g coveralls

install:
  - npm install

script:
  - npm test
  - npm run coverage

after_script:
  - coveralls < ./coverage/lcov.info || true # if coveralls doesn't have it covered

branches:
    only:
      - master

# Allow Travis tests to run in containers.
sudo: false

deploy:
  provider: npm
  email: tally.barak@gmail.com
  api_key: $NPM_API_KEY
  on:
    tags: true
    all_branches: true


================================================
FILE: .vscode/launch.json
================================================
{
    "version": "0.2.0",
    "configurations": [

        {
            "name": "Tests",
            "type": "node",
            "request": "launch",
            "program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
            "stopOnEntry": false,
            "args": ["--runInBand"],
            "cwd": "${workspaceRoot}",
            "runtimeExecutable": null,
            "runtimeArgs": [
                "--nolazy"
            ],
            "env": {
                "NODE_ENV": "development"
            },
            "console": "internalConsole",
            "sourceMaps": true
        },
        {
            "name": "Launch",
            "type": "node",
            "request": "launch",
            "program": "${workspaceRoot}/server/server.js",
            "stopOnEntry": false,
            "args": [],
            "cwd": "${workspaceRoot}",
            "preLaunchTask": null,
            "outFiles": ["build"],
            "runtimeExecutable": null,
            "runtimeArgs": [
                "--nolazy"
            ],
            "env": {
                "NODE_ENV": "development"
            },
            "console": "internalConsole",
            "sourceMaps": true
        },
        {
            "name": "Attach",
            "type": "node",
            "request": "attach",
            "port": 5858,
            "address": "localhost",
            "restart": false,
            "sourceMaps": false,
            "outFiles": ["dist"],
            "localRoot": "${workspaceRoot}",
            "remoteRoot": null
        },
        {
            "name": "Attach to Process",
            "type": "node",
            "request": "attach",
            "processId": "${command:PickProcess}",
            "port": 5858,
            "sourceMaps": false,
            "outFiles": ["dist"]
        }
    ]
}


================================================
FILE: .vscode/settings.json
================================================
// Place your settings in this file to overwrite default and user settings.
{
    "search.exclude": {
        "out": true,
        "lib": true
    },
    "vsicons.presets.angular": false
}


================================================
FILE: .vscode/tasks.json
================================================


================================================
FILE: .yo-rc.json
================================================
{
  "generator-loopback": {}
}

================================================
FILE: CHANGELOG.md
================================================
# Change Log

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

<a name="0.13.0"></a>
# [0.13.0](https://github.com/tallyb/loopback-graphql/compare/v0.12.1...v0.13.0) (2017-05-19)


### Bug Fixes

* **app:** Packages upgrades ([c7cf2de](https://github.com/tallyb/loopback-graphql/commit/c7cf2de))
* **resolvers:** Remove workaround. Closes [#44](https://github.com/tallyb/loopback-graphql/issues/44) ([758ebbf](https://github.com/tallyb/loopback-graphql/commit/758ebbf))



<a name="0.12.1"></a>
## [0.12.1](https://github.com/tallyb/loopback-graphql/compare/v0.12.0...v0.12.1) (2017-04-30)


### Bug Fixes

* **github:** Remove github template ([353aadf](https://github.com/tallyb/loopback-graphql/commit/353aadf))
* **package:** update graphql-server-express to version 0.7.0 ([#49](https://github.com/tallyb/loopback-graphql/issues/49)) ([36cf7b4](https://github.com/tallyb/loopback-graphql/commit/36cf7b4))



<a name="0.12.0"></a>
# [0.12.0](https://github.com/tallyb/loopback-graphql/compare/v0.11.0...v0.12.0) (2017-04-01)


### Features

* **app:** Remove scalar types and use libs ([749b5ee](https://github.com/tallyb/loopback-graphql/commit/749b5ee))



<a name="0.11.0"></a>
# [0.11.0](https://github.com/tallyb/loopback-graphql/compare/v0.10.0...v0.11.0) (2017-03-31)


### Bug Fixes

* **package:** update graphql-server-express to version 0.5.0 ([#24](https://github.com/tallyb/loopback-graphql/issues/24)) ([8f84b54](https://github.com/tallyb/loopback-graphql/commit/8f84b54))
* **package:** update graphql-tools to version 0.10.0 ([#31](https://github.com/tallyb/loopback-graphql/issues/31)) ([398386e](https://github.com/tallyb/loopback-graphql/commit/398386e))
* **package:** update graphql-tools to version 0.11.0 ([#46](https://github.com/tallyb/loopback-graphql/issues/46)) ([4991faa](https://github.com/tallyb/loopback-graphql/commit/4991faa))
* **tests:** Fix partial tests ([e5eb2cd](https://github.com/tallyb/loopback-graphql/commit/e5eb2cd))


### Features

* **app:** Upgrade to loopback 3.0 ([5dfe8fb](https://github.com/tallyb/loopback-graphql/commit/5dfe8fb))



<a name="0.10.0"></a>
# [0.10.0](https://github.com/tallyb/loopback-graphql/compare/v0.9.0...v0.10.0) (2017-01-06)


### Bug Fixes

* **app:** Fix models names ([c21f454](https://github.com/tallyb/loopback-graphql/commit/c21f454))
* **app:** Fix wrong mixins ([93e8da7](https://github.com/tallyb/loopback-graphql/commit/93e8da7))
* **package:** update graphql-tools to version 0.9.0 ([#21](https://github.com/tallyb/loopback-graphql/issues/21)) ([1f0f309](https://github.com/tallyb/loopback-graphql/commit/1f0f309))


### Features

* **app:** Adding request to context ([0a3163d](https://github.com/tallyb/loopback-graphql/commit/0a3163d))



<a name="0.9.0"></a>
# [0.9.0](https://github.com/tallyb/loopback-graphql/compare/v0.8.0...v0.9.0) (2016-11-20)


### Features

* **app:** Support complex models ([82e479c](https://github.com/tallyb/loopback-graphql/commit/82e479c)), closes [#7](https://github.com/tallyb/loopback-graphql/issues/7)



<a name="0.8.0"></a>
# [0.8.0](https://github.com/tallyb/loopback-graphql/compare/v0.7.0...v0.8.0) (2016-11-15)


### Features

* **app:** Resolvers with edges ([883e79d](https://github.com/tallyb/loopback-graphql/commit/883e79d))
* **app:** Support paginations ([5ca2257](https://github.com/tallyb/loopback-graphql/commit/5ca2257))



<a name="0.7.0"></a>
# [0.7.0](https://github.com/tallyb/loopback-graphql/compare/v0.6.0...v0.7.0) (2016-11-03)


### Bug Fixes

* **typedefs:** Include generated properties ([a10c444](https://github.com/tallyb/loopback-graphql/commit/a10c444))


### Features

* **app:** Fix hidden attributes ([8d5c8a0](https://github.com/tallyb/loopback-graphql/commit/8d5c8a0))



<a name="0.6.0"></a>
# [0.6.0](https://github.com/tallyb/loopback-graphql/compare/v0.5.3...v0.6.0) (2016-10-18)


### Features

* **App:** Support aggregated types ([b057b3b](https://github.com/tallyb/loopback-graphql/commit/b057b3b)), closes [#1](https://github.com/tallyb/loopback-graphql/issues/1)



<a name="0.5.3"></a>
## [0.5.3](https://github.com/tallyb/loopback-graphql/compare/v0.5.2...v0.5.3) (2016-10-16)


### Bug Fixes

* **App:** Error on ReferencesMany relationship ([81f0821](https://github.com/tallyb/loopback-graphql/commit/81f0821))



<a name="0.5.1"></a>
## [0.5.1](https://github.com/tallyb/loopback-graphql/compare/v0.5.0...0.5.1) (2016-10-15)


### Bug Fixes

* **resolvers:** Fix resolving nested models ([c80b02d](https://github.com/tallyb/loopback-graphql/commit/c80b02d))



<a name="0.5.0"></a>
# [0.5.0](https://github.com/tallyb/loopback-graphql/compare/v0.3.0...v0.5.0) (2016-10-14)


### Features

* **Query:** ID parameter to single object query ([83ab4c4](https://github.com/tallyb/loopback-graphql/commit/83ab4c4))



<a name="0.3.0"></a>
# [0.3.0](https://github.com/tallyb/loopback-graphql/compare/v0.2.1...v0.3.0) (2016-10-12)


### Bug Fixes

* **app:** Fix relationships errors ([29716d1](https://github.com/tallyb/loopback-graphql/commit/29716d1))


### Features

* **app:** Add Delete Mutations ([e57dd20](https://github.com/tallyb/loopback-graphql/commit/e57dd20))
* **app:** Publish scripts ([caa66bf](https://github.com/tallyb/loopback-graphql/commit/caa66bf))


================================================
FILE: CONTRIBUTING.md
================================================
# Guidelines for contributors

If you're unsure whether your pull request or feature is something that has a chance of being merged, just open an issue and ask away!


## New contributors

Are Welcome (no guidelines yet...)

================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2017 Tally Barak

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:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

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.


================================================
FILE: README.md
================================================

# Deprecation Warning: 
I have been very bad at maintaining this repo, and do not see how I come back to it in the near future.
I have seen that this repo is a fork that moved forward: https://github.com/yahoohung/loopback-graphql-server/. 
If anyone is willing to take maintaining this repo on themselves - you are welcome. 
Thanks for all the feedback... 

### Status
[![Build Status](https://travis-ci.org/Tallyb/loopback-graphql.svg?branch=master)](https://travis-ci.org/Tallyb/loopback-graphql)

# GraphQL Server for Loopback (Apollo Server)

Combine the powers of [ApolloStack](http://www.apollostack.com/) GraphQL with the backend of Loopback.
<br>
All of Loopback models are exposed as GraphQL Queries.
<br>
Define models in Loopback to be exposed as REST APIs and GraphQL queries and mutations *.
<br>
Use the Apollo [clients](http://dev.apollodata.com/) to access your data. 

![Loopback Graphql](./resources/loopback-graphql.png?raw=true "LoopBack Apollo Architecture") 

## Getting started

```sh
npm install loopback-graphql
```
Add the loopback-graphql component to the `server/component-config.json`: 

```
"loopback-graphql": {
    "path": "/graphql",
    "graphiqlPath":"/graphiql"
  }
```

Requests will be posted to `path` path. (Default: `/graphql`);

Graphiql is available on `graphiqlPath` path. (Default: `/graphiql`);

## Usage

Access the Graphiql interface to view your GraphQL model on the Docs section. 
Build the GraphQL queries and use them in your application.

geoPoint objects are supported as follow: 
```
{"newNote": 
  {
    "location": {"lat":40.77492964101182, "lng":-73.90950187151662}
  }
}
```

## Roadmap
[See here the Github project](https://github.com/Tallyb/loopback-graphql/projects/1)


================================================
FILE: __test__/data.json
================================================
{
    "ids": {
        "User": 3,
        "AccessToken": 1,
        "ACL": 1,
        "RoleMapping": 1,
        "Role": 1,
        "Note": 7,
        "Author": 6,
        "Reader": 2,
        "Book": 2,
        "Customer": 8,
        "Address": 1,
        "EmailAddress": 1,
        "Account": 3,
        "Order": 6
    },
    "models": {
        "User": {
            "1": "{\"username\":\"tally\",\"password\":\"$2a$10$b/Ok3FC3HYCbF2LlLXpk4OSsrz5EixJfkfJittHp8eEtPQvUJZiEa\",\"email\":\"tally@a.com\",\"id\":1}",
        },
        "AccessToken": {},
        "ACL": {},
        "RoleMapping": {},
        "Role": {},
        "Note": {
            "1": "{\"title\":\"1st note\",\"id\":1}",
            "2": "{\"title\":\"Who is Afraid\",\"Genre\":\"HUMOR\",\"authorId\":3,\"id\":2}",
            "3": "{\"title\":\"A room with a View\",\"authorId\":3,\"id\":3}",
            "4": "{\"title\":\"The Bluest Eye\",\"authorId\":5,\"id\":4}",
            "5": "{\"title\":\"Of Mice and Men\",\"Genre\":\"HUMOR\",\"authorId\":4,\"id\":5}",
            "6": "{\"title\":\"Love and Prejudice\",\"authorId\":8,\"Genre\":\"ROMANCE\",\"id\":6}"
        },
        "Author": {
            "1": "{\"first_name\":\"Jane\",\"last_name\":\"Austin\",\"birth_date\":\"1883-10-15T00:00:00.000Z\",\"id\":8,\"friendIds\":[5,7]}",
            "3": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-06-30T07:36:32.666Z\",\"friendIds\":[],\"id\":3}",
        },
        "Reader": {
            "1": "{\"name\":\"Reader 1\",\"id\":1}"
        },
        "Book": {
            "1": "{\"name\":\"Book 1\",\"links\":[{\"id\":1,\"name\":\"Author 1\",\"notes\":\"Note 1\",\"linkedId\":1,\"linkedType\":\"Author\"},{\"id\":2,\"name\":\"Reader 1\",\"notes\":\"Note 2\",\"linkedId\":1,\"linkedType\":\"Reader\"}],\"id\":1}"
        },
        "Order": {
            "1": "{\"date\":\"2014-12-31T18:30:00.000Z\",\"description\":\"First order by Customer A\",\"customerId\":1,\"id\":1}",
            "2": "{\"date\":\"2015-01-31T18:30:00.000Z\",\"description\":\"Second order by Customer A\",\"customerId\":1,\"id\":2}",
            "3": "{\"date\":\"2015-02-28T18:30:00.000Z\",\"description\":\"Order by Customer B\",\"customerId\":2,\"id\":3}",
            "4": "{\"date\":\"2015-03-31T18:30:00.000Z\",\"description\":\"Order by Customer C\",\"customerId\":3,\"id\":4}",
            "5": "{\"date\":\"2015-04-30T18:30:00.000Z\",\"description\":\"Order by Anonymous\",\"id\":5}"
        },
        "Customer": {
            "1": "{\"name\":\"Customer A\",\"age\":21,\"emailList\":[],\"accountIds\":[],\"id\":1}",
            "2": "{\"name\":\"Customer B\",\"age\":22,\"emailList\":[],\"accountIds\":[],\"id\":2}",
            "3": "{\"name\":\"Customer C\",\"age\":23,\"emailList\":[],\"accountIds\":[],\"id\":3}",
            "4": "{\"name\":\"Customer D\",\"age\":24,\"emailList\":[],\"accountIds\":[],\"id\":4}",
            "5": "{\"name\":\"Mary Smith\",\"emailList\":[],\"accountIds\":[1,2],\"id\":5}",
            "6": "{\"name\":\"John Smith\",\"emailList\":[],\"accountIds\":[],\"id\":6,\"billingAddress\":{\"street\":\"123 A St\",\"city\":\"San Jose\",\"state\":\"CA\",\"zipCode\":\"95131\"}}",
            "7": "{\"name\":\"Larry Smith\",\"emailList\":[{\"label\":\"home\",\"address\":\"larry@yahoo.com\",\"id\":2,\"name\":\"home\"}],\"accountIds\":[],\"id\":7}"
        },
        "Address": {},
        "EmailAddress": {},
        "Account": {
            "1": "{\"name\":\"Checking\",\"balance\":5000,\"id\":1}",
            "2": "{\"name\":\"Saving\",\"balance\":2000,\"id\":2}"
        }
    }
}


================================================
FILE: __test__/mutation.spec.ts
================================================
'use strict';
import { gqlRequest } from './testHelper';
import gql from 'graphql-tag';
// var _ = require('lodash');

describe('mutation', () => {

  it('should add and Delete single entity', () => {
    let id;
    const createAuthor = gql`
            mutation save ($obj: AuthorInput!) {
                saveAuthor (obj: $obj) {
                    first_name
                    last_name
                    birth_date
                    id
                }
           }
        `;
    const authorInput = {
      first_name: 'Virginia',
      last_name: 'Wolf',
      birth_date: new Date(),
    };
    const deleteAuthor = gql`
            mutation delete ($id: ID!) {
                deleteAuthor (id: $id) {
                    text
                }
           }
        `;

    return gqlRequest(createAuthor, 200, {
      obj: authorInput,
    })
      .then(res => {
        id = res.body.data.saveAuthor.id;
        return gqlRequest(deleteAuthor, 200, {
          id: id,
        });
      });
  });

  it('should add a single entity with sub type', () => {
    const body = 'Heckelbery Finn';
    const query = gql`
            mutation save ($obj: NoteInput!) {
                saveNote (obj: $obj) {
                    id
                    title
                    author {
                        first_name
                        last_name
                    }

                }
           }
        `;
    const variables = {
      obj: {
        title: 'Heckelbery Finn',
        content: {
          body: body,
          footer: 'The end',
        },
      },
    };

    return gqlRequest(query, 200, variables)
      .then(res => {
        expect(res.body.data.saveNote.title).toEqual(body);
      });
  });

  describe('remote methods', () => {

    const userInput = {
      email: 'John@a.com',
      password: '123456',
      username: 'John@a.com',
    };
    const createUser = `
          mutation userCreate ($obj: UserInput!) {
            saveUser ( obj: $obj ) {
              id
            }
          }
        `;
    const deleteUser = gql`
            mutation delete ($id: ID!) {
                deleteAuthor (id: $id) {
                    text
                }
           }
        `;
    let userId;

    beforeEach(() => {
      return gqlRequest(createUser, 200, {
        obj: userInput,
      })
        .then(res => {
          userId = res.body.data.saveUser.id;
        });
    });

    afterEach(() => {
      return gqlRequest(deleteUser, 200, {
        id: userId,
      });
    });
    it.skip('should login and return an accessToken', () => {
      const query = gql`
          mutation login{
            UserLogin(credentials:{username:"John@a.com", password:"123456"})
          }
        `;
      return gqlRequest(query, 200)
        .then(res => {
          expect(res.body.data.UserLogin).toHaveProperty('id');
        });
    });

  });

});


================================================
FILE: __test__/pagination.spec.ts
================================================
'use strict';
import { gqlRequest } from './testHelper';
import gql from 'graphql-tag';
// var _ = require('lodash');

describe('Pagination', () => {


  it('should query first 2 entities', () => {
    const query = gql`{
                    allNotes(first: 2) {
                        totalCount
                        pageInfo {
                            hasNextPage
                            hasPreviousPage
                            startCursor
                            endCursor
                        }
                        edges {
                        node {
                            title
                            id
                        }
                        cursor
                        }
                    }
                    }

        `;
    return gqlRequest(query, 200)
      .then(res => {
        let data: any = res.body.data;
        expect(data.allNotes.edges.length).toBeGreaterThan(0);
      });
  });

  it('should query entity after cursor', () => {
    const query = gql`{
            allNotes (after: "Y29ubmVjdGlvbi40", first: 3) {
                pageInfo  {
                    hasNextPage
                    hasPreviousPage
                    startCursor
                    endCursor
                }
                edges {
                node {
                    id
                    title
                }
                cursor
                }
            }
        }`;
    return gqlRequest(query, 200)
      .then(res => {
        let data: any = res.body.data;
        expect(data.allNotes.edges.length).toBeGreaterThan(0);
        expect(data.allNotes.edges[0].node.id).toBeGreaterThan(4);
        expect(data.allNotes.pageInfo.hasPreviousPage).toEqual(true);
      });
  });

  it('should query related entity on edge', () => {
    const query = gql`{
                allAuthors {
                    pageInfo {
                        hasNextPage
                        hasPreviousPage
                        startCursor
                        endCursor
                    }
                    edges {
                    node {
                        id
                        last_name
                        notes {
                        totalCount
                        Notes {
                            title
                        }
                        }
                    }
                    cursor
                    }
                }
                }
            `;
    return gqlRequest(query, 200)
      .then(res => {
        let data: any = res.body.data;
        expect(data.allAuthors.edges[0].node.notes.Notes.length).toBeGreaterThan(0);
        expect(data.allAuthors.edges[0].node.notes.totalCount).toBeGreaterThan(0);
        //data.allAuthors.edges[0].cursor.should.not.to.be.empty();
      });
  });

});


================================================
FILE: __test__/query.spec.ts
================================================
'use strict';
import { gqlRequest } from './testHelper';
import gql from 'graphql-tag';

describe('query', () => {

  describe('Single entity', () => {
    it('should execute a single query with relation', () => {
      const query = gql`
            query {
              allOrders(first:1){
                edges{
                  node{
                    date
                    description
                    customer{
                      edges{
                        node{
                          name
                          age
                        }
                      }
                    }
                  }
                }
              }
            }`;
      return gqlRequest(query, 200, {})
        .then(res => {
          console.log('RES', res.body.data);
          let data = res.body.data;
          expect(data.allOrders.edges.length).toEqual(1);
        });
    });
  });

  describe('Multiple entities', () => {
    it('should return response with where on id', () => {
      const query = gql`
                query users ($where:JSON){
                  allUsers(where: $where) {
                    totalCount
                    edges {
                      node {
                        id
                        email
                      }
                    }

                  }
      }`;
      const variables = {
        where: {
          id: {
            inq: [1, 2],
          },
        },
      };
      return gqlRequest(query, 200, variables)
        .then(res => {
          expect(res.body.data.allUsers.totalCount).toEqual(2);
        });

    });
  });

  describe('relationships', () => {
    it('should query related entity with nested relational data', () => {
      const query = gql`
                query {
                 allCustomers(first:2){
                   edges{
                     node{
                       name
                       age
                       orders{
                         edges{
                           node{
                             date
                             description
                             customer{
                               edges{
                                 node{
                                   name
                                   age
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
            `;
      return gqlRequest(query, 200, {})
        .then(res => {
          expect(res.body.data.allCustomers.edges.length).toEqual(2);
        });
    });
  });

});


================================================
FILE: __test__/testHelper.ts
================================================
'use strict';

import request from 'supertest';
import app from '../server/server.js';

export function gqlRequest(query: any, status: number, variables?: object) {

  return request(app)
    .post('/graphql')
    .send({
      query,
      variables,
    })
    .expect(status);
}


================================================
FILE: client/README.md
================================================
## Client

This is the place for your application front-end files.


================================================
FILE: common/models/account.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(Account) {

};


================================================
FILE: common/models/account.json
================================================
{
  "name": "Account",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "name": {
      "type": "string"
    },
    "balance": {
      "type": "number"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/address.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(Address) {

};


================================================
FILE: common/models/address.json
================================================
{
  "name": "Address",
  "base": "Model",
  "idInjection": true,
  "properties": {
    "street": {
      "type": "string"
    },
    "city": {
      "type": "string"
    },
    "state": {
      "type": "string"
    },
    "zipCode": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/author.js
================================================
'use strict';

module.exports = function(Author) {

    Author.remoteMethod(
        'addFriend', {
            'http': {
                'path': '/addFriend',
                'verb': 'post'
            },

            'accepts': [{
                'arg': 'author',
                'type': 'number'
            }, {
                'arg': 'friend',
                'type': ['number']
            }],

            'returns': {
                'arg': 'result',
                'type': 'object'
            }
        }
    );

    Author.addFriend = function(author, friend) {

        return Author.findById(author)
            .then(res => {
                let updated = res;
                updated.friendIds.push(friend);
                return updated.save();
            }).then(res => {});
    };
};

================================================
FILE: common/models/author.json
================================================
{
    "name": "Author",
    "plural": "Authors",
    "base": "PersistedModel",
    "idInjection": true,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "first_name": {
            "type": "string",
            "required": true
        },
        "last_name": {
            "type": "string",
            "required": true
        },

        "birth_date": {
            "type": "date",
            "required": true
        },
        "user": {
            "type": "User",
            "required": false
        },
        "dream": "Object"
    },
    "validations": [],
    "relations": {
        "notes": {
            "type": "hasMany",
            "model": "Note",
            "foreignKey": ""
        },
        "friends": {
            "type": "referencesMany",
            "model": "Author",
            "foreignKey": "friendIds"
        },
        "others": {
            "type": "hasMany",
            "model": "Author"
        }
    },
    "acls": [],
    "methods": {}
}

================================================
FILE: common/models/book.json
================================================
{
  "name": "Book",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "name": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {
    "people": {
      "type": "embedsMany",
      "model": "Link",
      "scope": {
        "include": "linked"
      }
    }
  },
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/catalogs.js
================================================
'use strict';

module.exports = function(Catalogs) {

};

================================================
FILE: common/models/catalogs.json
================================================
{
    "name": "catalogs",
    "base": "PersistedModel",
    "idInjection": true,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "_id": {
            "type": "string",
            "generated": true,
            "id": true
        }
    },
    "validations": [],
    "relations": {
        "products": {
            "type": "hasMany",
            "model": "products",
            "foreignKey": "catalogRef"
        }
    },
    "acls": [{
        "accessType": "*",
        "principalType": "ROLE",
        "principalId": "$everyone",
        "permission": "DENY"
    }, {
        "accessType": "*",
        "principalType": "ROLE",
        "principalId": "$authenticated",
        "permission": "ALLOW"
    }],
    "indexes": {
        "catalogRef_1": {
            "catalogRef": 1
        }
    },
    "methods": [],
    "permissions": "private",
    "mixins": {}
}

================================================
FILE: common/models/customer.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(Customer) {

};


================================================
FILE: common/models/customer.json
================================================
{
  "name": "Customer",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "name": {
      "type": "string"
    },
    "age": {
      "type": "number"
    }
  },
  "validations": [],
  "relations": {
    "address": {
      "type": "embedsOne",
      "model": "Address",
      "property": "billingAddress",
      "options": {
        "validate": true,
        "forceId": false
      }
    },
    "emails": {
      "type": "embedsMany",
      "model": "EmailAddress",
      "property": "emailList",
      "options": {
        "validate": true,
        "forceId": false
      }
    },
    "accounts": {
      "type": "referencesMany",
      "model": "Account",
      "foreignKey": "accountIds",
      "options": {
        "validate": true,
        "forceId": false
      }
    },
    "orders": {
      "type": "hasMany",
      "model": "Order",
      "foreignKey": "id"
    }
  },
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/email-address.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(EmailAddress) {

};


================================================
FILE: common/models/email-address.json
================================================
{
  "name": "EmailAddress",
  "base": "Model",
  "idInjection": true,
  "properties": {
    "label": {
      "type": "string"
    },
    "address": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/googlemaps.js
================================================
'use strict';

module.exports = function(Googlemaps) {};

================================================
FILE: common/models/googlemaps.json
================================================
{
    "name": "Googlemaps",
    "plural": "Googlemaps",
    "base": "PersistedModel",
    "idInjection": false,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "id": {
            "type": "string",
            "description": "contains a unique stable identifier denoting this place. This identifier may not be used to retrieve information about this place, but is guaranteed to be valid across sessions. It can be used to consolidate data about this place, and to verify the identity of a place across separate searches. **Note**: The `id` is now deprecated in favor of `place_id`."
        },
        "geometry": {
            "type": {
                "location": {
                    "lat": "number",
                    "lng": "number"
                },
                "viewport": {
                    "northeast": {
                        "lat": "number",
                        "lng": "number"
                    },
                    "southwest": {
                        "lat": "number",
                        "lng": "number"
                    }
                }
            },
            "description": "contains geometry information about the result, generally including the `location` (geocode) of the place and (optionally) the `viewport` identifying its general area of coverage."
        },
        "photos": {
            "description": "an array of `photo` objects, each containing a reference to an image. A Place Search will return at most one `photo` object. Performing a Place Details request on the place may return up to ten photos. More information about Place Photos and how you can use the images in your application can be found in the [Place Photos](https://developers.google.com/places/web-service/photos) documentation.",
            "type": [{
                "photo_reference": {
                    "type": "string",
                    "description": " a string used to identify the photo when you perform a Photo request."
                },
                "height": {
                    "type": "number",
                    "description": " the maximum height of the image."
                },
                "width": {
                    "type": "number",
                    "description": " the maximum width of the image."
                },
                "html_attributions": {
                    "type": ["string"],
                    "description": "contains any required attributions. This field will always be present, but may be empty."
                }
            }]
        },
        "scope": {
            "type": "string",
            "description": [
                "Indicates the scope of the `place_id`. The possible values are:", " * `APP`: The place ID is recognised by your application only. This is because your application added the place, and the place has not yet passed the moderation process.", " * `GOOGLE`: The place ID is available to other applications and on Google Maps.", "**Note**: The `scope` field is included only in Nearby Search results and Place Details results. You can only retrieve app-scoped places via the Nearby Search and the Place Details requests. If the `scope` field is not present in a response, it is safe to assume the scope is `GOOGLE`."
            ]
        },
        "alt_ids": {
            "type": {
                "place_id": {
                    "type": "string",
                    "description": "The most likely reason for a place to have an alternative place ID is if your application adds a place and receives an application-scoped place ID, then later receives a Google-scoped place ID after passing the moderation process."
                },
                "scope": {
                    "type": "string",
                    "description": "The scope of an alternative place ID will always be APP, indicating that the alternative place ID is recognised by your application only."
                }
            },
            "description": ["An array of zero, one or more alternative place IDs for the place, with a scope related to each alternative ID. Note: This array may be empty or not present.", "For example, let's assume your application adds a place and receives a `place_id` of `AAA` for the new place. Later, the place passes the moderation process and receives a Google-scoped `place_id` of `BBB`. From this point on, the information for this place will contain:", "```", "\"results\" : [", "      {", "        \"place_id\" : \"BBB\",", "        \"scope\" : \"GOOGLE\",", "        \"alt_ids\" : [", "          {", "            \"place_id\" : \"AAA\",", "            \"scope\" : \"APP\",", "          }", "        ],", "      }", "    ]", "```"]
        }
    },
    "validations": [],
    "relations": {},
    "acls": [],
    "methods": {}
}


================================================
FILE: common/models/link.json
================================================
{
  "name": "Link",
  "base": "Model",
  "idInjection": true,
  "properties": {
    "id": {
      "type": "number",
      "id": true
    },
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {
    "linked": {
      "type": "belongsTo",
      "polymorphic": {
        "idType": "number"
      },
      "properties": {
        "name": "name"
      },
      "options": {
        "invertProperties": true
      }
    }
  },
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/note.js
================================================
'use strict';

module.exports = function(Note) {

    Note.clear = () => {
        return {
            note: {
                Content: ''
            },
            previousClear: new Date()
        };
    };

    Note.remoteMethod(
        'clear', {
            'http': {
                'path': '/clear',
                'verb': 'post'
            },
            'returns': [{
                'arg': 'note',
                'type': 'object'
            }, {
                'arg': 'previousClear',
                'type': 'Date'
            }]
        });
};

================================================
FILE: common/models/note.json
================================================
{
    "name": "Note",
    "properties": {
        "title": {
            "type": "string",
            "required": true
        },
        "content": {
            "type": "Content"
        },
        "Genre": {
            "type": "string",
            "required": false,
            "enum": [
                "HUMOR",
                "SCI_FI",
                "HORROR",
                "ROMANCE",
                "NON_FICTION"
            ]
        },
        "location": {
            "type": "GeoPoint"
        }
    },
    "validations": [],
    "relations": {
        "author": {
            "type": "belongsTo",
            "model": "Author",
            "foreignKey": ""
        }
    },
    "acls": [],
    "methods": {
        "prototype.vote": {
            "accepts": [{
                "arg": "rank",
                "type": "number",
                "required": true,
                "description": ""
            }],
            "returns": [],
            "description": " vote  a note",
            "http": [{
                "path": "vote",
                "verb": "post"
            }]
        }
    }
}


================================================
FILE: common/models/order.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(Order) {

};


================================================
FILE: common/models/order.json
================================================
{
  "name": "Order",
  "base": "PersistedModel",
  "idInjection": true,
  "options": {
    "validateUpsert": true
  },
  "properties": {
    "date": {
      "type": "date"
    },
    "description": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {
    "customer": {
      "type": "hasOne",
      "model": "Customer",
      "foreignKey": "id"
    }
  },
  "acls": [],
  "methods": {}
}


================================================
FILE: common/models/products.js
================================================
'use strict';

module.exports = function(Products) {

};

================================================
FILE: common/models/products.json
================================================
{
    "name": "products",
    "base": "PersistedModel",
    "idInjection": true,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "_id": {
            "type": "string",
            "generated": true,
            "id": true
        }
    },
    "validations": [],
    "relations": {
        "catalog": {
            "type": "belongsTo",
            "model": "catalogs",
            "foreignKey": "catalogRef"
        }
    },
    "acls": [{
        "accessType": "*",
        "principalType": "ROLE",
        "principalId": "$everyone",
        "permission": "DENY"
    }, {
        "accessType": "*",
        "principalType": "ROLE",
        "principalId": "$authenticated",
        "permission": "ALLOW"
    }],
    "indexes": {
        "catalogRef_1": {
            "catalogRef": 1
        }
    },
    "methods": [],
    "permissions": "private",
    "mixins": {}
}

================================================
FILE: common/models/reader.json
================================================
{
  "name": "Reader",
  "base": "PersistedModel",
  "idInjection": true,
  "properties": {
    "name": {
      "type": "string"
    }
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": {}
}


================================================
FILE: common/types/content.json
================================================
{
    "name": "Content",
    "plural": "Content",
    "base": "Model",
    "idInjection": false,
    "options": {
        "validateUpsert": true
    },
    "properties": {
        "title": {
            "type": "string"
        },
        "body": {
            "type": "string"
        },
        "footer": {
            "type": "string"
        }
    },
    "validations": [],
    "relations": {},
    "acls": [],
    "methods": {}

}

================================================
FILE: data.json
================================================
{
  "ids": {
    "User": 1,
    "AccessToken": 1,
    "ACL": 1,
    "RoleMapping": 1,
    "Role": 1,
    "Customer": 1,
    "Account": 1,
    "Author": 6,
    "Reader": 1,
    "Book": 1,
    "Order": 1,
    "Note": 1,
    "Googlemaps": 1,
    "products": 1,
    "catalogs": 1
  },
  "models": {
    "User": {},
    "AccessToken": {},
    "ACL": {},
    "RoleMapping": {},
    "Role": {},
    "Customer": {},
    "Account": {},
    "Author": {
      "1": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-06-30T07:47:24.747Z\",\"friendIds\":[],\"id\":1}",
      "2": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-06-30T07:49:23.893Z\",\"friendIds\":[],\"id\":2}",
      "3": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-06-30T09:43:37.721Z\",\"friendIds\":[],\"id\":3}",
      "4": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-07-08T05:38:45.056Z\",\"friendIds\":[],\"id\":4}",
      "5": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-09-23T04:09:57.126Z\",\"friendIds\":[],\"id\":5}"
    },
    "Reader": {},
    "Book": {},
    "Order": {},
    "Note": {},
    "Googlemaps": {},
    "products": {},
    "catalogs": {}
  }
}

================================================
FILE: jsconfig.json
================================================
{
	// See https://go.microsoft.com/fwlink/?LinkId=759670
	// for the documentation about the jsconfig.json format
	"compilerOptions": {
		"target": "es6",
		"module": "commonjs",
		"allowSyntheticDefaultImports": true
	},
	"exclude": [
		"node_modules",
		"bower_components",
		"jspm_packages",
		"tmp",
		"temp"
	],
	"env": {
        "node": true
    }
}


================================================
FILE: package.json
================================================
{
    "name": "loopback-graphql",
    "version": "0.13.0",
    "description": "Add Apollo Server or GraphQL queries on your Loopback server",
    "main": "build/src/index.js",
    "directories": {
        "test": "test"
    },
    "types": "build/index",
    "scripts": {
        "clean": "rimraf coverage build tmp",
        "build": "tsc -p tsconfig.release.json",
        "lint": "tslint -t stylish '{src,__tests__}/**/*.{ts,tsx}'",
        "pretest": "npm run lint  && npm run copydata",
        "test": "npm run test:only",
        "test:only": "jest --coverage",
        "test:watch": "jest --watch",
        "copydata": "cpx ./__test__/data.json ./server/",
        "test:notify": "npm run test:watch -- --notify",
        "test:co": "npm run test -- --runInBand",
        "coverage": "npm test -- --coverage",
        "coverage:notify": "npm run coverage -- --watch --notify",
        "start": "npm run build && node server/server.js",
        "start:watch": "concurrently \"npm run build:watch\" \"node-dev server/server.js\"",
        "prerelease": "npm test",
        "release": "standard-version"
    },
    "repository": {
        "url": "git+https://github.com/tallyb/loopback-graphql.git",
        "type": "git"
    },
    "keywords": [
        "Loopback",
        "GraphQL",
        "Apollo",
        "Express",
        "Javascript",
        "REST",
        "APIs"
    ],
    "author": "Tally Barak <tally.barak@gmail.com>",
    "license": "MIT",
    "bugs": {
        "url": "https://github.com/tallyb/loopback-graphql/issues"
    },
    "homepage": "https://github.com/tallyb/loopback-graphql#readme",
    "dependencies": {
        "body-parser": "^1.17.2",
        "graphql": "^0.12.0",
        "graphql-date": "^1.0.3",
        "graphql-geojson": "^1.0.0",
        "graphql-server-express": "^1.0.0",
        "graphql-tools": "^3.0.0",
        "graphql-type-json": "^0.2.0",
        "lodash": "^4.17.4"
    },
    "devDependencies": {
        "@types/jest": "22.0.0",
        "@types/graphql": "^0.13.4",
        "@types/jest": "^21.1.0",
        "@types/lodash": "^4.14.66",
        "@types/request": "2.0.7",
        "@types/node": "^10.5.5",
        "@types/request-promise": "^4.1.33",
        "@types/supertest": "^2.0.1",
        "@types/uuid": "^3.0.0",
        "awesome-typescript-loader": "^5.0.0",
        "compression": "^1.6.2",
        "concurrently": "^3.4.0",
        "cors": "^2.8.3",
        "cpx": "^1.5.0",
        "eslint": "^5.0.0",
        "express": "^4.15.3",
        "ghooks": "^2.0.0",
        "graphql-tag": "^2.3.0",
        "helmet": "^3.6.1",
        "jest-cli": "^22.0.0",
        "jest": "^22.0.0",
        "loopback": "^3.8.0",
        "loopback-boot": "^2.24.1",
        "loopback-component-explorer": "^6.0.0",
        "loopback-datasource-juggler": "^3.9.1",
        "node-dev": "^3.1.3",
        "nsp": "^3.0.0",
        "request": "^2.81.0",
        "rimraf": "^2.6.1",
        "serve-favicon": "^2.4.3",
        "standard-version": "^4.2.0",
        "strong-error-handler": "^3.0.0",
        "supertest": "^3.0.0",
        "ts-jest": "^23.1.0",
        "tslint": "^5.4.3",
        "typescript": "^2.4.0"
    },
    "jest": {
        "transform": {
            ".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js"
        },
        "mapCoverage": true,
        "testEnvironment": "node",
        "testRegex": ".*\\.spec\\.ts$",
        "moduleFileExtensions": [
            "ts",
            "js",
            "json"
        ],
        "globals": {
            "__DEV__": true,
            "ts-jest": {
                "tsConfigFile": "tsconfig.test.json"
            }
        }
    }
}


================================================
FILE: server/boot/authentication.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function enableAuthentication(server) {
  // enable authentication
};


================================================
FILE: server/boot/root.js
================================================
// Copyright IBM Corp. 2015. All Rights Reserved.
// Node module: loopback-example-relations
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';

module.exports = function(app) {

};


================================================
FILE: server/component-config.json
================================================
{
    "loopback-component-explorer": {
        "mountPath": "/explorer"
    },
    "../build/index.js": {}
}


================================================
FILE: server/config.json
================================================
{
  "restApiRoot": "/api",
  "host": "0.0.0.0",
  "port": 3000,
  "remoting": {
    "context": false,
    "rest": {
      "normalizeHttpPath": false,
      "xml": false
    },
    "json": {
      "strict": false,
      "limit": "100kb"
    },
    "urlencoded": {
      "extended": true,
      "limit": "100kb"
    },
    "cors": false,
    "handleErrors": false
  },
  "legacyExplorer": false
}


================================================
FILE: server/data.json
================================================
{
    "ids": {
        "User": 3,
        "AccessToken": 1,
        "ACL": 1,
        "RoleMapping": 1,
        "Role": 1,
        "Note": 7,
        "Author": 6,
        "Reader": 2,
        "Book": 2,
        "Customer": 8,
        "Address": 1,
        "EmailAddress": 1,
        "Account": 3,
        "Order": 6
    },
    "models": {
        "User": {
            "1": "{\"username\":\"tally\",\"password\":\"$2a$10$b/Ok3FC3HYCbF2LlLXpk4OSsrz5EixJfkfJittHp8eEtPQvUJZiEa\",\"email\":\"tally@a.com\",\"id\":1}",
        },
        "AccessToken": {},
        "ACL": {},
        "RoleMapping": {},
        "Role": {},
        "Note": {
            "1": "{\"title\":\"1st note\",\"id\":1}",
            "2": "{\"title\":\"Who is Afraid\",\"Genre\":\"HUMOR\",\"authorId\":3,\"id\":2}",
            "3": "{\"title\":\"A room with a View\",\"authorId\":3,\"id\":3}",
            "4": "{\"title\":\"The Bluest Eye\",\"authorId\":5,\"id\":4}",
            "5": "{\"title\":\"Of Mice and Men\",\"Genre\":\"HUMOR\",\"authorId\":4,\"id\":5}",
            "6": "{\"title\":\"Love and Prejudice\",\"authorId\":8,\"Genre\":\"ROMANCE\",\"id\":6}"
        },
        "Author": {
            "1": "{\"first_name\":\"Jane\",\"last_name\":\"Austin\",\"birth_date\":\"1883-10-15T00:00:00.000Z\",\"id\":8,\"friendIds\":[5,7]}",
            "3": "{\"first_name\":\"Virginia\",\"last_name\":\"Wolf\",\"birth_date\":\"2017-06-30T07:36:32.666Z\",\"friendIds\":[],\"id\":3}",
        },
        "Reader": {
            "1": "{\"name\":\"Reader 1\",\"id\":1}"
        },
        "Book": {
            "1": "{\"name\":\"Book 1\",\"links\":[{\"id\":1,\"name\":\"Author 1\",\"notes\":\"Note 1\",\"linkedId\":1,\"linkedType\":\"Author\"},{\"id\":2,\"name\":\"Reader 1\",\"notes\":\"Note 2\",\"linkedId\":1,\"linkedType\":\"Reader\"}],\"id\":1}"
        },
        "Order": {
            "1": "{\"date\":\"2014-12-31T18:30:00.000Z\",\"description\":\"First order by Customer A\",\"customerId\":1,\"id\":1}",
            "2": "{\"date\":\"2015-01-31T18:30:00.000Z\",\"description\":\"Second order by Customer A\",\"customerId\":1,\"id\":2}",
            "3": "{\"date\":\"2015-02-28T18:30:00.000Z\",\"description\":\"Order by Customer B\",\"customerId\":2,\"id\":3}",
            "4": "{\"date\":\"2015-03-31T18:30:00.000Z\",\"description\":\"Order by Customer C\",\"customerId\":3,\"id\":4}",
            "5": "{\"date\":\"2015-04-30T18:30:00.000Z\",\"description\":\"Order by Anonymous\",\"id\":5}"
        },
        "Customer": {
            "1": "{\"name\":\"Customer A\",\"age\":21,\"emailList\":[],\"accountIds\":[],\"id\":1}",
            "2": "{\"name\":\"Customer B\",\"age\":22,\"emailList\":[],\"accountIds\":[],\"id\":2}",
            "3": "{\"name\":\"Customer C\",\"age\":23,\"emailList\":[],\"accountIds\":[],\"id\":3}",
            "4": "{\"name\":\"Customer D\",\"age\":24,\"emailList\":[],\"accountIds\":[],\"id\":4}",
            "5": "{\"name\":\"Mary Smith\",\"emailList\":[],\"accountIds\":[1,2],\"id\":5}",
            "6": "{\"name\":\"John Smith\",\"emailList\":[],\"accountIds\":[],\"id\":6,\"billingAddress\":{\"street\":\"123 A St\",\"city\":\"San Jose\",\"state\":\"CA\",\"zipCode\":\"95131\"}}",
            "7": "{\"name\":\"Larry Smith\",\"emailList\":[{\"label\":\"home\",\"address\":\"larry@yahoo.com\",\"id\":2,\"name\":\"home\"}],\"accountIds\":[],\"id\":7}"
        },
        "Address": {},
        "EmailAddress": {},
        "Account": {
            "1": "{\"name\":\"Checking\",\"balance\":5000,\"id\":1}",
            "2": "{\"name\":\"Saving\",\"balance\":2000,\"id\":2}"
        }
    }
}


================================================
FILE: server/datasources.json
================================================
{
    "db": {
        "name": "db",
        "connector": "memory",
        "file": "./data.json"
    },
    "transient": {
        "name": "transient",
        "connector": "memory"
    }
}


================================================
FILE: server/middleware.development.json
================================================
{
  "final:after": {
    "strong-error-handler": {
      "params": {
        "debug": true,
        "log": true
      }
    }
  }
}


================================================
FILE: server/middleware.json
================================================
{
  "initial:before": {
    "loopback#favicon": {}
  },
  "initial": {
    "compression": {},
    "cors": {
      "params": {
        "origin": true,
        "credentials": true,
        "maxAge": 86400
      }
    }
  },
  "session": {
  },
  "auth": {
  },
  "parse": {
  },
  "routes:before": {
    "loopback#rest": {
      "paths": ["${restApiRoot}"]
    }
  },
  "files": {
    "serve-static": {
      "params": "$!../client"
    }
  },
  "final": {
    "loopback#urlNotFound": {}
  },
  "final:after": {
    "strong-error-handler": {}
  }
}


================================================
FILE: server/model-config.json
================================================
{
    "_meta": {
        "sources": [
            "loopback/common/models",
            "loopback/server/models",
            "../common/models",
            "../common/types",
            "./models"
        ]
    },
    "User": {
        "dataSource": "db"
    },
    "AccessToken": {
        "dataSource": "db",
        "public": false
    },
    "ACL": {
        "dataSource": "db",
        "public": false
    },
    "RoleMapping": {
        "dataSource": "db",
        "public": false
    },
    "Role": {
        "dataSource": "db",
        "public": false
    },
    "Customer": {
        "dataSource": "db",
        "public": true
    },
    "Address": {
        "dataSource": "transient",
        "public": false
    },
    "EmailAddress": {
        "dataSource": "transient",
        "public": false
    },
    "Account": {
        "dataSource": "db",
        "public": false
    },
    "Author": {
        "dataSource": "db",
        "public": true
    },
    "Reader": {
        "dataSource": "db",
        "public": false
    },
    "Book": {
        "dataSource": "db",
        "public": true
    },
    "Link": {
        "dataSource": "transient",
        "public": false
    },
    "Order": {
        "dataSource": "db",
        "public": true
    },
    "Note": {
        "dataSource": "db",
        "public": true
    },
    "Content": {
        "dataSource": null,
        "public": false
    },
    "Googlemaps": {
        "dataSource": "db",
        "public": true
    },
    "products": {
        "dataSource": "db",
        "public": true
    },
    "catalogs": {
        "dataSource": "db",
        "public": true
    }
}

================================================
FILE: server/server.js
================================================
'use strict';

var loopback = require('loopback');
var boot = require('loopback-boot');

var app = module.exports = loopback();

app.start = function() {
    // start the web server
    return app.listen(function() {
        app.emit('started');
        var baseUrl = app.get('url').replace(/\/$/, '');
        console.log('Web server listening at: %s', baseUrl);
        if (app.get('loopback-component-explorer')) {
            var explorerPath = app.get('loopback-component-explorer').mountPath;
            console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
        }
    });
};

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
    if (err) {
        throw err;
    }

    // start the server if `$ node server.js`
    if (require.main === module) {
        app.start();
    }
});


================================================
FILE: src/ast.ts
================================================
import * as _ from 'lodash';
import {
  connectionTypeName,
  singularModelName,
  pluralModelName,
  methodName,
  edgeTypeName,
  sharedRelations,
  idToCursor,
} from './utils';
import { findRelated, findAll, findOne, resolveConnection } from './execution';
import { ITypesHash } from './interfaces';

/*** Loopback Types - GraphQL types
        any - JSON
        Array - [JSON]
        Boolean = boolean
        Buffer - not supported
        Date - Date (custom scalar)
        GeoPoint - not supported
        null - not supported
        Number = float
        Object = JSON (custom scalar)
        String - string
    ***/

let types: ITypesHash = {};

const exchangeTypes = {
  'any': 'JSON',
  'Any': 'JSON',
  'Number': 'Int',
  'number': 'Int',
  'Object': 'JSON',
  'object': 'JSON',
};

const SCALARS = {
  any: 'JSON',
  number: 'Float',
  string: 'String',
  boolean: 'Boolean',
  objectid: 'ID',
  date: 'Date',
  object: 'JSON',
  now: 'Date',
  guid: 'ID',
  uuid: 'ID',
  uuidv4: 'ID',
  geopoint: 'GeoPoint',
};

const PAGINATION = 'where: JSON, after: String, first: Int, before: String, last: Int';
const IDPARAMS = 'id: ID!';

function getScalar(type: string) {
  return SCALARS[type.toLowerCase().trim()];
}

function toTypes(union: string[]) {
  return _.map(union, type => {
    return getScalar(type) ? getScalar(type) : type;
  });
}

function mapProperty(model: any, property: any, modelName: string, propertyName: string) {
  if (property.deprecated) {
    return;
  }
  types[modelName].fields[propertyName] = {
    required: property.required,
    hidden: model.definition.settings.hidden && model.definition.settings.hidden.indexOf(propertyName) !== -1,
  };
  let currentProperty = types[modelName].fields[propertyName];

  let typeName = `${modelName}_${propertyName}`;
  let propertyType = property.type;

  if (propertyType.name === 'Array') { // JSON Array
    currentProperty.list = true;
    currentProperty.gqlType = 'JSON';
    currentProperty.scalar = true;
    return;
  }

  if (_.isArray(property.type)) {
    currentProperty.list = true;
    propertyType = property.type[0];
  }

  let scalar = getScalar(propertyType.name);
  if (property.defaultFn) {
    scalar = getScalar(property.defaultFn);
  }
  if (scalar) {
    currentProperty.scalar = true;
    currentProperty.gqlType = scalar;
    if (property.enum) { // enum has a dedicated type but no input type is required
      types[typeName] = {
        values: property.enum,
        category: 'ENUM',
      };
      currentProperty.gqlType = typeName;
    }
  }

  if (propertyType.name === 'ModelConstructor' && property.defaultFn !== 'now') {
    currentProperty.gqlType = propertyType.modelName;
    let union = propertyType.modelName.split('|');
    //type is a union
    if (union.length > 1) { // union type
      types[typeName] = { // creating a new union type
        category: 'UNION',
        values: toTypes(union),
      };
    } else if (propertyType.settings && propertyType.settings.anonymous && propertyType.definition) {
      currentProperty.gqlType = typeName;
      types[typeName] = {
        category: 'TYPE',
        input: true,
        fields: {},
      }; // creating a new type
      _.forEach(propertyType.definition.properties, (p, key) => {
        mapProperty(propertyType, p, typeName, key);
      });
    }
  }
}

function mapRelation(rel: any, modelName: string, relName: string) {
  types[modelName].fields[relName] = {
    relation: true,
    embed: rel.embed,
    gqlType: connectionTypeName(rel.modelTo),
    args: PAGINATION,
    resolver: (obj, args) => {
      return findRelated(rel, obj, args);
    },
  };
}

/*
function generateReturns(name, props) {
    if (_.isObject(props)) {
        props = [props];
    }
    let args;
    args = _.map(props, prop => {
        if (_.isArray(prop.type)) {
            return `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}`;
        } else if (toType(prop.type)) {
            return `${prop.arg}: ${toType(prop.type)}${prop.required ? '!' : ''}`;
        }
        return '';
    }).join(' \n ');
    return args ? `{${args}}` : '';
}

function generateAccepts(name, props) {
    let ret = _.map(props, prop => {
        let propType = prop.type;
        if (_.isArray(prop.type)) {
            propType = prop.type[0];
        }
        return propType ? `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}` : '';
    }).join(' \n ');
    return ret ? `(${ret})` : '';

}
*/

function addRemoteHooks(model: any) {

  _.map(model.sharedClass._methods, (method: any) => {
    if (method.accessType !== 'READ' && method.http.path) {
      let acceptingParams = '',
        returnType = 'JSON';
      method.accepts.map(function (param) {
        let paramType = '';
        if (typeof param.type === 'object') {
          paramType = 'JSON';
        } else {
          if (!SCALARS[param.type.toLowerCase()]) {
            paramType = `${param.type}Input`;
          } else {
            paramType = _.upperFirst(param.type);
          }
        }
        if (param.arg) {
          acceptingParams += `${param.arg}: ${exchangeTypes[paramType] || paramType} `;
        }
      });
      if (method.returns && method.returns[0]) {
        if (!SCALARS[method.returns[0].type] && typeof method.returns[0].type !== 'object') {
          returnType = `${method.returns[0].type}`;
        } else {
          returnType = `${_.upperFirst(method.returns[0].type)}`;
          if (typeof method.returns[0].type === 'object') {
            returnType = 'JSON';
          }
        }
      }
      types.Mutation.fields[`${methodName(method, model)}`] = {
        relation: true,
        args: acceptingParams,
        gqlType: `${exchangeTypes[returnType] || returnType}`,
      };
    }
  });
}

function mapRoot(model) {
  types.Query.fields[singularModelName(model)] = {
    relation: true,
    args: IDPARAMS,
    root: true,
    gqlType: singularModelName(model),
    resolver: (obj, args /*, context*/) => {
      findOne(model, obj, args);
    },
  };

  types.Query.fields[pluralModelName(model)] = {
    relation: true,
    root: true,
    args: PAGINATION,
    gqlType: connectionTypeName(model),
    resolver: (obj, args) => {
      findAll(model, obj, args);
    },
  };

  types.Mutation.fields[`save${singularModelName(model)}`] = {
    relation: true,
    args: `obj: ${singularModelName(model)}Input!`,
    gqlType: singularModelName(model),
    resolver: (context, args) => model.upsert(args.obj, context),
  };

  types.Mutation.fields[`delete${singularModelName(model)}`] = {
    relation: true,
    args: IDPARAMS,
    gqlType: ` ${singularModelName(model)}`,
    resolver: (context, args) => {
      return model.findById(args.id, context)
        .then(instance => instance.destroy());
    },
  };
  // _.each(model.sharedClass.methods, method => {
  //     if (method.accessType !== 'READ' && method.http.path) {
  //         let methodName = methodName(method, model);
  //         types.Mutation.fields[methodName] = {
  //             gqlType: `${generateReturns(method.name, method.returns)}`,
  //             args: `${generateAccepts(method.name, method.accepts)}`
  //         }

  //         return `${methodName(method)}
  //                     ${generateAccepts(method.name, method.accepts)}

  //                 : JSON`;
  //     } else {
  //         return undefined;
  //     }
  // });
  addRemoteHooks(model);
}

function mapConnection(model) {
  types[connectionTypeName(model)] = {
    connection: true,
    category: 'TYPE',
    fields: {
      pageInfo: {
        required: true,
        gqlType: 'pageInfo',
      },
      edges: {
        list: true,
        gqlType: edgeTypeName(model),
        resolver: (obj /*, args, context*/) => {
          return _.map(obj.list, node => {
            return {
              cursor: idToCursor(node[model.getIdName()]),
              node: node,
            };
          });
        },
      },
      totalCount: {
        gqlType: 'Int',
        scalar: true,
        resolver: (obj /*, args, context*/) => {
          return obj.count;
        },
      },
      [model.pluralModelName]: {
        gqlType: singularModelName(model),
        list: true,
        resolver: (obj /*, args, context*/) => {
          return obj.list;
        },
      },
    },
    resolver: (/*obj, args, context*/) => {
      return resolveConnection(model);
    },
  };
  types[edgeTypeName(model)] = {
    category: 'TYPE',
    fields: {
      node: {
        gqlType: singularModelName(model),
        required: true,
      },
      cursor: {
        gqlType: 'String',
        required: true,
      },
    },
  };

}
export function abstractTypes(models: any[]): ITypesHash {
  //building all models types & relationships
  types.pageInfo = {
    category: 'TYPE',
    fields: {
      hasNextPage: {
        gqlType: 'Boolean',
        required: true,
      },
      hasPreviousPage: {
        gqlType: 'Boolean',
        required: true,
      },
      startCursor: {
        gqlType: 'String',
      },
      endCursor: {
        gqlType: 'String',
      },
    },
  };
  types.Query = {
    category: 'TYPE',
    fields: {},
  };
  types.Mutation = {
    category: 'TYPE',
    fields: {},
  };

  _.forEach(models, model => {
    if (model.shared) {
      mapRoot(model);
    }
    types[singularModelName(model)] = {
      category: 'TYPE',
      input: true,
      fields: {},
    };
    _.forEach(model.definition.properties, (property, key) => {
      mapProperty(model, property, singularModelName(model), key);
    });

    mapConnection(model);
    _.forEach(sharedRelations(model), rel => {
      mapRelation(rel, singularModelName(model), rel.name);
      mapConnection(rel.modelTo);
    });
  });
  return types;
}


================================================
FILE: src/boot.ts
================================================
import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';
import { makeExecutableSchema } from 'graphql-tools';
import * as bodyParser from 'body-parser';

import { abstractTypes } from './ast';
import { resolvers } from './resolvers';
import { generateTypeDefs } from './typedefs';

export function boot(app, options) {
  const models = app.models();
  let types = abstractTypes(models);
  let schema = makeExecutableSchema({
    typeDefs: generateTypeDefs(types),
    resolvers: resolvers(models),
    resolverValidationOptions: {
      requireResolversForAllFields: false,
    },
  });

  let graphiqlPath = options.graphiqlPath || '/graphiql';
  let path = options.path || '/graphql';

  app.use(path, bodyParser.json(), graphqlExpress(req => {
    return {
      schema,
      context: req,
    };
  }));
  app.use(graphiqlPath, graphiqlExpress({
    endpointURL: path,
  }));
}


================================================
FILE: src/execution.ts
================================================
import * as _ from 'lodash';

import {
  getId,
  connectionTypeName,
  idToCursor,
} from './utils';

function buildSelector(model, args) {
  let selector = {
    where: args.where || {},
    skip: undefined,
    limit: undefined,
    order: undefined,
  };
  const begin = getId(args.after);
  const end = getId(args.before);

  selector.skip = args.first - args.last || 0;
  selector.limit = args.last || args.first;
  selector.order = model.getIdName() + (end ? ' DESC' : ' ASC');
  if (begin) {
    selector.where[model.getIdName()] = selector[model.getIdName()] || {};
    selector.where[model.getIdName()].gt = begin;
  }
  if (end) {
    selector.where[model.getIdName()] = selector[model.getIdName()] || {};
    selector.where[model.getIdName()].lt = end;
  }
  return selector;
}

function findOne(model, obj, args /*, context*/) {
  let id = obj ? obj[model.getIdName()] : args.id;
  return model.findById(id);
}

function getCount(model, obj, args, context) {
  return model.count(args.where, obj, context);
}

function getFirst(model, obj, args) {
  return model.findOne({
    order: model.getIdName() + (args.before ? ' DESC' : ' ASC'),
    where: args.where,
  }, obj)
    .then(res => {
      return res ? res.__data : {};
    });
}

function getList(model, args) {
  return model.find(buildSelector(model, args));
}

function findAll(model: any, obj: any, args: any) {
  const response = {
    args: args,
    count: undefined,
    first: undefined,
    list: undefined,
  };
  return getCount(model, obj, args, undefined)
    .then(count => {
      response.count = count;
      return getFirst(model, obj, args);
    })
    .then(first => {
      response.first = first;
      return getList(model, args);
    })
    .then(list => {
      response.list = list;
      return response;
    });
}

function findRelated(rel, obj, args) {
  if (_.isArray(obj[rel.keyFrom])) {
    return [];
  }
  args.where = {
    [rel.keyTo]: obj[rel.keyFrom],
  };
  return findAll(rel.modelTo, obj, args);

}

function resolveConnection(model) {
  return {
    [connectionTypeName(model)]: {
      totalCount: (obj) => {
        return obj.count;
      },

      edges: (obj) => {
        return _.map(obj.list, node => {
          return {
            cursor: idToCursor(node[model.getIdName()]),
            node: node,
          };
        });
      },

      [model.pluralModelName]: (obj) => {
        return obj.list;
      },

      pageInfo: (obj) => {
        let pageInfo = {
          startCursor: null,
          endCursor: null,
          hasPreviousPage: false,
          hasNextPage: false,
        };
        if (obj.count > 0) {
          pageInfo.startCursor = idToCursor(obj.list[0][model.getIdName()]);
          pageInfo.endCursor = idToCursor(obj.list[obj.list.length - 1][model.getIdName()]);
          pageInfo.hasNextPage = obj.list.length === obj.args.limit;
          pageInfo.hasPreviousPage = obj.list[0][model.getIdName()] !== obj.first[model.getIdName()].toString();
        }
        return pageInfo;
      },
    },
  };
}

export {
  findAll,
  findOne,
  findRelated,
  resolveConnection,
};


================================================
FILE: src/index.ts
================================================
import { boot } from './boot';
module.exports = boot;


================================================
FILE: src/interfaces.ts
================================================
//export declare function Model(arg?: { hooks?: {}, remotes?: {} }): any;

export interface IProperty {
  type: any;
  deprecated?: Boolean;
  required?: Boolean;
  defaultFn?: any;
  enum?: any;
}

export interface IField {
  list?: Boolean;
  scalar?: Boolean;
  required?: Boolean;
  gqlType: string;
  relation?: any;
  args?: any;
}

export interface ITypesHash {
  [id: string]: any;
}

export interface ISchemaType {
  category: string;
  fields: IField[];
  input: any;
  values: any;
}


================================================
FILE: src/methods.ts
================================================
// import * as _ from 'lodash';
// import {toType} from './ast';
// import {} from './utils';
// import {Property} from './interfaces';


// function generateAccepts(name: string, props: Property[]) {
//   let ret = _.map(props, prop => {
//     let propType = prop.type;
//     if (_.isArray(prop.type)) {
//       propType = prop.type[0];
//     }
//     return propType ? `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}` : '';
//   }).join(' \n ');
//   return ret ? `(${ret})` : '';

// }

// function generateReturns(name, props) {
//   if (_.isObject(props)) {
//     props = [props];
//   }
//   let args;
//   args = _.map(props, prop => {
//     if (_.isArray(prop.type)) {
//       return `${prop.arg}: [${toType(prop.type[0])}]${prop.required ? '!' : ''}`;
//     } else if (toType(prop.type)) {
//       return `${prop.arg}: ${toType(prop.type)}${prop.required ? '!' : ''}`;
//     }
//     return '';
//   }).join(' \n ');
//   return args ? `{${args}}` : '';
// }

// export default function generateMethods(model) {
//   return _.chain(model.sharedClass.methods())
//     .map(method => {
//       if (method.accessType === 'WRITE' && method.http.path) {
//         return `${utils.methodName(method)}
//                         ${generateAccepts(method.name, method.accepts)}
//                         ${generateReturns(method.name, method.returns)}
//                     : JSON`;
//       } else {
//         return undefined;
//       }
//     })
//     .compact()
//     .value()
//     .join(' \n ');
// }


================================================
FILE: src/resolvers.ts
================================================
import * as _ from 'lodash';
import * as utils from './utils';

import * as execution from './execution';
import * as GraphQLJSON from 'graphql-type-json';
import * as GraphQLDate from 'graphql-date';
import {
  CoordinatesScalar,
} from 'graphql-geojson';

const scalarResolvers = {
  JSON: GraphQLJSON,
  Date: GraphQLDate,
  GeoPoint: CoordinatesScalar,
};

function RelationResolver(model) {
  let resolver = {};
  _.forEach(utils.sharedRelations(model), rel => {
    resolver[rel.name] = (obj, args) => {
      return execution.findRelated(rel, obj, args);
    };
  });

  return {
    [utils.singularModelName(model)]: resolver,
  };
}

function rootResolver(model) {
  return {
    Query: {
      [`${utils.pluralModelName(model)}`]: (root, args) => {
        return execution.findAll(model, root, args);
      },
      [`${utils.singularModelName(model)}`]: (obj, args) => {
        return execution.findOne(model, obj, args);
      },
    },
    Mutation: {
      [`save${utils.singularModelName(model)}`]: (_root, args) => {
        return model.upsert(args.obj);
      },
      [`delete${utils.singularModelName(model)}`]: (_root, args) => {
        return model.findById(args.id)
          .then(instance => {
            return instance ? instance.destroy() : null;
          });
      },
    },
  };
}

function connectionResolver(model: any) {
  return {
    [utils.connectionTypeName(model)]: {
      totalCount: (obj) => {
        return obj.count;
      },

      edges: (obj) => {
        return _.map(obj.list, node => {
          return {
            cursor: utils.idToCursor(node[model.getIdName()]),
            node: node,
          };
        });
      },

      [model.pluralModelName]: (obj) => {
        return obj.list;
      },

      pageInfo: (obj) => {
        let pageInfo = {
          startCursor: null,
          endCursor: null,
          hasPreviousPage: false,
          hasNextPage: false,
        };
        if (obj.count > 0) {
          pageInfo.startCursor = utils.idToCursor(obj.list[0][model.getIdName()]);
          pageInfo.endCursor = utils.idToCursor(obj.list[obj.list.length - 1][model.getIdName()]);
          pageInfo.hasNextPage = obj.list.length === obj.args.limit;
          pageInfo.hasPreviousPage = obj.list[0][model.getIdName()] !== obj.first[model.getIdName()].toString();
        }
        return pageInfo;
      },
    },
  };
}

function remoteResolver(model) {
  let mutation = {};
  //model.sharedClass.methods
  if (model.sharedClass && model.sharedClass.methods) {
    model.sharedClass._methods.map(function (method) {
      if (method.accessType !== 'READ' && method.http.path) {
        let acceptingParams = [];
        method.accepts.map(function (param) {
          if (param.arg) {
            acceptingParams.push(param.arg);
          }
        });
        mutation[`${utils.methodName(method, model)}`] = (args) => {
          let params = [];
          _.each(method.accepts, (el, i) => {
            params[i] = args[el.arg];
          });
          return model[method.name].apply(model, params);
        };
      }
    });
  }
  return {
    Mutation: mutation,
  };
}

/**
 * Generate resolvers for all models
 *
 * @param {Object} models: All loopback Models
 * @returns {Object} resolvers functions for all models - queries and mutations
 */
export function resolvers(models: any[]) {
  return _.reduce(models, (obj: any, model: any) => {
    if (model.shared) {
      return _.merge(
        obj,
        rootResolver(model),
        connectionResolver(model),
        RelationResolver(model),
        remoteResolver(model),
      );
    }
    return obj;
  }, scalarResolvers);
}


================================================
FILE: src/typedefs.ts
================================================
import * as _ from 'lodash';
import { ISchemaType, IField, ITypesHash } from './interfaces';

const scalarTypes = `
        scalar Date
        scalar JSON
        scalar GeoPoint
        `;

function args(params: string): string {
  return params ? `(${args})` : '';
}

function generateInputField(field: IField, name: string): string {
  return `
        ${name} : ${field.list ? '[' : ''}
        ${field.gqlType}${field.scalar ? '' : 'Input'}${field.required ? '!' : ''} ${field.list ? ']' : ''}`;
}

function generateOutputField(field: IField, name: string): string {
  return `${name} ${args(field.args)} : ${field.list ? '[' : ''}${field.gqlType}${field.required ? '!' : ''} ${field.list ? ']' : ''}`;
}

export function generateTypeDefs(types: ITypesHash) {
  const categories = {
    TYPE: (type: ISchemaType, name: string) => {
      let output = _.reduce(type.fields, (res: string, field: IField, fieldName: string): string => {
        return res + generateOutputField(field, fieldName) + ' \n ';
      }, '');

      let result = `
                type ${name} {
                    ${output}
                }`;
      if (type.input) {
        let input = _.reduce(type.fields, (accumulator: string, field: IField, fieldName: string) => {
          return !field.relation ? accumulator + generateInputField(field, fieldName) + ' \n ' : accumulator;
        }, '');
        result += `input ${name}Input {
                    ${input}
                }`;
      }
      return result;
    },
    UNION: (type: ISchemaType, name: string) => {
      return `union ${name} = ${type.values.join(' | ')}`;
    },
    ENUM: (type: ISchemaType, name: string) => {
      return `enum ${name} {${type.values.join(' ')}}`;
    },
  };

  return _.reduce(types, (result: string, type: ISchemaType, name: string) => {
    return result + categories[type.category](type, name);
  }, scalarTypes);
}


================================================
FILE: src/utils.ts
================================================
import * as _ from 'lodash';

const PAGINATION = '(where: JSON, after: String, first: Int, before: String, last: Int)';

function base64(i) {
  return (new Buffer(i, 'ascii')).toString('base64');
}

function unbase64(i) {
  return (new Buffer(i, 'base64')).toString('ascii');
}

const PREFIX = 'connection.';

/**
 * Creates the cursor string from an offset.
 * @param {String} id the id to convert
 * @returns {String}   an opaque cursor
 */
function idToCursor(id) {
  return base64(PREFIX + id);
}

/**
 * Rederives the offset from the cursor string.
 * @param {String} cursor   the cursor for conversion
 * @returns {String} id   converted id
 */
function cursorToId(cursor) {
  return unbase64(cursor).substring(PREFIX.length);
}

function getId(cursor) {
  if (cursor === undefined || cursor === null) {
    return null;
  }
  return cursorToId(cursor);
}

function connectionTypeName(model) {
  return `${model.modelName}Connection`;
}

function edgeTypeName(model: any) {
  return `${model.modelName}Edge`; // e.g. UserEdge
}

function singularModelName(model) {
  return model.modelName;
}

function pluralModelName(model: any) {
  return 'all' + _.upperFirst(model.pluralModelName);
}

function sharedRelations(model: any) {
  return _.pickBy(model.relations, rel => rel.modelTo && rel.modelTo.shared);
}

function sharedModels(models: any[]) {
  return _.filter(models, model => {
    return model.shared;
  });
}

function methodName(method, model) {
  return model.modelName + _.upperFirst(method.name);
}
export {
  PAGINATION,
  getId,
  idToCursor,
  cursorToId,
  connectionTypeName,
  edgeTypeName,
  singularModelName,
  methodName,
  pluralModelName,
  sharedRelations,
  sharedModels,
};


================================================
FILE: tsconfig.json
================================================
{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "moduleResolution": "node",
        "noImplicitAny": false,
        "allowSyntheticDefaultImports": true,
        "allowJs": true,
        "importHelpers": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitThis": true,
        "alwaysStrict": true,
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "declaration": false,
        "outDir": "build",
        "sourceMap": true,
        "watch": true
    },
    "include": [
        "src/**/*",
        "__tests__/**/*"
    ],
    "typeRoots": [
        "node_modules/@types"
    ]
}


================================================
FILE: tsconfig.release.json
================================================
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "sourceMap": false,
        "declaration": false,
        "outDir": "build",
        "removeComments": true,
        "watch": false
    },
    "include": [
        "src/**/*"
    ]
}


================================================
FILE: tsconfig.test.json
================================================
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "allowSyntheticDefaultImports": true,
        "moduleResolution": "node",
        "inlineSourceMap": true
    }
}


================================================
FILE: tslint.json
================================================
{
    "rules": {
        "align": [
            false,
            "parameters",
            "arguments",
            "statements"
        ],
        "ban": false,
        "class-name": true,
        "curly": true,
        "eofline": true,
        "forin": true,
        "indent": [
            true,
            "spaces"
        ],
        "interface-name": [],
        "jsdoc-format": true,
        "label-position": true,
        "max-line-length": [
            true,
            140
        ],
        "member-access": true,
        "member-ordering": [
            true,
            "public-before-private",
            "static-before-instance",
            "variables-before-functions"
        ],
        "no-any": false,
        "no-arg": true,
        "no-bitwise": true,
        "no-conditional-assignment": true,
        "no-consecutive-blank-lines": false,
        "no-console": [
            true,
            "log",
            "debug",
            "info",
            "time",
            "timeEnd",
            "trace"
        ],
        "no-construct": true,
        "no-debugger": true,
        "no-duplicate-variable": true,
        "no-empty": true,
        "no-eval": true,
        "no-inferrable-types": [],
        "no-internal-module": true,
        "no-null-keyword": false,
        "no-require-imports": false,
        "no-shadowed-variable": true,
        "no-switch-case-fall-through": true,
        "no-trailing-whitespace": true,
        "no-unused-expression": true,
        "no-var-keyword": true,
        "no-var-requires": true,
        "object-literal-sort-keys": false,
        "one-line": [
            true,
            "check-open-brace",
            "check-catch",
            "check-else",
            "check-finally",
            "check-whitespace"
        ],
        "quotemark": [
            true,
            "single",
            "avoid-escape"
        ],
        "radix": true,
        "semicolon": [
            true,
            "always"
        ],
        "switch-default": true,
        "trailing-comma": [
            true,
            {
                "multiline": "always",
                "singleline": "never"
            }
        ],
        "triple-equals": [
            true,
            "allow-null-check"
        ],
        "typedef": [
            false,
            "call-signature",
            "parameter",
            "arrow-parameter",
            "property-declaration",
            "variable-declaration",
            "member-variable-declaration"
        ],
        "typedef-whitespace": [
            true,
            {
                "call-signature": "nospace",
                "index-signature": "nospace",
                "parameter": "nospace",
                "property-declaration": "nospace",
                "variable-declaration": "nospace"
            },
            {
                "call-signature": "space",
                "index-signature": "space",
                "parameter": "space",
                "property-declaration": "space",
                "variable-declaration": "space"
            }
        ],
        "variable-name": [
            true,
            "check-format",
            "allow-leading-underscore",
            "ban-keywords"
        ],
        "whitespace": [
            true,
            "check-branch",
            "check-decl",
            "check-operator",
            "check-separator",
            "check-type"
        ]
    }
}
Download .txt
gitextract_knu9ajem/

├── .editorconfig
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .jsbeautifyrc
├── .npmignore
├── .travis.yml
├── .vscode/
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── .yo-rc.json
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── __test__/
│   ├── data.json
│   ├── mutation.spec.ts
│   ├── pagination.spec.ts
│   ├── query.spec.ts
│   └── testHelper.ts
├── client/
│   └── README.md
├── common/
│   ├── models/
│   │   ├── account.js
│   │   ├── account.json
│   │   ├── address.js
│   │   ├── address.json
│   │   ├── author.js
│   │   ├── author.json
│   │   ├── book.json
│   │   ├── catalogs.js
│   │   ├── catalogs.json
│   │   ├── customer.js
│   │   ├── customer.json
│   │   ├── email-address.js
│   │   ├── email-address.json
│   │   ├── googlemaps.js
│   │   ├── googlemaps.json
│   │   ├── link.json
│   │   ├── note.js
│   │   ├── note.json
│   │   ├── order.js
│   │   ├── order.json
│   │   ├── products.js
│   │   ├── products.json
│   │   └── reader.json
│   └── types/
│       └── content.json
├── data.json
├── jsconfig.json
├── package.json
├── server/
│   ├── boot/
│   │   ├── authentication.js
│   │   └── root.js
│   ├── component-config.json
│   ├── config.json
│   ├── data.json
│   ├── datasources.json
│   ├── middleware.development.json
│   ├── middleware.json
│   ├── model-config.json
│   └── server.js
├── src/
│   ├── ast.ts
│   ├── boot.ts
│   ├── execution.ts
│   ├── index.ts
│   ├── interfaces.ts
│   ├── methods.ts
│   ├── resolvers.ts
│   ├── typedefs.ts
│   └── utils.ts
├── tsconfig.json
├── tsconfig.release.json
├── tsconfig.test.json
└── tslint.json
Download .txt
SYMBOL INDEX (48 symbols across 8 files)

FILE: __test__/testHelper.ts
  function gqlRequest (line 6) | function gqlRequest(query: any, status: number, variables?: object) {

FILE: src/ast.ts
  constant SCALARS (line 38) | const SCALARS = {
  constant PAGINATION (line 53) | const PAGINATION = 'where: JSON, after: String, first: Int, before: Stri...
  constant IDPARAMS (line 54) | const IDPARAMS = 'id: ID!';
  function getScalar (line 56) | function getScalar(type: string) {
  function toTypes (line 60) | function toTypes(union: string[]) {
  function mapProperty (line 66) | function mapProperty(model: any, property: any, modelName: string, prope...
  function mapRelation (line 130) | function mapRelation(rel: any, modelName: string, relName: string) {
  function addRemoteHooks (line 172) | function addRemoteHooks(model: any) {
  function mapRoot (line 212) | function mapRoot(model) {
  function mapConnection (line 268) | function mapConnection(model) {
  function abstractTypes (line 323) | function abstractTypes(models: any[]): ITypesHash {

FILE: src/boot.ts
  function boot (line 9) | function boot(app, options) {

FILE: src/execution.ts
  function buildSelector (line 9) | function buildSelector(model, args) {
  function findOne (line 33) | function findOne(model, obj, args /*, context*/) {
  function getCount (line 38) | function getCount(model, obj, args, context) {
  function getFirst (line 42) | function getFirst(model, obj, args) {
  function getList (line 52) | function getList(model, args) {
  function findAll (line 56) | function findAll(model: any, obj: any, args: any) {
  function findRelated (line 78) | function findRelated(rel, obj, args) {
  function resolveConnection (line 89) | function resolveConnection(model) {

FILE: src/interfaces.ts
  type IProperty (line 3) | interface IProperty {
  type IField (line 11) | interface IField {
  type ITypesHash (line 20) | interface ITypesHash {
  type ISchemaType (line 24) | interface ISchemaType {

FILE: src/resolvers.ts
  function RelationResolver (line 17) | function RelationResolver(model) {
  function rootResolver (line 30) | function rootResolver(model) {
  function connectionResolver (line 54) | function connectionResolver(model: any) {
  function remoteResolver (line 93) | function remoteResolver(model) {
  function resolvers (line 126) | function resolvers(models: any[]) {

FILE: src/typedefs.ts
  function args (line 10) | function args(params: string): string {
  function generateInputField (line 14) | function generateInputField(field: IField, name: string): string {
  function generateOutputField (line 20) | function generateOutputField(field: IField, name: string): string {
  function generateTypeDefs (line 24) | function generateTypeDefs(types: ITypesHash) {

FILE: src/utils.ts
  constant PAGINATION (line 3) | const PAGINATION = '(where: JSON, after: String, first: Int, before: Str...
  function base64 (line 5) | function base64(i) {
  function unbase64 (line 9) | function unbase64(i) {
  constant PREFIX (line 13) | const PREFIX = 'connection.';
  function idToCursor (line 20) | function idToCursor(id) {
  function cursorToId (line 29) | function cursorToId(cursor) {
  function getId (line 33) | function getId(cursor) {
  function connectionTypeName (line 40) | function connectionTypeName(model) {
  function edgeTypeName (line 44) | function edgeTypeName(model: any) {
  function singularModelName (line 48) | function singularModelName(model) {
  function pluralModelName (line 52) | function pluralModelName(model: any) {
  function sharedRelations (line 56) | function sharedRelations(model: any) {
  function sharedModels (line 60) | function sharedModels(models: any[]) {
  function methodName (line 66) | function methodName(method, model) {
Condensed preview — 71 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (97K chars).
[
  {
    "path": ".editorconfig",
    "chars": 301,
    "preview": "# EditorConfig helps developers define and maintain consistent\r\n# coding styles between different editors and IDEs\r\n# ht"
  },
  {
    "path": ".eslintignore",
    "chars": 32,
    "preview": "/client/*\r\n/coverage/**\r\n/out/**"
  },
  {
    "path": ".eslintrc.json",
    "chars": 3824,
    "preview": "{\n    \"root\": true,\n    \"env\": {\n        \"amd\": true,\n        \"browser\": true,\n        \"mocha\": true,\n        \"es6\": tru"
  },
  {
    "path": ".gitignore",
    "chars": 292,
    "preview": "# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Dependencies\nnode_modules/\n\n# Coverage\ncoverage\n\n# Transpiled files\nbuild/\n\n# VS Cod"
  },
  {
    "path": ".jsbeautifyrc",
    "chars": 1239,
    "preview": "{\n  \"html\": {\n    \"allowed_file_extensions\": [\"htm\", \"html\", \"xhtml\", \"shtml\", \"xml\", \"svg\"],\n    \"brace_style\": \"collap"
  },
  {
    "path": ".npmignore",
    "chars": 89,
    "preview": "server\nclient\ntest\ncoverage\nresources\ncommon\ndata.json\n.vscode\n.github\n./data.json\nbuild\n"
  },
  {
    "path": ".travis.yml",
    "chars": 570,
    "preview": "language: node_js\nnode_js:\n  - \"6\"\n  - \"7\"\n\ncache:\n  directories:\n    - ${HOME}/.npm\n\nbefore_install:\n  - npm config set"
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1830,
    "preview": "{\n    \"version\": \"0.2.0\",\n    \"configurations\": [\n\n        {\n            \"name\": \"Tests\",\n            \"type\": \"node\",\n  "
  },
  {
    "path": ".vscode/settings.json",
    "chars": 189,
    "preview": "// Place your settings in this file to overwrite default and user settings.\n{\n    \"search.exclude\": {\n        \"out\": tru"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 0,
    "preview": ""
  },
  {
    "path": ".yo-rc.json",
    "chars": 32,
    "preview": "{\r\n  \"generator-loopback\": {}\r\n}"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5376,
    "preview": "# Change Log\n\nAll notable changes to this project will be documented in this file. See [standard-version](https://github"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 223,
    "preview": "# Guidelines for contributors\n\nIf you're unsure whether your pull request or feature is something that has a chance of b"
  },
  {
    "path": "LICENSE",
    "chars": 1078,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2017 Tally Barak\n\nPermission is hereby granted, free of charge, to any person obtai"
  },
  {
    "path": "README.md",
    "chars": 1733,
    "preview": "\n# Deprecation Warning: \nI have been very bad at maintaining this repo, and do not see how I come back to it in the near"
  },
  {
    "path": "__test__/data.json",
    "chars": 3604,
    "preview": "{\n    \"ids\": {\n        \"User\": 3,\n        \"AccessToken\": 1,\n        \"ACL\": 1,\n        \"RoleMapping\": 1,\n        \"Role\": "
  },
  {
    "path": "__test__/mutation.spec.ts",
    "chars": 2919,
    "preview": "'use strict';\nimport { gqlRequest } from './testHelper';\nimport gql from 'graphql-tag';\n// var _ = require('lodash');\n\nd"
  },
  {
    "path": "__test__/pagination.spec.ts",
    "chars": 2842,
    "preview": "'use strict';\nimport { gqlRequest } from './testHelper';\nimport gql from 'graphql-tag';\n// var _ = require('lodash');\n\nd"
  },
  {
    "path": "__test__/query.spec.ts",
    "chars": 2741,
    "preview": "'use strict';\nimport { gqlRequest } from './testHelper';\nimport gql from 'graphql-tag';\n\ndescribe('query', () => {\n\n  de"
  },
  {
    "path": "__test__/testHelper.ts",
    "chars": 282,
    "preview": "'use strict';\n\nimport request from 'supertest';\nimport app from '../server/server.js';\n\nexport function gqlRequest(query"
  },
  {
    "path": "client/README.md",
    "chars": 67,
    "preview": "## Client\n\nThis is the place for your application front-end files.\n"
  },
  {
    "path": "common/models/account.js",
    "chars": 262,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "common/models/account.json",
    "chars": 259,
    "preview": "{\n  \"name\": \"Account\",\n  \"base\": \"PersistedModel\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"name\": {\n      \"type\": "
  },
  {
    "path": "common/models/address.js",
    "chars": 262,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "common/models/address.json",
    "chars": 341,
    "preview": "{\n  \"name\": \"Address\",\n  \"base\": \"Model\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"street\": {\n      \"type\": \"string"
  },
  {
    "path": "common/models/author.js",
    "chars": 804,
    "preview": "'use strict';\n\nmodule.exports = function(Author) {\n\n    Author.remoteMethod(\n        'addFriend', {\n            'http': "
  },
  {
    "path": "common/models/author.json",
    "chars": 1012,
    "preview": "{\n    \"name\": \"Author\",\n    \"plural\": \"Authors\",\n    \"base\": \"PersistedModel\",\n    \"idInjection\": true,\n    \"options\": {"
  },
  {
    "path": "common/models/book.json",
    "chars": 338,
    "preview": "{\n  \"name\": \"Book\",\n  \"base\": \"PersistedModel\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"name\": {\n      \"type\": \"st"
  },
  {
    "path": "common/models/catalogs.js",
    "chars": 56,
    "preview": "'use strict';\n\nmodule.exports = function(Catalogs) {\n\n};"
  },
  {
    "path": "common/models/catalogs.json",
    "chars": 901,
    "preview": "{\n    \"name\": \"catalogs\",\n    \"base\": \"PersistedModel\",\n    \"idInjection\": true,\n    \"options\": {\n        \"validateUpser"
  },
  {
    "path": "common/models/customer.js",
    "chars": 263,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "common/models/customer.json",
    "chars": 932,
    "preview": "{\n  \"name\": \"Customer\",\n  \"base\": \"PersistedModel\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"name\": {\n      \"type\":"
  },
  {
    "path": "common/models/email-address.js",
    "chars": 267,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "common/models/email-address.json",
    "chars": 256,
    "preview": "{\n  \"name\": \"EmailAddress\",\n  \"base\": \"Model\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"label\": {\n      \"type\": \"st"
  },
  {
    "path": "common/models/googlemaps.js",
    "chars": 56,
    "preview": "'use strict';\n\nmodule.exports = function(Googlemaps) {};"
  },
  {
    "path": "common/models/googlemaps.json",
    "chars": 4828,
    "preview": "{\n    \"name\": \"Googlemaps\",\n    \"plural\": \"Googlemaps\",\n    \"base\": \"PersistedModel\",\n    \"idInjection\": false,\n    \"opt"
  },
  {
    "path": "common/models/link.json",
    "chars": 530,
    "preview": "{\n  \"name\": \"Link\",\n  \"base\": \"Model\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"id\": {\n      \"type\": \"number\",\n    "
  },
  {
    "path": "common/models/note.js",
    "chars": 563,
    "preview": "'use strict';\n\nmodule.exports = function(Note) {\n\n    Note.clear = () => {\n        return {\n            note: {\n        "
  },
  {
    "path": "common/models/note.json",
    "chars": 1122,
    "preview": "{\n    \"name\": \"Note\",\n    \"properties\": {\n        \"title\": {\n            \"type\": \"string\",\n            \"required\": true\n"
  },
  {
    "path": "common/models/order.js",
    "chars": 260,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "common/models/order.json",
    "chars": 409,
    "preview": "{\n  \"name\": \"Order\",\n  \"base\": \"PersistedModel\",\n  \"idInjection\": true,\n  \"options\": {\n    \"validateUpsert\": true\n  },\n "
  },
  {
    "path": "common/models/products.js",
    "chars": 56,
    "preview": "'use strict';\n\nmodule.exports = function(Products) {\n\n};"
  },
  {
    "path": "common/models/products.json",
    "chars": 902,
    "preview": "{\n    \"name\": \"products\",\n    \"base\": \"PersistedModel\",\n    \"idInjection\": true,\n    \"options\": {\n        \"validateUpser"
  },
  {
    "path": "common/models/reader.json",
    "chars": 211,
    "preview": "{\n  \"name\": \"Reader\",\n  \"base\": \"PersistedModel\",\n  \"idInjection\": true,\n  \"properties\": {\n    \"name\": {\n      \"type\": \""
  },
  {
    "path": "common/types/content.json",
    "chars": 435,
    "preview": "{\n    \"name\": \"Content\",\n    \"plural\": \"Content\",\n    \"base\": \"Model\",\n    \"idInjection\": false,\n    \"options\": {\n      "
  },
  {
    "path": "data.json",
    "chars": 1267,
    "preview": "{\n  \"ids\": {\n    \"User\": 1,\n    \"AccessToken\": 1,\n    \"ACL\": 1,\n    \"RoleMapping\": 1,\n    \"Role\": 1,\n    \"Customer\": 1,\n"
  },
  {
    "path": "jsconfig.json",
    "chars": 375,
    "preview": "{\r\n\t// See https://go.microsoft.com/fwlink/?LinkId=759670\r\n\t// for the documentation about the jsconfig.json format\r\n\t\"c"
  },
  {
    "path": "package.json",
    "chars": 3656,
    "preview": "{\n    \"name\": \"loopback-graphql\",\n    \"version\": \"0.13.0\",\n    \"description\": \"Add Apollo Server or GraphQL queries on y"
  },
  {
    "path": "server/boot/authentication.js",
    "chars": 308,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "server/boot/root.js",
    "chars": 258,
    "preview": "// Copyright IBM Corp. 2015. All Rights Reserved.\n// Node module: loopback-example-relations\n// This file is licensed un"
  },
  {
    "path": "server/component-config.json",
    "chars": 109,
    "preview": "{\n    \"loopback-component-explorer\": {\n        \"mountPath\": \"/explorer\"\n    },\n    \"../build/index.js\": {}\n}\n"
  },
  {
    "path": "server/config.json",
    "chars": 395,
    "preview": "{\n  \"restApiRoot\": \"/api\",\n  \"host\": \"0.0.0.0\",\n  \"port\": 3000,\n  \"remoting\": {\n    \"context\": false,\n    \"rest\": {\n    "
  },
  {
    "path": "server/data.json",
    "chars": 3604,
    "preview": "{\n    \"ids\": {\n        \"User\": 3,\n        \"AccessToken\": 1,\n        \"ACL\": 1,\n        \"RoleMapping\": 1,\n        \"Role\": "
  },
  {
    "path": "server/datasources.json",
    "chars": 190,
    "preview": "{\n    \"db\": {\n        \"name\": \"db\",\n        \"connector\": \"memory\",\n        \"file\": \"./data.json\"\n    },\n    \"transient\":"
  },
  {
    "path": "server/middleware.development.json",
    "chars": 132,
    "preview": "{\n  \"final:after\": {\n    \"strong-error-handler\": {\n      \"params\": {\n        \"debug\": true,\n        \"log\": true\n      }\n"
  },
  {
    "path": "server/middleware.json",
    "chars": 547,
    "preview": "{\n  \"initial:before\": {\n    \"loopback#favicon\": {}\n  },\n  \"initial\": {\n    \"compression\": {},\n    \"cors\": {\n      \"param"
  },
  {
    "path": "server/model-config.json",
    "chars": 1645,
    "preview": "{\n    \"_meta\": {\n        \"sources\": [\n            \"loopback/common/models\",\n            \"loopback/server/models\",\n      "
  },
  {
    "path": "server/server.js",
    "chars": 923,
    "preview": "'use strict';\n\nvar loopback = require('loopback');\nvar boot = require('loopback-boot');\n\nvar app = module.exports = loop"
  },
  {
    "path": "src/ast.ts",
    "chars": 9814,
    "preview": "import * as _ from 'lodash';\nimport {\n  connectionTypeName,\n  singularModelName,\n  pluralModelName,\n  methodName,\n  edge"
  },
  {
    "path": "src/boot.ts",
    "chars": 900,
    "preview": "import { graphqlExpress, graphiqlExpress } from 'graphql-server-express';\nimport { makeExecutableSchema } from 'graphql-"
  },
  {
    "path": "src/execution.ts",
    "chars": 3129,
    "preview": "import * as _ from 'lodash';\n\nimport {\n  getId,\n  connectionTypeName,\n  idToCursor,\n} from './utils';\n\nfunction buildSel"
  },
  {
    "path": "src/index.ts",
    "chars": 54,
    "preview": "import { boot } from './boot';\nmodule.exports = boot;\n"
  },
  {
    "path": "src/interfaces.ts",
    "chars": 495,
    "preview": "//export declare function Model(arg?: { hooks?: {}, remotes?: {} }): any;\n\nexport interface IProperty {\n  type: any;\n  d"
  },
  {
    "path": "src/methods.ts",
    "chars": 1547,
    "preview": "// import * as _ from 'lodash';\n// import {toType} from './ast';\n// import {} from './utils';\n// import {Property} from "
  },
  {
    "path": "src/resolvers.ts",
    "chars": 3668,
    "preview": "import * as _ from 'lodash';\nimport * as utils from './utils';\n\nimport * as execution from './execution';\nimport * as Gr"
  },
  {
    "path": "src/typedefs.ts",
    "chars": 1898,
    "preview": "import * as _ from 'lodash';\nimport { ISchemaType, IField, ITypesHash } from './interfaces';\n\nconst scalarTypes = `\n    "
  },
  {
    "path": "src/utils.ts",
    "chars": 1709,
    "preview": "import * as _ from 'lodash';\n\nconst PAGINATION = '(where: JSON, after: String, first: Int, before: String, last: Int)';\n"
  },
  {
    "path": "tsconfig.json",
    "chars": 700,
    "preview": "{\n    \"compilerOptions\": {\n        \"target\": \"es6\",\n        \"module\": \"commonjs\",\n        \"moduleResolution\": \"node\",\n  "
  },
  {
    "path": "tsconfig.release.json",
    "chars": 252,
    "preview": "{\n    \"extends\": \"./tsconfig.json\",\n    \"compilerOptions\": {\n        \"sourceMap\": false,\n        \"declaration\": false,\n "
  },
  {
    "path": "tsconfig.test.json",
    "chars": 183,
    "preview": "{\n    \"extends\": \"./tsconfig.json\",\n    \"compilerOptions\": {\n        \"allowSyntheticDefaultImports\": true,\n        \"modu"
  },
  {
    "path": "tslint.json",
    "chars": 3453,
    "preview": "{\n    \"rules\": {\n        \"align\": [\n            false,\n            \"parameters\",\n            \"arguments\",\n            \"s"
  }
]

About this extraction

This page contains the full source code of the Tallyb/loopback-graphql GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 71 files (83.8 KB), approximately 23.7k tokens, and a symbol index with 48 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!