Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
0fc1236266 | |||
52ee2cf6a3 | |||
50ba6732fe | |||
a8ad87115e | |||
bcc443bd59 | |||
4e7f938f53 | |||
4683936de0 | |||
6f1a2acf96 |
34
README.md
34
README.md
@ -1,24 +1,30 @@
|
|||||||
<a href="https://supergraph.dev"><img src="https://supergraph.dev/logo.svg" width="100" height="100" align="right" /></a>
|
<a href="https://supergraph.dev"><img src="https://supergraph.dev/hologram.svg" width="100" height="100" align="right" /></a>
|
||||||
|
|
||||||
# Super Graph - Instant GraphQL API for Rails
|
# Super Graph - Build web products faster. Instant GraphQL APIs for your apps
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
[](https://discord.gg/6pSWCTZ)
|
||||||
|
|
||||||
Get an high-performance GraphQL API for your Rails app in seconds without writing a line of code. Super Graph will auto-learn your database structure and relationships. Built in support for Rails authentication and JWT tokens.
|
Get an instant high performance GraphQL API for Postgres. No code needed. GraphQL is automatically transformed into efficient database queries.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Why I built Super Graph?
|
## The story of Super Graph?
|
||||||
|
|
||||||
Honestly, cause it was more fun than my real work. After working on several product though my career I found myself hating building CRUD APIs (Create, Update, Delete, List, Show). It was always the same thing figure out what the UI needs then build an endpoint for it, if related data is needed than join with another table. I didn't want to write that code anymore I wanted the computer to just do it.
|
After working on several products through my career I find that we spend way too much time on building API backends. Most APIs also require constant updating, this costs real time and money.
|
||||||
|
|
||||||
|
It's always the same thing, figure out what the UI needs then build an endpoint for it. Most API code involves struggling with an ORM to query a database and mangle the data into a shape that the UI expects to see.
|
||||||
|
|
||||||
I always liked GraphQL it sounded friendly, but it still required me to write all the same database query code. Sure the API was nicer but it took a lot of work sometime even more than a simple REST API would have. I wanted a GraphQL server that just worked the second you deployed it without having to write a line of code.
|
I didn't want to write this code anymore, I wanted the computer to do it. Enter GraphQL, to me it sounded great, but it still required me to write all the same database query code.
|
||||||
|
|
||||||
And so after a lot of coffee and some Avocado toasts __Super Graph was born, a GraphQL server that just works, is high performance and easy to deploy__. I hope you find it as useful as I do and there's a lot more coming so hit that :star: to stay in the loop.
|
Having worked with compilers before I saw this as a compiler problem. Why not build a compiler that converts GraphQL to highly efficient SQL.
|
||||||
|
|
||||||
|
This compiler is what sits at the heart of Super Graph with layers of useful functionality around it like authentication, remote joins, rails integration, database migrations and everything else needed for you to build production ready apps with it.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Works with Rails database schemas
|
- Works with Rails database schemas
|
||||||
- Automatically learns schemas and relationships
|
- Automatically learns schemas and relationships
|
||||||
- Belongs-To, One-To-Many and Many-To-Many table relationships
|
- Belongs-To, One-To-Many and Many-To-Many table relationships
|
||||||
@ -27,14 +33,12 @@ And so after a lot of coffee and some Avocado toasts __Super Graph was born, a G
|
|||||||
- JWT tokens supported (Auth0, etc)
|
- JWT tokens supported (Auth0, etc)
|
||||||
- Join with remote REST APIs
|
- Join with remote REST APIs
|
||||||
- Highly optimized and fast Postgres SQL queries
|
- Highly optimized and fast Postgres SQL queries
|
||||||
|
- Support GraphQL queries and mutations
|
||||||
- Configure with a simple config file
|
- Configure with a simple config file
|
||||||
- High performance GO codebase
|
- High performance GO codebase
|
||||||
- Tiny docker image and low memory requirements
|
- Tiny docker image and low memory requirements
|
||||||
|
- Database migrations tool
|
||||||
## Watch some talks
|
- Write database seeding scripts in Javascript
|
||||||
|
|
||||||
[](https://youtu.be/TGq9wJAj78I)
|
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
@ -42,7 +46,9 @@ And so after a lot of coffee and some Avocado toasts __Super Graph was born, a G
|
|||||||
|
|
||||||
## Contact me
|
## Contact me
|
||||||
|
|
||||||
[twitter.com/dosco](https://twitter.com/dosco)
|
[twitter/dosco](https://twitter.com/dosco)
|
||||||
|
|
||||||
|
[chat/super-graph](https://discord.gg/6pSWCTZ)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
@ -2,20 +2,91 @@
|
|||||||
|
|
||||||
variables {
|
variables {
|
||||||
"update": {
|
"update": {
|
||||||
"name": "Hellooooo",
|
"name": "Wu-Tang",
|
||||||
"description": "World"
|
"description": "No description needed"
|
||||||
},
|
},
|
||||||
"user": 123
|
"product_id": 1
|
||||||
}
|
}
|
||||||
|
|
||||||
mutation {
|
mutation {
|
||||||
products(update: $update, where: {id: {eq: 134}}) {
|
products(id: $product_id, update: $update) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": {
|
||||||
|
"email": "gfk@myspace.com",
|
||||||
|
"full_name": "Ghostface Killah",
|
||||||
|
"created_at": "now",
|
||||||
|
"updated_at": "now"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation {
|
||||||
|
user(insert: $data) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": {
|
||||||
|
"product_id": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation {
|
||||||
|
products(id: $product_id, delete: true) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query {
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
picture: avatar
|
||||||
|
products(limit: 2, where: {price: {gt: 10}}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variables {
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "Protect Ya Neck",
|
||||||
|
"created_at": "now",
|
||||||
|
"updated_at": "now"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Enter the Wu-Tang",
|
||||||
|
"created_at": "now",
|
||||||
|
"updated_at": "now"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation {
|
||||||
|
products(insert: $data) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query {
|
||||||
|
me {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
full_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
variables {
|
variables {
|
||||||
"update": {
|
"update": {
|
||||||
"name": "Helloo",
|
"name": "Helloo",
|
||||||
@ -30,40 +101,4 @@ mutation {
|
|||||||
name
|
name
|
||||||
description
|
description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query {
|
|
||||||
me {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
full_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
variables {
|
|
||||||
"update": {
|
|
||||||
"name": "Hellooooo",
|
|
||||||
"description": "World",
|
|
||||||
"created_at": "now",
|
|
||||||
"updated_at": "now"
|
|
||||||
},
|
|
||||||
"user": 123
|
|
||||||
}
|
|
||||||
|
|
||||||
mutation {
|
|
||||||
products(update: $update, where: {id: {eq: 134}}) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
query {
|
|
||||||
me {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
full_name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -22,7 +22,7 @@ enable_tracing: true
|
|||||||
|
|
||||||
# Watch the config folder and reload Super Graph
|
# Watch the config folder and reload Super Graph
|
||||||
# with the new configs when a change is detected
|
# with the new configs when a change is detected
|
||||||
reload_on_config_change: true
|
reload_on_config_change: false
|
||||||
|
|
||||||
# File that points to the database seeding script
|
# File that points to the database seeding script
|
||||||
# seed_file: seed.js
|
# seed_file: seed.js
|
||||||
|
@ -11,16 +11,16 @@ services:
|
|||||||
# ports:
|
# ports:
|
||||||
# - "6379:6379"
|
# - "6379:6379"
|
||||||
|
|
||||||
# rails_app:
|
rails_app:
|
||||||
# build: rails-app/.
|
build: rails-app/.
|
||||||
# command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
|
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
|
||||||
# volumes:
|
volumes:
|
||||||
# - ./rails-app:/app
|
- ./rails-app:/app
|
||||||
# - /app/tmp
|
- /app/tmp
|
||||||
# ports:
|
ports:
|
||||||
# - "3000:3000"
|
- "3000:3000"
|
||||||
# depends_on:
|
depends_on:
|
||||||
# - db
|
- db
|
||||||
|
|
||||||
super_graph:
|
super_graph:
|
||||||
build:
|
build:
|
||||||
@ -37,6 +37,6 @@ services:
|
|||||||
command: wu -pattern="*.go" go run main.go serv
|
command: wu -pattern="*.go" go run main.go serv
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
#- rails_app
|
- rails_app
|
||||||
|
|
||||||
# - redis
|
# - redis
|
||||||
|
@ -51,21 +51,106 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-gray-100 my-10">
|
<div class="bg-gray-100 mt-10">
|
||||||
<div class="container mx-auto px-10 md:px-0 py-32">
|
<div class="container mx-auto px-10 md:px-0 py-32">
|
||||||
<h1 class="uppercase font-semibold text-xl text-blue-800 mb-4">
|
<h1 class="uppercase font-semibold text-xl text-blue-800 mb-4">
|
||||||
What is {{ data.heroText }}?
|
What is {{ data.heroText }}?
|
||||||
</h1>
|
</h1>
|
||||||
<div class="text-2xl md:text-3xl">
|
<div class="text-2xl md:text-3xl">
|
||||||
{{ data.description }}
|
Super Graph can automatically learn a Postgres database and instantly serve it as a fast and secured GraphQL API. It comes with tools to create a new app and manage it's database. You get it all, a very productive developer and a highly scalable app backend. It's designed to work well on serverless platforms by Google, AWS, Microsoft, etc. The goal is to save you a ton of time and money so you can focus on you're apps core value.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="theme-default-content markdown">
|
<div class="flex flex-wrap">
|
||||||
<Content />
|
<div class="md:w-2/4">
|
||||||
|
<img src="/graphql.png">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="md:w-2/4">
|
||||||
|
<img src="/json.png">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-10 py-10 md:py-20">
|
||||||
|
<div class="container mx-auto px-10 md:px-0">
|
||||||
|
<h1 class="uppercase font-semibold text-xl text-blue-800 mb-4">
|
||||||
|
How to use {{ data.heroText }}?
|
||||||
|
</h1>
|
||||||
|
<div class="text-2xl md:text-3xl">
|
||||||
|
<small class="text-sm">Use the below command to download and install Super Graph. You will need Go 1.13 or above</small>
|
||||||
|
<pre>‣ GO111MODULE=on go get -u github.com/dosco/super-graph</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Create a new app and change to it's directory</small>
|
||||||
|
<pre>‣ super-graph new blog; cd blog</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Setup the app database and seed it with fake data. Docker compose will start a Postgres database for your app</small>
|
||||||
|
<pre>‣ docker-compose run blog_api ./super-graph db:setup</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">And finally launch Super Graph configured for your app</small>
|
||||||
|
<pre>‣ docker-compose up</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-100 mt-10">
|
||||||
|
<div class="container mx-auto px-10 md:px-0 py-32">
|
||||||
|
<h1 class="uppercase font-semibold text-xl text-blue-800 mb-4">
|
||||||
|
The story of {{ data.heroText }}
|
||||||
|
</h1>
|
||||||
|
<div class="text-2xl md:text-3xl">
|
||||||
|
After working on several products through my career I find that we spend way too much time on building API backends. Most APIs also require constant updating, this costs real time and money.<br><br>
|
||||||
|
|
||||||
|
It's always the same thing, figure out what the UI needs then build an endpoint for it. Most API code involves struggling with an ORM to query a database and mangle the data into a shape that the UI expects to see.<br><br>
|
||||||
|
|
||||||
|
I didn't want to write this code anymore, I wanted the computer to do it. Enter GraphQL, to me it sounded great, but it still required me to write all the same database query code.<br><br>
|
||||||
|
|
||||||
|
Having worked with compilers before I saw this as a compiler problem. Why not build a compiler that converts GraphQL to highly efficient SQL.<br><br>
|
||||||
|
|
||||||
|
This compiler is what sits at the heart of Super Graph with layers of useful functionality around it like authentication, remote joins, rails integration, database migrations and everything else needed for you to build production ready apps with it.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overflow-hidden bg-indigo-900" style="height: 730px">
|
||||||
|
<div class="container mx-auto py-20">
|
||||||
|
<img src="/super-graph-web-ui.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-10 md:py-20">
|
||||||
|
<div class="container mx-auto px-10 md:px-0">
|
||||||
|
<h1 class="uppercase font-semibold text-xl text-blue-800 mb-4">
|
||||||
|
Try it with a demo Rails app
|
||||||
|
</h1>
|
||||||
|
<div class="text-2xl md:text-3xl">
|
||||||
|
<small class="text-sm">Download the Docker compose config for the demo</small>
|
||||||
|
<pre>‣ curl -L -o demo.yml https://bit.ly/2mq05lW</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Setup the demo database</small>
|
||||||
|
<pre>‣ docker-compose -f demo.yml run rails_app rake db:create db:migrate db:seed</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Run the demo</small>
|
||||||
|
<pre>‣ docker-compose -f demo.yml up</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Signin to the demo app (user1@demo.com / 123456)</small>
|
||||||
|
<pre>‣ open http://localhost:3000</pre>
|
||||||
|
|
||||||
|
<small class="text-sm">Try the super graph web ui</small>
|
||||||
|
<pre>‣ open http://localhost:8080</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border-t py-10">
|
||||||
|
<div class="container mx-auto">
|
||||||
|
<style>.embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }</style>
|
||||||
|
<div class="embed-container shadow">
|
||||||
|
<iframe src='https://www.youtube.com/embed/MfPL2A-DAJk' frameborder='0' allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mx-auto text-center py-8"
|
class="mx-auto text-center py-8"
|
||||||
v-if="data.footer"
|
v-if="data.footer"
|
||||||
|
@ -3,12 +3,14 @@ module.exports = {
|
|||||||
description: 'Get an instant GraphQL API for your Rails apps.',
|
description: 'Get an instant GraphQL API for your Rails apps.',
|
||||||
|
|
||||||
themeConfig: {
|
themeConfig: {
|
||||||
logo: '/logo.svg',
|
logo: '/hologram.svg',
|
||||||
nav: [
|
nav: [
|
||||||
{ text: 'Docs', link: '/guide' },
|
{ text: 'Docs', link: '/guide' },
|
||||||
{ text: 'Deploy', link: '/deploy' },
|
{ text: 'Deploy', link: '/deploy' },
|
||||||
{ text: 'Github', link: 'https://github.com/dosco/super-graph' },
|
{ text: 'Github', link: 'https://github.com/dosco/super-graph' },
|
||||||
{ text: 'Docker', link: 'https://hub.docker.com/r/dosco/super-graph/builds' },
|
{ text: 'Docker', link: 'https://hub.docker.com/r/dosco/super-graph/builds' },
|
||||||
|
{ text: 'Join Chat', link: 'https://discord.gg/NKdXBc' },
|
||||||
|
|
||||||
],
|
],
|
||||||
serviceWorker: {
|
serviceWorker: {
|
||||||
updatePopup: true
|
updatePopup: true
|
||||||
|
BIN
docs/.vuepress/public/graphql.png
Normal file
BIN
docs/.vuepress/public/graphql.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.5 KiB |
BIN
docs/.vuepress/public/json.png
Normal file
BIN
docs/.vuepress/public/json.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 149 KiB |
@ -10,6 +10,14 @@
|
|||||||
p {
|
p {
|
||||||
@apply py-2 text-lg
|
@apply py-2 text-lg
|
||||||
}
|
}
|
||||||
|
pre {
|
||||||
|
white-space: pre-wrap; /* css-3 */
|
||||||
|
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
||||||
|
white-space: -pre-wrap; /* Opera 4-6 */
|
||||||
|
white-space: -o-pre-wrap; /* Opera 7 */
|
||||||
|
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
|
@ -20,57 +20,11 @@ features:
|
|||||||
- title: Ruby-on-Rails
|
- title: Ruby-on-Rails
|
||||||
details: Can read Rails cookies and supports rails database conventions.
|
details: Can read Rails cookies and supports rails database conventions.
|
||||||
- title: Serverless
|
- title: Serverless
|
||||||
details: Instant startup for scale to zero environments like Google Cloud Run, App Engine, AWS Lambda
|
details: Instant startup for scale to zero environments like Google Cloud Run, App Engine, AWS Lambda
|
||||||
- title: Go Lang
|
- title: Go Lang
|
||||||
details: Go is a language created at Google to build fast and secure web services.
|
details: Go is a language created at Google to build fast and secure web services.
|
||||||
- title: Free and Open Source
|
- title: Free and Open Source
|
||||||
details: Not a VC funded startup. Not even a startup just good old open source code
|
details: Not a VC funded startup. Not even a startup just good old open source code
|
||||||
|
|
||||||
footer: MIT Licensed | Copyright © 2018-present Vikram Rangnekar
|
footer: MIT Licensed | Copyright © 2018-present Vikram Rangnekar
|
||||||
---
|
---
|
||||||
|
|
||||||
## Try the demo
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# download super graph source
|
|
||||||
git clone https://github.com/dosco/super-graph.git
|
|
||||||
|
|
||||||
# setup the demo rails app & database and run it
|
|
||||||
./demo start
|
|
||||||
|
|
||||||
# signin to the demo app (user1@demo.com / 123456)
|
|
||||||
open http://localhost:3000
|
|
||||||
|
|
||||||
# try the super graph web ui
|
|
||||||
open http://localhost:8080
|
|
||||||
```
|
|
||||||
|
|
||||||
## Try a query
|
|
||||||
|
|
||||||
```graphql
|
|
||||||
query {
|
|
||||||
users {
|
|
||||||
id
|
|
||||||
email
|
|
||||||
picture : avatar
|
|
||||||
products(limit: 2, where: { price: { gt: 10 } }) {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Why Super Graph?
|
|
||||||
|
|
||||||
After working on several product though my career I found building CRUD APIs (Create, Update, Delete, List, Show) to be a big part of the job. It was always the same thing figure out what the UI needs then build an endpoint for it, if related data is needed than join with another table. I didn't want to write that code anymore I wanted the computer to just do it.
|
|
||||||
|
|
||||||
I always liked GraphQL it sounded friendly, but it still required me to write all the same database query code. Sure the API was nicer but it took a lot of work sometime even more than a simple REST API would have. I wanted a GraphQL server that just worked the second you deployed it without having to write a line of code.
|
|
||||||
|
|
||||||
And so after a lot of coffee and some Avocado toasts __Super Graph was born, a GraphQL server that just works, is high performance and easy to deploy__. I hope you find it as useful as I do and there's a lot more coming so hit that :star: to stay in the loop.
|
|
||||||
|
|
||||||
|
|
||||||
## Say hello
|
|
||||||
|
|
||||||
[twitter.com/dosco](https://twitter.com/dosco)
|
|
||||||
|
510
docs/guide.md
510
docs/guide.md
@ -4,30 +4,37 @@ sidebar: auto
|
|||||||
|
|
||||||
# Guide to Super Graph
|
# Guide to Super Graph
|
||||||
|
|
||||||
Without writing a line of code get an instant high-performance GraphQL API for your Ruby-on-Rails app. Super Graph will automatically understand your apps database and expose a secure, fast and complete GraphQL API for it. Built in support for Rails authentication and JWT tokens.
|
Get an instant high performance GraphQL API for Postgres. No code needed. GraphQL is automatically transformed into efficient database queries. Also Designed to integrate with your Rails apps.
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Automatically learns Postgres schemas and relationships
|
|
||||||
- Supports Belongs-To, One-To-Many and Many-To-Many table relationships
|
|
||||||
- Works with Rails database schemas
|
- Works with Rails database schemas
|
||||||
- Full text search and aggregations
|
- Automatically learns schemas and relationships
|
||||||
|
- Belongs-To, One-To-Many and Many-To-Many table relationships
|
||||||
|
- Full text search and Aggregations
|
||||||
- Rails Auth supported (Redis, Memcache, Cookie)
|
- Rails Auth supported (Redis, Memcache, Cookie)
|
||||||
- JWT tokens supported (Auth0, etc)
|
- JWT tokens supported (Auth0, etc)
|
||||||
- Join database queries with remote data sources (APIs like Stripe, Twitter, etc)
|
- Join with remote REST APIs
|
||||||
- Generates highly optimized and fast Postgres SQL queries
|
- Highly optimized and fast Postgres SQL queries
|
||||||
- Uses prepared statements for very fast Postgres queries
|
- Support GraphQL queries and mutations
|
||||||
- Configure with a simple config file
|
- Configure with a simple config file
|
||||||
- High performance GO codebase
|
- High performance GO codebase
|
||||||
- Tiny docker image and low memory requirements
|
- Tiny docker image and low memory requirements
|
||||||
|
- Database migrations tool
|
||||||
|
- Write database seeding scripts in Javascript
|
||||||
|
|
||||||
## Try it out
|
## Try the demo app
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# download super graph source
|
# download the Docker compose config for the demo
|
||||||
git clone https://github.com/dosco/super-graph.git
|
curl -L -o demo.yml https://bit.ly/2mq05lW
|
||||||
|
|
||||||
# setup the demo rails app & database and run it
|
# setup the demo rails app & database and run it
|
||||||
./demo start
|
docker-compose -f demo.yml run rails_app rake db:create db:migrate db:seed
|
||||||
|
|
||||||
|
# run the demo
|
||||||
|
docker-compose -f demo.yml up
|
||||||
|
|
||||||
# signin to the demo app (user1@demo.com / 123456)
|
# signin to the demo app (user1@demo.com / 123456)
|
||||||
open http://localhost:3000
|
open http://localhost:3000
|
||||||
@ -43,7 +50,7 @@ docker website [https://docs.docker.com/docker-for-mac/install/](https://docs.do
|
|||||||
|
|
||||||
#### Trying out GraphQL
|
#### Trying out GraphQL
|
||||||
|
|
||||||
We currently support the `query` action which is used for fetching data. Support for `mutation` and `subscriptions` is work in progress. For example the below GraphQL query would fetch two products that belong to the current user where the price is greater than 10
|
We currently fully support queries and mutations. Support for `subscriptions` is work in progress. For example the below GraphQL query would fetch two products that belong to the current user where the price is greater than 10.
|
||||||
|
|
||||||
#### GQL Query
|
#### GQL Query
|
||||||
|
|
||||||
@ -65,6 +72,27 @@ query {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
In another example the below GraphQL mutation would insert a product into the database. The first part of the below example is the variable data and the second half is the GraphQL mutation. For mutations data has to always ben passed as a variable.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"name": "Art of Computer Programming",
|
||||||
|
"description": "The Art of Computer Programming (TAOCP) is a comprehensive monograph written by computer scientist Donald Knuth",
|
||||||
|
"price": 30.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(insert: $data) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
The above GraphQL query returns the JSON result below. It handles all
|
The above GraphQL query returns the JSON result below. It handles all
|
||||||
kinds of complexity without you having to writing a line of code.
|
kinds of complexity without you having to writing a line of code.
|
||||||
|
|
||||||
@ -109,6 +137,325 @@ curl 'http://localhost:8080/api/v1/graphql' \
|
|||||||
-H 'content-type: application/json' \
|
-H 'content-type: application/json' \
|
||||||
-H 'X-User-ID: 5' \
|
-H 'X-User-ID: 5' \
|
||||||
--data-binary '{"query":"{ products { name price users { email }}}"}'
|
--data-binary '{"query":"{ products { name price users { email }}}"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get Started
|
||||||
|
|
||||||
|
Super Graph can generate your initial app for you. The generated app will have config files, database migrations and seed files among other things like docker related files.
|
||||||
|
|
||||||
|
You can then add your database schema to the migrations, maybe create some seed data using the seed script and launch Super Graph. You're now good to go and can start working on your UI frontend in React, Vue or whatever.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# use the below command to download and install Super Graph. You will need Go 1.13 or above
|
||||||
|
GO111MODULE=on go get -u github.com/dosco/super-graph
|
||||||
|
|
||||||
|
# create a new app and change to it's directory
|
||||||
|
super-graph new blog; cd blog
|
||||||
|
|
||||||
|
# setup the app database and seed it with fake data. Docker compose will start a Postgres database for your app
|
||||||
|
docker-compose run blog_api ./super-graph db:setup
|
||||||
|
|
||||||
|
# and finally launch Super Graph configured for your app
|
||||||
|
docker-compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
Lets take a look at the files generated by Super Graph when you create a new app
|
||||||
|
|
||||||
|
```bash
|
||||||
|
super-graph new blog
|
||||||
|
|
||||||
|
> created 'blog'
|
||||||
|
> created 'blog/Dockerfile'
|
||||||
|
> created 'blog/docker-compose.yml'
|
||||||
|
> created 'blog/config'
|
||||||
|
> created 'blog/config/dev.yml'
|
||||||
|
> created 'blog/config/prod.yml'
|
||||||
|
> created 'blog/config/seed.js'
|
||||||
|
> created 'blog/config/migrations'
|
||||||
|
> created 'blog/config/migrations/100_init.sql'
|
||||||
|
> app 'blog' initialized
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker files
|
||||||
|
|
||||||
|
Docker Compose is a great way to run multiple services while developing on your desktop or laptop. In our case we need Postgres and Super Graph to both be running and the `docker-compose.yml` is configured to do just that. The Super Graph service is named after your app postfixed with `_api`. The Dockerfile can be used build a containr of your app for production deployment.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose run blog_api ./super-graph help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Config files
|
||||||
|
|
||||||
|
All the config files needs to configure Super Graph for your app are contained in this folder for starters you have two `dev.yaml` and `prod.yaml`. When the `GO_ENV` environment variable is set to `development` then `dev.yaml` is used and the prod one when it's set to `production`. Stage and Test are the other two environment options, but you can set the `GO_ENV` to whatever you like (eg. `alpha-test`) and Super Graph will look for a yaml file with that name to load config from.
|
||||||
|
|
||||||
|
### Seed.js
|
||||||
|
|
||||||
|
Having data flowing through your API makes building your frontend UI so much easier. When creafting say a user profile wouldn't it be nice for the API to return a fake user with name, picture and all. This is why having the ability to seed your database is important. Seeding cn also be used in production to setup some initial users like the admins or to add an initial set of products to a ecommerce store.
|
||||||
|
|
||||||
|
Super Graph makes this easy by allowing you to write your seeding script in plan old Javascript. The below file that auto-generated for new apps uses our built-in functions `fake` and `graphql` to generate fake data and use GraphQL mutations to insert it into the database.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Example script to seed database
|
||||||
|
|
||||||
|
var users = [];
|
||||||
|
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
var data = {
|
||||||
|
full_name: fake.name(),
|
||||||
|
email: fake.email()
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = graphql(" \
|
||||||
|
mutation { \
|
||||||
|
user(insert: $data) { \
|
||||||
|
id \
|
||||||
|
} \
|
||||||
|
}", { data: data })
|
||||||
|
|
||||||
|
users.push(res.user)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can generate the following fake data for your seeding purposes. Below is the list of fake data functions supported by the built-in fake data library. For example `fake.image_url()` will generate a fake image url or `fake.shuffle_strings(['hello', 'world', 'cool'])` will generate a randomly shuffled version of that array of strings or `fake.rand_string(['hello', 'world', 'cool'])` will return a random string from the array provided.
|
||||||
|
|
||||||
|
```
|
||||||
|
// Person
|
||||||
|
person
|
||||||
|
name
|
||||||
|
name_prefix
|
||||||
|
name_suffix
|
||||||
|
first_name
|
||||||
|
last_name
|
||||||
|
gender
|
||||||
|
ssn
|
||||||
|
contact
|
||||||
|
email
|
||||||
|
phone
|
||||||
|
phone_formatted
|
||||||
|
username
|
||||||
|
password
|
||||||
|
|
||||||
|
// Address
|
||||||
|
address
|
||||||
|
city
|
||||||
|
country
|
||||||
|
country_abr
|
||||||
|
state
|
||||||
|
state_abr
|
||||||
|
status_code
|
||||||
|
street
|
||||||
|
street_name
|
||||||
|
street_number
|
||||||
|
street_prefix
|
||||||
|
street_suffix
|
||||||
|
zip
|
||||||
|
latitude
|
||||||
|
latitude_in_range
|
||||||
|
longitude
|
||||||
|
longitude_in_range
|
||||||
|
|
||||||
|
// Beer
|
||||||
|
beer_alcohol
|
||||||
|
beer_hop
|
||||||
|
beer_ibu
|
||||||
|
beer_blg
|
||||||
|
beer_malt
|
||||||
|
beer_name
|
||||||
|
beer_style
|
||||||
|
beer_yeast
|
||||||
|
|
||||||
|
// Cars
|
||||||
|
vehicle
|
||||||
|
vehicle_type
|
||||||
|
car_maker
|
||||||
|
car_model
|
||||||
|
fuel_type
|
||||||
|
transmission_gear_type
|
||||||
|
|
||||||
|
// Text
|
||||||
|
word
|
||||||
|
sentence
|
||||||
|
paragrph
|
||||||
|
question
|
||||||
|
quote
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
generate
|
||||||
|
boolean
|
||||||
|
uuid
|
||||||
|
|
||||||
|
// Colors
|
||||||
|
color
|
||||||
|
hex_color
|
||||||
|
rgb_color
|
||||||
|
safe_color
|
||||||
|
|
||||||
|
// Internet
|
||||||
|
url
|
||||||
|
image_url
|
||||||
|
domain_name
|
||||||
|
domain_suffix
|
||||||
|
ipv4_address
|
||||||
|
ipv6_address
|
||||||
|
simple_status_code
|
||||||
|
http_method
|
||||||
|
user_agent
|
||||||
|
user_agent_firefox
|
||||||
|
user_agent_chrome
|
||||||
|
user_agent_opera
|
||||||
|
user_agent_safari
|
||||||
|
|
||||||
|
// Date / Time
|
||||||
|
date
|
||||||
|
date_range
|
||||||
|
nano_second
|
||||||
|
second
|
||||||
|
minute
|
||||||
|
hour
|
||||||
|
month
|
||||||
|
day
|
||||||
|
weekday
|
||||||
|
year
|
||||||
|
timezone
|
||||||
|
timezone_abv
|
||||||
|
timezone_full
|
||||||
|
timezone_offset
|
||||||
|
|
||||||
|
// Payment
|
||||||
|
price
|
||||||
|
credit_card
|
||||||
|
credit_card_cvv
|
||||||
|
credit_card_number
|
||||||
|
credit_card_number_luhn
|
||||||
|
credit_card_type
|
||||||
|
currency
|
||||||
|
currency_long
|
||||||
|
currency_short
|
||||||
|
|
||||||
|
// Company
|
||||||
|
bs
|
||||||
|
buzzword
|
||||||
|
company
|
||||||
|
company_suffix
|
||||||
|
job
|
||||||
|
job_description
|
||||||
|
job_level
|
||||||
|
job_title
|
||||||
|
|
||||||
|
// Hacker
|
||||||
|
hacker_abbreviation
|
||||||
|
hacker_adjective
|
||||||
|
hacker_ingverb
|
||||||
|
hacker_noun
|
||||||
|
hacker_phrase
|
||||||
|
hacker_verb
|
||||||
|
|
||||||
|
//Hipster
|
||||||
|
hipster_word
|
||||||
|
hipster_paragraph
|
||||||
|
hipster_sentence
|
||||||
|
|
||||||
|
// File
|
||||||
|
extension
|
||||||
|
mine_type
|
||||||
|
|
||||||
|
// Numbers
|
||||||
|
number
|
||||||
|
numerify
|
||||||
|
int8
|
||||||
|
int16
|
||||||
|
int32
|
||||||
|
int64
|
||||||
|
uint8
|
||||||
|
uint16
|
||||||
|
uint32
|
||||||
|
uint64
|
||||||
|
float32
|
||||||
|
float32_range
|
||||||
|
float64
|
||||||
|
float64_range
|
||||||
|
shuffle_ints
|
||||||
|
mac_address
|
||||||
|
|
||||||
|
//String
|
||||||
|
digit
|
||||||
|
letter
|
||||||
|
lexify
|
||||||
|
rand_string
|
||||||
|
shuffle_strings
|
||||||
|
numerify
|
||||||
|
```
|
||||||
|
|
||||||
|
### Migrations
|
||||||
|
|
||||||
|
Easy database migrations is the most important thing when building products backend by a relational database. We make it super easy to manage and migrate your database.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
super-graph db:new create_users
|
||||||
|
> created migration 'config/migrations/101_create_users.sql'
|
||||||
|
```
|
||||||
|
|
||||||
|
Migrations in Super Graph are plain old Postgres SQL. Here's an example for the above migration.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- Write your migrate up statements here
|
||||||
|
|
||||||
|
CREATE TABLE public.users (
|
||||||
|
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||||
|
full_name text,
|
||||||
|
email text UNIQUE NOT NULL CHECK (length(email) < 255),
|
||||||
|
created_at timestamptz NOT NULL NOT NULL DEFAULT NOW(),
|
||||||
|
updated_at timestamptz NOT NULL NOT NULL DEFAULT NOW()
|
||||||
|
);
|
||||||
|
|
||||||
|
---- create above / drop below ----
|
||||||
|
|
||||||
|
-- Write your down migrate statements here. If this migration is irreversible
|
||||||
|
-- then delete the separator line above.
|
||||||
|
|
||||||
|
DROP TABLE public.users
|
||||||
|
```
|
||||||
|
|
||||||
|
We would encourage you to leverage triggers to maintain consistancy of your data for example here are a couple triggers that you can add to you init migration and across your tables.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- This trigger script will set the updated_at column everytime a row is updated
|
||||||
|
CREATE OR REPLACE FUNCTION trigger_set_updated_at()
|
||||||
|
RETURNS TRIGGER SET SCHEMA 'public' LANGUAGE 'plpgsql' AS $$
|
||||||
|
BEGIN
|
||||||
|
new.updated_at = now();
|
||||||
|
RETURN new;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
-- An exmple of adding this trigger to the users table
|
||||||
|
CREATE TRIGGER set_updated_at BEFORE UPDATE ON public.users
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE trigger_set_updated_at();
|
||||||
|
```
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- This trigger script will set the user_id column to the current
|
||||||
|
-- Super Graph user.id value everytime a row is created or updated
|
||||||
|
CREATE OR REPLACE FUNCTION trigger_set_user_id()
|
||||||
|
RETURNS TRIGGER SET SCHEMA 'public' LANGUAGE 'plpgsql' AS $$
|
||||||
|
BEGIN
|
||||||
|
IF TG_OP = 'UPDATE' THEN
|
||||||
|
new.user_id = old.user_id;
|
||||||
|
ELSE
|
||||||
|
new.user_id = current_setting('user.id')::int;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN new;
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
-- An exmple of adding this trigger to the blog_posts table
|
||||||
|
CREATE TRIGGER set_user_id BEFORE INSERT OR UPDATE ON public.blog_posts
|
||||||
|
FOR EACH ROW EXECUTE PROCEDURE trigger_set_user_id();
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -150,7 +497,7 @@ query {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Complex queries (Where)
|
### Advanced queries
|
||||||
|
|
||||||
Super Graph support complex queries where you can add filters, ordering,offsets and limits on the query.
|
Super Graph support complex queries where you can add filters, ordering,offsets and limits on the query.
|
||||||
|
|
||||||
@ -187,7 +534,7 @@ contains | column: { contains: [1, 2, 4] } | Is this array/json column a subset
|
|||||||
contained_in | column: { contains: "{'a':1, 'b':2}" } | Is this array/json column a subset of these value
|
contained_in | column: { contains: "{'a':1, 'b':2}" } | Is this array/json column a subset of these value
|
||||||
is_null | column: { is_null: true } | Is column value null or not
|
is_null | column: { is_null: true } | Is column value null or not
|
||||||
|
|
||||||
### Aggregation (Max, Count, etc)
|
### Aggregations
|
||||||
|
|
||||||
You will often find the need to fetch aggregated values from the database such as `count`, `max`, `min`, etc. This is simple to do with GraphQL, just prefix the aggregation name to the field name that you want to aggregrate like `count_id`. The below query will group products by name and find the minimum price for each group. Notice the `min_price` field we're adding `min_` to price.
|
You will often find the need to fetch aggregated values from the database such as `count`, `max`, `min`, etc. This is simple to do with GraphQL, just prefix the aggregation name to the field name that you want to aggregrate like `count_id`. The below query will group products by name and find the minimum price for each group. Notice the `min_price` field we're adding `min_` to price.
|
||||||
|
|
||||||
@ -239,6 +586,141 @@ query {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Mutations
|
||||||
|
|
||||||
|
In GraphQL mutations is the operation type for when you need to modify data. Super Graph supports the `insert`, `update` and `delete` database operations. Here are some examples.
|
||||||
|
|
||||||
|
When using mutations the data must be passed as variables since Super Graphs compiles the query into an prepared statement in the database for maximum speed. Prepared statements are are functions in your code when called they accept arguments and your variables are passed in as those arguments.
|
||||||
|
|
||||||
|
### Insert
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"name": "Art of Computer Programming",
|
||||||
|
"description": "The Art of Computer Programming (TAOCP) is a comprehensive monograph written by computer scientist Donald Knuth",
|
||||||
|
"price": 30.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(insert: $data) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bulk insert
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": [{
|
||||||
|
"name": "Art of Computer Programming",
|
||||||
|
"description": "The Art of Computer Programming (TAOCP) is a comprehensive monograph written by computer scientist Donald Knuth",
|
||||||
|
"price": 30.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Compilers: Principles, Techniques, and Tools",
|
||||||
|
"description": "Known to professors, students, and developers worldwide as the 'Dragon Book' is available in a new edition",
|
||||||
|
"price": 93.74
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(insert: $data) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"price": 200.0
|
||||||
|
},
|
||||||
|
"product_id": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(update: $data, id: $product_id) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bulk update
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"price": 500.0
|
||||||
|
},
|
||||||
|
"gt_product_id": 450.0,
|
||||||
|
"lt_product_id:": 550.0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(update: $data, where: {
|
||||||
|
price: { gt: $gt_product_id, lt: lt_product_id }
|
||||||
|
}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"price": 500.0
|
||||||
|
},
|
||||||
|
"product_id": 5
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(delete: true, id: $product_id) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bulk delete
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"price": 500.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
mutation {
|
||||||
|
product(delete: true, where: { price: { eq: { 500.0 } } }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Using variables
|
### Using variables
|
||||||
|
|
||||||
Variables (`$product_id`) and their values (`"product_id": 5`) can be passed along side the GraphQL query. Using variables makes for better client side code as well as improved server side SQL query caching. The build-in web-ui also supports setting variables. Not having to manipulate your GraphQL query string to insert values into it makes for cleaner
|
Variables (`$product_id`) and their values (`"product_id": 5`) can be passed along side the GraphQL query. Using variables makes for better client side code as well as improved server side SQL query caching. The build-in web-ui also supports setting variables. Not having to manipulate your GraphQL query string to insert values into it makes for cleaner
|
||||||
|
21
go.mod
21
go.mod
@ -2,33 +2,40 @@ module github.com/dosco/super-graph
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/GeertJohan/go.rice v1.0.0
|
github.com/GeertJohan/go.rice v1.0.0
|
||||||
github.com/Masterminds/semver v1.4.2
|
github.com/Masterminds/semver v1.5.0
|
||||||
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
github.com/OneOfOne/xxhash v1.2.5 // indirect
|
||||||
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3
|
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
|
||||||
github.com/brianvoe/gofakeit v3.18.0+incompatible
|
github.com/brianvoe/gofakeit v3.18.0+incompatible
|
||||||
github.com/cespare/xxhash/v2 v2.0.0
|
github.com/cespare/xxhash/v2 v2.1.0
|
||||||
|
github.com/daaku/go.zipexe v1.0.1 // indirect
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/dlclark/regexp2 v1.2.0 // indirect
|
github.com/dlclark/regexp2 v1.2.0 // indirect
|
||||||
github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733
|
github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733
|
||||||
github.com/fsnotify/fsnotify v1.4.7
|
github.com/fsnotify/fsnotify v1.4.7
|
||||||
github.com/garyburd/redigo v1.6.0
|
github.com/garyburd/redigo v1.6.0
|
||||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
|
github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect
|
||||||
github.com/gobuffalo/flect v0.1.1
|
github.com/gobuffalo/flect v0.1.6
|
||||||
github.com/gorilla/websocket v1.4.0
|
github.com/gorilla/websocket v1.4.1
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect
|
||||||
github.com/jackc/pgconn v1.0.1
|
github.com/jackc/pgconn v1.0.1
|
||||||
github.com/jackc/pgtype v1.0.1
|
github.com/jackc/pgtype v1.0.1
|
||||||
github.com/jackc/pgx v3.6.0+incompatible
|
github.com/jackc/pgx v3.6.0+incompatible
|
||||||
github.com/jackc/pgx/v4 v4.0.1
|
github.com/jackc/pgx/v4 v4.0.1
|
||||||
github.com/jackc/tern v1.8.2
|
github.com/jackc/tern v1.8.2
|
||||||
|
github.com/magiconair/properties v1.8.1 // indirect
|
||||||
|
github.com/pelletier/go-toml v1.4.0 // indirect
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/rs/zerolog v1.15.0
|
github.com/rs/zerolog v1.15.0
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
|
github.com/spf13/afero v1.2.2 // indirect
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
github.com/spf13/viper v1.3.2
|
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/spf13/viper v1.4.0
|
||||||
github.com/valyala/fasttemplate v1.0.1
|
github.com/valyala/fasttemplate v1.0.1
|
||||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7
|
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad
|
||||||
|
golang.org/x/sys v0.0.0-20190927073244-c990c680b611 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
||||||
)
|
)
|
||||||
|
|
||||||
|
107
go.sum
107
go.sum
@ -1,3 +1,4 @@
|
|||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||||
@ -5,35 +6,53 @@ github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voi
|
|||||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||||
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
|
||||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI=
|
github.com/OneOfOne/xxhash v1.2.5 h1:zl/OfRA6nftbBK9qTohYBJ5xvw6C/oNKizR7cZGl3cI=
|
||||||
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
|
||||||
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3 h1:+qz9Ga6l6lKw6fgvk5RMV5HQznSLvI8Zxajwdj4FhFg=
|
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3 h1:+qz9Ga6l6lKw6fgvk5RMV5HQznSLvI8Zxajwdj4FhFg=
|
||||||
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3/go.mod h1:FlkD11RtgMTYjVuBnb7cxoHmQGqvPpCsr2atC88nl/M=
|
github.com/adjust/gorails v0.0.0-20171013043634-2786ed0c03d3/go.mod h1:FlkD11RtgMTYjVuBnb7cxoHmQGqvPpCsr2atC88nl/M=
|
||||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
|
||||||
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
||||||
|
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=
|
github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=
|
||||||
github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=
|
github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.0.0 h1:Eb1IiuHmi3FhT12NKfqCQXSXRqc4NTMvgJoREemrSt4=
|
github.com/cespare/xxhash/v2 v2.0.0 h1:Eb1IiuHmi3FhT12NKfqCQXSXRqc4NTMvgJoREemrSt4=
|
||||||
github.com/cespare/xxhash/v2 v2.0.0/go.mod h1:MaMeaVDXZNmTpkOyhVs3/WfjgobkbQgfrVnrr3DyZL0=
|
github.com/cespare/xxhash/v2 v2.0.0/go.mod h1:MaMeaVDXZNmTpkOyhVs3/WfjgobkbQgfrVnrr3DyZL0=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||||
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||||
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
|
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
|
||||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||||
|
github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M=
|
||||||
|
github.com/daaku/go.zipexe v1.0.1/go.mod h1:5xWogtqlYnfBXkSB1o9xysukNP9GTvaNkqzUZbt3Bw8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
|
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||||
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
|
||||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733 h1:cyNc40Dx5YNEO94idePU8rhVd3dn+sd04Arh0kDBAaw=
|
github.com/dop251/goja v0.0.0-20190912223329-aa89e6a4c733 h1:cyNc40Dx5YNEO94idePU8rhVd3dn+sd04Arh0kDBAaw=
|
||||||
@ -42,15 +61,35 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc=
|
||||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||||
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
|
github.com/go-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
|
||||||
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/gobuffalo/flect v0.1.1 h1:GTZJjJufv9FxgRs1+0Soo3wj+Md3kTUmTER/YE4uINA=
|
github.com/gobuffalo/flect v0.1.1 h1:GTZJjJufv9FxgRs1+0Soo3wj+Md3kTUmTER/YE4uINA=
|
||||||
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
|
||||||
|
github.com/gobuffalo/flect v0.1.6 h1:D7KWNRFiCknJKA495/e1BO7oxqf8tbieaLv/ehoZ/+g=
|
||||||
|
github.com/gobuffalo/flect v0.1.6/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||||
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||||
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
@ -100,8 +139,13 @@ github.com/jackc/puddle v1.0.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv
|
|||||||
github.com/jackc/tern v1.8.2 h1:+d9eK83fRS0dbf6nt+2tjILYF4FKG1O5xTFB8Lzc66U=
|
github.com/jackc/tern v1.8.2 h1:+d9eK83fRS0dbf6nt+2tjILYF4FKG1O5xTFB8Lzc66U=
|
||||||
github.com/jackc/tern v1.8.2/go.mod h1:AMppp2oyCT6rYnJHLLMmPWwahfFvdIVi6mr9gH81Nxs=
|
github.com/jackc/tern v1.8.2/go.mod h1:AMppp2oyCT6rYnJHLLMmPWwahfFvdIVi6mr9gH81Nxs=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
@ -114,23 +158,41 @@ github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
|||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||||
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
|
||||||
|
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
|
||||||
github.com/pkg/errors v0.0.0-20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.0.0-20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||||
github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
|
github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY=
|
||||||
@ -139,13 +201,17 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR
|
|||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
|
||||||
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
|
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v0.0.0-20160114030619-9c9300901990/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.0-20160114030619-9c9300901990/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
@ -153,11 +219,17 @@ github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
|||||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||||
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v0.0.0-20151218134703-7f60f83a2c81/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20151218134703-7f60f83a2c81/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
|
||||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
|
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||||
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
@ -166,6 +238,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
@ -173,14 +247,17 @@ github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8W
|
|||||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7tbLt/I/gQuP559o/0FrAkHKlQM/Ks=
|
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec h1:DGmKwyZwEB8dI7tbLt/I/gQuP559o/0FrAkHKlQM/Ks=
|
||||||
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
|
github.com/vaughan0/go-ini v0.0.0-20130923145212-a98ad7ee00ec/go.mod h1:owBmyHYMLkxyrugmfwE/DLJyW8Ro9mkphwuVErQ0iUw=
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||||
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
golang.org/x/crypto v0.0.0-20151201002508-7b85b097bf75/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20151201002508-7b85b097bf75/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
@ -189,15 +266,30 @@ golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaE
|
|||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
||||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad h1:5E5raQxcv+6CZ11RrBYQe5WRbUIWpScjh0kvHZkZIrQ=
|
||||||
|
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a h1:1n5lsVfiQW3yfsRGu98756EH1YthsFqr/5mxHduZW2A=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -209,21 +301,36 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
||||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190927073244-c990c680b611 h1:q9u40nxWT5zRClI/uU9dHCiYGottAg6Nzz4YUQyHxdA=
|
||||||
|
golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package migrate_test
|
package migrate_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/jackc/pgx"
|
|
||||||
"github.com/jackc/tern/migrate"
|
|
||||||
. "gopkg.in/check.v1"
|
. "gopkg.in/check.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
type MigrateSuite struct {
|
type MigrateSuite struct {
|
||||||
conn *pgx.Conn
|
conn *pgx.Conn
|
||||||
}
|
}
|
||||||
@ -352,3 +349,4 @@ func Example_OnStartMigrationProgressLogging() {
|
|||||||
// Output:
|
// Output:
|
||||||
// Migrating up: create a table
|
// Migrating up: create a table
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/dosco/super-graph/qcode"
|
"github.com/dosco/super-graph/qcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var zeroPaging = qcode.Paging{}
|
||||||
|
|
||||||
func (co *Compiler) compileMutation(qc *qcode.QCode, w *bytes.Buffer, vars Variables) (uint32, error) {
|
func (co *Compiler) compileMutation(qc *qcode.QCode, w *bytes.Buffer, vars Variables) (uint32, error) {
|
||||||
if len(qc.Selects) == 0 {
|
if len(qc.Selects) == 0 {
|
||||||
return 0, errors.New("empty query")
|
return 0, errors.New("empty query")
|
||||||
@ -38,6 +40,12 @@ func (co *Compiler) compileMutation(qc *qcode.QCode, w *bytes.Buffer, vars Varia
|
|||||||
return 0, errors.New("valid mutations are 'insert' and 'update'")
|
return 0, errors.New("valid mutations are 'insert' and 'update'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root.Paging = zeroPaging
|
||||||
|
root.DistinctOn = root.DistinctOn[:]
|
||||||
|
root.OrderBy = root.OrderBy[:]
|
||||||
|
root.Where = nil
|
||||||
|
root.Args = nil
|
||||||
|
|
||||||
return c.compileQuery(qc, w)
|
return c.compileQuery(qc, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +174,10 @@ func (c *compilerContext) renderDelete(qc *qcode.QCode, w *bytes.Buffer, vars Va
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.w.WriteString(`DELETE FROM `)
|
c.w.WriteString(`WITH `)
|
||||||
|
quoted(c.w, ti.Name)
|
||||||
|
|
||||||
|
c.w.WriteString(` AS (DELETE FROM `)
|
||||||
c.w.WriteString(ti.Name)
|
c.w.WriteString(ti.Name)
|
||||||
io.WriteString(c.w, ` WHERE `)
|
io.WriteString(c.w, ` WHERE `)
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package psql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ func simpleInsert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `WITH "users" AS (WITH "input" AS (SELECT {{data}}::json AS j) INSERT INTO users (full_name, email) SELECT full_name, email FROM input i, json_populate_record(NULL::users, i.j) t RETURNING *) SELECT json_object_agg('user', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "user_0"."id" AS "id") AS "sel_0")) AS "sel_json_0" FROM (SELECT "user"."id" FROM "users" AS "user" WHERE ((("user"."id") = {{user_id}})) LIMIT ('1') :: integer) AS "user_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `WITH "users" AS (WITH "input" AS (SELECT {{data}}::json AS j) INSERT INTO users (full_name, email) SELECT full_name, email FROM input i, json_populate_record(NULL::users, i.j) t RETURNING *) SELECT json_object_agg('user', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "users_0"."id" AS "id") AS "sel_0")) AS "sel_json_0" FROM (SELECT "users"."id" FROM "users") AS "users_0") AS "done_1337";`
|
||||||
|
|
||||||
vars := map[string]json.RawMessage{
|
vars := map[string]json.RawMessage{
|
||||||
"data": json.RawMessage(`{"email": "reannagreenholt@orn.com", "full_name": "Flo Barton"}`),
|
"data": json.RawMessage(`{"email": "reannagreenholt@orn.com", "full_name": "Flo Barton"}`),
|
||||||
@ -24,8 +23,6 @@ func simpleInsert(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(">", string(resSQL))
|
|
||||||
|
|
||||||
if string(resSQL) != sql {
|
if string(resSQL) != sql {
|
||||||
t.Fatal(errNotExpected)
|
t.Fatal(errNotExpected)
|
||||||
}
|
}
|
||||||
@ -39,7 +36,7 @@ func singleInsert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `WITH product AS (WITH input AS (SELECT {{insert}}::json AS j) INSERT INTO product (name, description) SELECT name, description FROM input i, json_populate_record(NULL::product, i.j) t RETURNING *) SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("id") = 15)) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `WITH "products" AS (WITH "input" AS (SELECT {{insert}}::json AS j) INSERT INTO products (name, description) SELECT name, description FROM input i, json_populate_record(NULL::products, i.j) t RETURNING *) SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products") AS "products_0") AS "done_1337";`
|
||||||
|
|
||||||
vars := map[string]json.RawMessage{
|
vars := map[string]json.RawMessage{
|
||||||
"insert": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
"insert": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
||||||
@ -63,7 +60,7 @@ func bulkInsert(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `WITH product AS (WITH input AS (SELECT {{insert}}::json AS j) INSERT INTO product (name, description) SELECT name, description FROM input i, json_populate_recordset(NULL::product, i.j) t RETURNING *) SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("id") = 15)) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `WITH "products" AS (WITH "input" AS (SELECT {{insert}}::json AS j) INSERT INTO products (name, description) SELECT name, description FROM input i, json_populate_recordset(NULL::products, i.j) t RETURNING *) SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products") AS "products_0") AS "done_1337";`
|
||||||
|
|
||||||
vars := map[string]json.RawMessage{
|
vars := map[string]json.RawMessage{
|
||||||
"insert": json.RawMessage(` [{ "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }]`),
|
"insert": json.RawMessage(` [{ "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }]`),
|
||||||
@ -87,7 +84,7 @@ func singleUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `WITH product AS (WITH input AS (SELECT {{update}}::json AS j) UPDATE product SET (name, description) = (SELECT name, description FROM input i, json_populate_record(NULL::product, i.j) t) WHERE (("product"."price") > 0) AND (("product"."price") < 8) AND (("product"."id") = 1) AND (("id") = 15) RETURNING *) SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("product"."id") = 1) AND (("id") = 15)) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `WITH "products" AS (WITH "input" AS (SELECT {{update}}::json AS j) UPDATE products SET (name, description) = (SELECT name, description FROM input i, json_populate_record(NULL::products, i.j) t) WHERE (("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") = 1) AND (("products"."id") = 15) RETURNING *) SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products") AS "products_0") AS "done_1337";`
|
||||||
|
|
||||||
vars := map[string]json.RawMessage{
|
vars := map[string]json.RawMessage{
|
||||||
"update": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
"update": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
||||||
@ -111,7 +108,7 @@ func delete(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `DELETE FROM product WHERE (("product"."price") > 0) AND (("product"."price") < 8) AND (("product"."id") = 1) RETURNING *) SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("product"."id") = 1)) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `WITH "products" AS (DELETE FROM products WHERE (("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") = 1) RETURNING *) SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products") AS "products_0") AS "done_1337";`
|
||||||
|
|
||||||
vars := map[string]json.RawMessage{
|
vars := map[string]json.RawMessage{
|
||||||
"update": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
"update": json.RawMessage(` { "name": "my_name", "woo": { "hoo": "goo" }, "description": "my_desc" }`),
|
||||||
@ -133,5 +130,4 @@ func TestCompileInsert(t *testing.T) {
|
|||||||
t.Run("bulkInsert", bulkInsert)
|
t.Run("bulkInsert", bulkInsert)
|
||||||
t.Run("singleUpdate", singleUpdate)
|
t.Run("singleUpdate", singleUpdate)
|
||||||
t.Run("delete", delete)
|
t.Run("delete", delete)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
326
psql/select.go
326
psql/select.go
@ -192,15 +192,15 @@ func (c *compilerContext) processChildren(sel *qcode.Select, ti *DBTableInfo) (u
|
|||||||
fallthrough
|
fallthrough
|
||||||
case RelBelongTo:
|
case RelBelongTo:
|
||||||
if _, ok := colmap[rel.Col2]; !ok {
|
if _, ok := colmap[rel.Col2]; !ok {
|
||||||
cols = append(cols, &qcode.Column{sel.Table, rel.Col2, rel.Col2})
|
cols = append(cols, &qcode.Column{ti.Name, rel.Col2, rel.Col2})
|
||||||
}
|
}
|
||||||
case RelOneToManyThrough:
|
case RelOneToManyThrough:
|
||||||
if _, ok := colmap[rel.Col1]; !ok {
|
if _, ok := colmap[rel.Col1]; !ok {
|
||||||
cols = append(cols, &qcode.Column{sel.Table, rel.Col1, rel.Col1})
|
cols = append(cols, &qcode.Column{ti.Name, rel.Col1, rel.Col1})
|
||||||
}
|
}
|
||||||
case RelRemote:
|
case RelRemote:
|
||||||
if _, ok := colmap[rel.Col1]; !ok {
|
if _, ok := colmap[rel.Col1]; !ok {
|
||||||
cols = append(cols, &qcode.Column{sel.Table, rel.Col1, rel.Col2})
|
cols = append(cols, &qcode.Column{ti.Name, rel.Col1, rel.Col2})
|
||||||
}
|
}
|
||||||
skipped |= (1 << uint(id))
|
skipped |= (1 << uint(id))
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo) (uint
|
|||||||
c.w.WriteString(`"`)
|
c.w.WriteString(`"`)
|
||||||
|
|
||||||
if hasOrder {
|
if hasOrder {
|
||||||
err := c.renderOrderBy(sel)
|
err := c.renderOrderBy(sel, ti)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return skipped, err
|
return skipped, err
|
||||||
}
|
}
|
||||||
@ -241,7 +241,7 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo) (uint
|
|||||||
c.w.WriteString(`SELECT `)
|
c.w.WriteString(`SELECT `)
|
||||||
|
|
||||||
if len(sel.DistinctOn) != 0 {
|
if len(sel.DistinctOn) != 0 {
|
||||||
c.renderDistinctOn(sel)
|
c.renderDistinctOn(sel, ti)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.w.WriteString(`row_to_json((`)
|
c.w.WriteString(`row_to_json((`)
|
||||||
@ -252,11 +252,11 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo) (uint
|
|||||||
c.w.WriteString(`" FROM (SELECT `)
|
c.w.WriteString(`" FROM (SELECT `)
|
||||||
|
|
||||||
// Combined column names
|
// Combined column names
|
||||||
c.renderColumns(sel)
|
c.renderColumns(sel, ti)
|
||||||
|
|
||||||
c.renderRemoteRelColumns(sel)
|
c.renderRemoteRelColumns(sel, ti)
|
||||||
|
|
||||||
err := c.renderJoinedColumns(sel, skipped)
|
err := c.renderJoinedColumns(sel, ti, skipped)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return skipped, err
|
return skipped, err
|
||||||
}
|
}
|
||||||
@ -271,7 +271,7 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo) (uint
|
|||||||
// END-ROW-TO-JSON
|
// END-ROW-TO-JSON
|
||||||
|
|
||||||
if hasOrder {
|
if hasOrder {
|
||||||
c.renderOrderByColumns(sel)
|
c.renderOrderByColumns(sel, ti)
|
||||||
}
|
}
|
||||||
// END-SELECT
|
// END-SELECT
|
||||||
|
|
||||||
@ -289,23 +289,25 @@ func (c *compilerContext) renderSelectClose(sel *qcode.Select, ti *DBTableInfo)
|
|||||||
hasOrder := len(sel.OrderBy) != 0
|
hasOrder := len(sel.OrderBy) != 0
|
||||||
|
|
||||||
if hasOrder {
|
if hasOrder {
|
||||||
err := c.renderOrderBy(sel)
|
err := c.renderOrderBy(sel, ti)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sel.Paging.Limit) != 0 {
|
if sel.Action == 0 {
|
||||||
//fmt.Fprintf(w, ` LIMIT ('%s') :: integer`, c.sel.Paging.Limit)
|
if len(sel.Paging.Limit) != 0 {
|
||||||
c.w.WriteString(` LIMIT ('`)
|
//fmt.Fprintf(w, ` LIMIT ('%s') :: integer`, c.sel.Paging.Limit)
|
||||||
c.w.WriteString(sel.Paging.Limit)
|
c.w.WriteString(` LIMIT ('`)
|
||||||
c.w.WriteString(`') :: integer`)
|
c.w.WriteString(sel.Paging.Limit)
|
||||||
|
c.w.WriteString(`') :: integer`)
|
||||||
|
|
||||||
} else if ti.Singular {
|
} else if ti.Singular {
|
||||||
c.w.WriteString(` LIMIT ('1') :: integer`)
|
c.w.WriteString(` LIMIT ('1') :: integer`)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c.w.WriteString(` LIMIT ('20') :: integer`)
|
c.w.WriteString(` LIMIT ('20') :: integer`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sel.Paging.Offset) != 0 {
|
if len(sel.Paging.Offset) != 0 {
|
||||||
@ -367,18 +369,18 @@ func (c *compilerContext) renderJoinTable(sel *qcode.Select) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderColumns(sel *qcode.Select) {
|
func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo) {
|
||||||
for i, col := range sel.Cols {
|
for i, col := range sel.Cols {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
io.WriteString(c.w, ", ")
|
io.WriteString(c.w, ", ")
|
||||||
}
|
}
|
||||||
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s"`,
|
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s"`,
|
||||||
//c.sel.Table, c.sel.ID, col.Name, col.FieldName)
|
//c.sel.Table, c.sel.ID, col.Name, col.FieldName)
|
||||||
colWithTableIDAlias(c.w, sel.Table, sel.ID, col.Name, col.FieldName)
|
colWithTableIDAlias(c.w, ti.Name, sel.ID, col.Name, col.FieldName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select) {
|
func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select, ti *DBTableInfo) {
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
for _, id := range sel.Children {
|
for _, id := range sel.Children {
|
||||||
@ -393,13 +395,13 @@ func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select) {
|
|||||||
}
|
}
|
||||||
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s"`,
|
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s"`,
|
||||||
//c.sel.Table, c.sel.ID, rel.Col1, rel.Col2)
|
//c.sel.Table, c.sel.ID, rel.Col1, rel.Col2)
|
||||||
colWithTableID(c.w, sel.Table, sel.ID, rel.Col1)
|
colWithTableID(c.w, ti.Name, sel.ID, rel.Col1)
|
||||||
alias(c.w, rel.Col2)
|
alias(c.w, rel.Col2)
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderJoinedColumns(sel *qcode.Select, skipped uint32) error {
|
func (c *compilerContext) renderJoinedColumns(sel *qcode.Select, ti *DBTableInfo, skipped uint32) error {
|
||||||
colsRendered := len(sel.Cols) != 0
|
colsRendered := len(sel.Cols) != 0
|
||||||
|
|
||||||
for _, id := range sel.Children {
|
for _, id := range sel.Children {
|
||||||
@ -411,11 +413,12 @@ func (c *compilerContext) renderJoinedColumns(sel *qcode.Select, skipped uint32)
|
|||||||
if skipThis {
|
if skipThis {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sel := &c.s[id]
|
childSel := &c.s[id]
|
||||||
|
|
||||||
//fmt.Fprintf(w, `"%s_%d_join"."%s" AS "%s"`,
|
//fmt.Fprintf(w, `"%s_%d_join"."%s" AS "%s"`,
|
||||||
//s.Table, s.ID, s.Table, s.FieldName)
|
//s.Table, s.ID, s.Table, s.FieldName)
|
||||||
colWithTableIDSuffixAlias(c.w, sel.Table, sel.ID, "_join", sel.Table, sel.FieldName)
|
colWithTableIDSuffixAlias(c.w, childSel.Table, childSel.ID,
|
||||||
|
"_join", childSel.Table, childSel.FieldName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -447,7 +450,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
//fmt.Fprintf(w, `ts_rank("%s"."%s", to_tsquery('%s')) AS %s`,
|
//fmt.Fprintf(w, `ts_rank("%s"."%s", to_tsquery('%s')) AS %s`,
|
||||||
//c.sel.Table, cn, arg.Val, col.Name)
|
//c.sel.Table, cn, arg.Val, col.Name)
|
||||||
c.w.WriteString(`ts_rank(`)
|
c.w.WriteString(`ts_rank(`)
|
||||||
colWithTable(c.w, sel.Table, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
c.w.WriteString(`, to_tsquery('`)
|
c.w.WriteString(`, to_tsquery('`)
|
||||||
c.w.WriteString(arg.Val)
|
c.w.WriteString(arg.Val)
|
||||||
c.w.WriteString(`')`)
|
c.w.WriteString(`')`)
|
||||||
@ -460,7 +463,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
//fmt.Fprintf(w, `ts_headline("%s"."%s", to_tsquery('%s')) AS %s`,
|
//fmt.Fprintf(w, `ts_headline("%s"."%s", to_tsquery('%s')) AS %s`,
|
||||||
//c.sel.Table, cn, arg.Val, col.Name)
|
//c.sel.Table, cn, arg.Val, col.Name)
|
||||||
c.w.WriteString(`ts_headlinek(`)
|
c.w.WriteString(`ts_headlinek(`)
|
||||||
colWithTable(c.w, sel.Table, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
c.w.WriteString(`, to_tsquery('`)
|
c.w.WriteString(`, to_tsquery('`)
|
||||||
c.w.WriteString(arg.Val)
|
c.w.WriteString(arg.Val)
|
||||||
c.w.WriteString(`')`)
|
c.w.WriteString(`')`)
|
||||||
@ -481,7 +484,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
//fmt.Fprintf(w, `%s("%s"."%s") AS %s`, fn, c.sel.Table, cn, col.Name)
|
//fmt.Fprintf(w, `%s("%s"."%s") AS %s`, fn, c.sel.Table, cn, col.Name)
|
||||||
c.w.WriteString(fn)
|
c.w.WriteString(fn)
|
||||||
c.w.WriteString(`(`)
|
c.w.WriteString(`(`)
|
||||||
colWithTable(c.w, sel.Table, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
c.w.WriteString(`)`)
|
c.w.WriteString(`)`)
|
||||||
alias(c.w, col.Name)
|
alias(c.w, col.Name)
|
||||||
}
|
}
|
||||||
@ -489,7 +492,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
} else {
|
} else {
|
||||||
groupBy = append(groupBy, i)
|
groupBy = append(groupBy, i)
|
||||||
//fmt.Fprintf(w, `"%s"."%s"`, c.sel.Table, cn)
|
//fmt.Fprintf(w, `"%s"."%s"`, c.sel.Table, cn)
|
||||||
colWithTable(c.w, sel.Table, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if i < len(sel.Cols)-1 || len(childCols) != 0 {
|
if i < len(sel.Cols)-1 || len(childCols) != 0 {
|
||||||
@ -510,15 +513,10 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
|
|
||||||
c.w.WriteString(` FROM `)
|
c.w.WriteString(` FROM `)
|
||||||
|
|
||||||
if c.schema.IsAlias(sel.Table) || ti.Singular {
|
//fmt.Fprintf(w, ` FROM "%s"`, c.sel.Table)
|
||||||
//fmt.Fprintf(w, ` FROM "%s" AS "%s"`, tn, c.sel.Table)
|
c.w.WriteString(`"`)
|
||||||
tableWithAlias(c.w, ti.Name, sel.Table)
|
c.w.WriteString(ti.Name)
|
||||||
} else {
|
c.w.WriteString(`"`)
|
||||||
//fmt.Fprintf(w, ` FROM "%s"`, c.sel.Table)
|
|
||||||
c.w.WriteString(`"`)
|
|
||||||
c.w.WriteString(ti.Name)
|
|
||||||
c.w.WriteString(`"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if tn, ok := c.tmap[sel.Table]; ok {
|
// if tn, ok := c.tmap[sel.Table]; ok {
|
||||||
// //fmt.Fprintf(w, ` FROM "%s" AS "%s"`, tn, c.sel.Table)
|
// //fmt.Fprintf(w, ` FROM "%s" AS "%s"`, tn, c.sel.Table)
|
||||||
@ -545,7 +543,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
|
|
||||||
c.w.WriteString(` WHERE (`)
|
c.w.WriteString(` WHERE (`)
|
||||||
|
|
||||||
if err := c.renderRelationship(sel); err != nil {
|
if err := c.renderRelationship(sel, ti); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,22 +565,24 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
c.w.WriteString(`, `)
|
c.w.WriteString(`, `)
|
||||||
}
|
}
|
||||||
//fmt.Fprintf(w, `"%s"."%s"`, c.sel.Table, c.sel.Cols[id].Name)
|
//fmt.Fprintf(w, `"%s"."%s"`, c.sel.Table, c.sel.Cols[id].Name)
|
||||||
colWithTable(c.w, sel.Table, sel.Cols[id].Name)
|
colWithTable(c.w, ti.Name, sel.Cols[id].Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sel.Paging.Limit) != 0 {
|
if sel.Action == 0 {
|
||||||
//fmt.Fprintf(w, ` LIMIT ('%s') :: integer`, c.sel.Paging.Limit)
|
if len(sel.Paging.Limit) != 0 {
|
||||||
c.w.WriteString(` LIMIT ('`)
|
//fmt.Fprintf(w, ` LIMIT ('%s') :: integer`, c.sel.Paging.Limit)
|
||||||
c.w.WriteString(sel.Paging.Limit)
|
c.w.WriteString(` LIMIT ('`)
|
||||||
c.w.WriteString(`') :: integer`)
|
c.w.WriteString(sel.Paging.Limit)
|
||||||
|
c.w.WriteString(`') :: integer`)
|
||||||
|
|
||||||
} else if ti.Singular {
|
} else if ti.Singular {
|
||||||
c.w.WriteString(` LIMIT ('1') :: integer`)
|
c.w.WriteString(` LIMIT ('1') :: integer`)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c.w.WriteString(` LIMIT ('20') :: integer`)
|
c.w.WriteString(` LIMIT ('20') :: integer`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sel.Paging.Offset) != 0 {
|
if len(sel.Paging.Offset) != 0 {
|
||||||
@ -594,11 +594,11 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
|
|
||||||
//fmt.Fprintf(w, `) AS "%s_%d"`, c.sel.Table, c.sel.ID)
|
//fmt.Fprintf(w, `) AS "%s_%d"`, c.sel.Table, c.sel.ID)
|
||||||
c.w.WriteString(`)`)
|
c.w.WriteString(`)`)
|
||||||
aliasWithID(c.w, sel.Table, sel.ID)
|
aliasWithID(c.w, ti.Name, sel.ID)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderOrderByColumns(sel *qcode.Select) {
|
func (c *compilerContext) renderOrderByColumns(sel *qcode.Select, ti *DBTableInfo) {
|
||||||
colsRendered := len(sel.Cols) != 0
|
colsRendered := len(sel.Cols) != 0
|
||||||
|
|
||||||
for i := range sel.OrderBy {
|
for i := range sel.OrderBy {
|
||||||
@ -611,13 +611,13 @@ func (c *compilerContext) renderOrderByColumns(sel *qcode.Select) {
|
|||||||
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s_%d_%s_ob"`,
|
//fmt.Fprintf(w, `"%s_%d"."%s" AS "%s_%d_%s_ob"`,
|
||||||
//c.sel.Table, c.sel.ID, c,
|
//c.sel.Table, c.sel.ID, c,
|
||||||
//c.sel.Table, c.sel.ID, c)
|
//c.sel.Table, c.sel.ID, c)
|
||||||
colWithTableID(c.w, sel.Table, sel.ID, col)
|
colWithTableID(c.w, ti.Name, sel.ID, col)
|
||||||
c.w.WriteString(` AS `)
|
c.w.WriteString(` AS `)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, col, "_ob")
|
tableIDColSuffix(c.w, sel.Table, sel.ID, col, "_ob")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderRelationship(sel *qcode.Select) error {
|
func (c *compilerContext) renderRelationship(sel *qcode.Select, ti *DBTableInfo) error {
|
||||||
parent := c.s[sel.ParentID]
|
parent := c.s[sel.ParentID]
|
||||||
|
|
||||||
rel, err := c.schema.GetRel(sel.Table, parent.Table)
|
rel, err := c.schema.GetRel(sel.Table, parent.Table)
|
||||||
@ -630,7 +630,7 @@ func (c *compilerContext) renderRelationship(sel *qcode.Select) error {
|
|||||||
//fmt.Fprintf(w, `(("%s"."%s") = ("%s_%d"."%s"))`,
|
//fmt.Fprintf(w, `(("%s"."%s") = ("%s_%d"."%s"))`,
|
||||||
//c.sel.Table, rel.Col1, c.parent.Table, c.parent.ID, rel.Col2)
|
//c.sel.Table, rel.Col1, c.parent.Table, c.parent.ID, rel.Col2)
|
||||||
c.w.WriteString(`((`)
|
c.w.WriteString(`((`)
|
||||||
colWithTable(c.w, sel.Table, rel.Col1)
|
colWithTable(c.w, ti.Name, rel.Col1)
|
||||||
c.w.WriteString(`) = (`)
|
c.w.WriteString(`) = (`)
|
||||||
colWithTableID(c.w, parent.Table, parent.ID, rel.Col2)
|
colWithTableID(c.w, parent.Table, parent.ID, rel.Col2)
|
||||||
c.w.WriteString(`))`)
|
c.w.WriteString(`))`)
|
||||||
@ -639,7 +639,7 @@ func (c *compilerContext) renderRelationship(sel *qcode.Select) error {
|
|||||||
//fmt.Fprintf(w, `(("%s"."%s") = ("%s_%d"."%s"))`,
|
//fmt.Fprintf(w, `(("%s"."%s") = ("%s_%d"."%s"))`,
|
||||||
//c.sel.Table, rel.Col1, c.parent.Table, c.parent.ID, rel.Col2)
|
//c.sel.Table, rel.Col1, c.parent.Table, c.parent.ID, rel.Col2)
|
||||||
c.w.WriteString(`((`)
|
c.w.WriteString(`((`)
|
||||||
colWithTable(c.w, sel.Table, rel.Col1)
|
colWithTable(c.w, ti.Name, rel.Col1)
|
||||||
c.w.WriteString(`) = (`)
|
c.w.WriteString(`) = (`)
|
||||||
colWithTableID(c.w, parent.Table, parent.ID, rel.Col2)
|
colWithTableID(c.w, parent.Table, parent.ID, rel.Col2)
|
||||||
c.w.WriteString(`))`)
|
c.w.WriteString(`))`)
|
||||||
@ -648,7 +648,7 @@ func (c *compilerContext) renderRelationship(sel *qcode.Select) error {
|
|||||||
//fmt.Fprintf(w, `(("%s"."%s") = ("%s"."%s"))`,
|
//fmt.Fprintf(w, `(("%s"."%s") = ("%s"."%s"))`,
|
||||||
//c.sel.Table, rel.Col1, rel.Through, rel.Col2)
|
//c.sel.Table, rel.Col1, rel.Through, rel.Col2)
|
||||||
c.w.WriteString(`((`)
|
c.w.WriteString(`((`)
|
||||||
colWithTable(c.w, sel.Table, rel.Col1)
|
colWithTable(c.w, ti.Name, rel.Col1)
|
||||||
c.w.WriteString(`) = (`)
|
c.w.WriteString(`) = (`)
|
||||||
colWithTable(c.w, rel.Through, rel.Col2)
|
colWithTable(c.w, rel.Through, rel.Col2)
|
||||||
c.w.WriteString(`))`)
|
c.w.WriteString(`))`)
|
||||||
@ -683,6 +683,7 @@ func (c *compilerContext) renderWhere(sel *qcode.Select, ti *DBTableInfo) error
|
|||||||
default:
|
default:
|
||||||
return fmt.Errorf("11: unexpected value %v (%t)", intf, intf)
|
return fmt.Errorf("11: unexpected value %v (%t)", intf, intf)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *qcode.Exp:
|
case *qcode.Exp:
|
||||||
switch val.Op {
|
switch val.Op {
|
||||||
case qcode.OpAnd, qcode.OpOr:
|
case qcode.OpAnd, qcode.OpOr:
|
||||||
@ -693,109 +694,109 @@ func (c *compilerContext) renderWhere(sel *qcode.Select, ti *DBTableInfo) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
qcode.FreeExp(val)
|
qcode.FreeExp(val)
|
||||||
continue
|
|
||||||
case qcode.OpNot:
|
case qcode.OpNot:
|
||||||
st.Push(val.Children[0])
|
st.Push(val.Children[0])
|
||||||
st.Push(qcode.OpNot)
|
st.Push(qcode.OpNot)
|
||||||
qcode.FreeExp(val)
|
qcode.FreeExp(val)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if val.NestedCol {
|
|
||||||
//fmt.Fprintf(w, `(("%s") `, val.Col)
|
|
||||||
c.w.WriteString(`(("`)
|
|
||||||
c.w.WriteString(val.Col)
|
|
||||||
c.w.WriteString(`") `)
|
|
||||||
|
|
||||||
} else if len(val.Col) != 0 {
|
|
||||||
//fmt.Fprintf(w, `(("%s"."%s") `, c.sel.Table, val.Col)
|
|
||||||
c.w.WriteString(`((`)
|
|
||||||
colWithTable(c.w, sel.Table, val.Col)
|
|
||||||
c.w.WriteString(`) `)
|
|
||||||
}
|
|
||||||
valExists := true
|
|
||||||
|
|
||||||
switch val.Op {
|
|
||||||
case qcode.OpEquals:
|
|
||||||
c.w.WriteString(`=`)
|
|
||||||
case qcode.OpNotEquals:
|
|
||||||
c.w.WriteString(`!=`)
|
|
||||||
case qcode.OpGreaterOrEquals:
|
|
||||||
c.w.WriteString(`>=`)
|
|
||||||
case qcode.OpLesserOrEquals:
|
|
||||||
c.w.WriteString(`<=`)
|
|
||||||
case qcode.OpGreaterThan:
|
|
||||||
c.w.WriteString(`>`)
|
|
||||||
case qcode.OpLesserThan:
|
|
||||||
c.w.WriteString(`<`)
|
|
||||||
case qcode.OpIn:
|
|
||||||
c.w.WriteString(`IN`)
|
|
||||||
case qcode.OpNotIn:
|
|
||||||
c.w.WriteString(`NOT IN`)
|
|
||||||
case qcode.OpLike:
|
|
||||||
c.w.WriteString(`LIKE`)
|
|
||||||
case qcode.OpNotLike:
|
|
||||||
c.w.WriteString(`NOT LIKE`)
|
|
||||||
case qcode.OpILike:
|
|
||||||
c.w.WriteString(`ILIKE`)
|
|
||||||
case qcode.OpNotILike:
|
|
||||||
c.w.WriteString(`NOT ILIKE`)
|
|
||||||
case qcode.OpSimilar:
|
|
||||||
c.w.WriteString(`SIMILAR TO`)
|
|
||||||
case qcode.OpNotSimilar:
|
|
||||||
c.w.WriteString(`NOT SIMILAR TO`)
|
|
||||||
case qcode.OpContains:
|
|
||||||
c.w.WriteString(`@>`)
|
|
||||||
case qcode.OpContainedIn:
|
|
||||||
c.w.WriteString(`<@`)
|
|
||||||
case qcode.OpHasKey:
|
|
||||||
c.w.WriteString(`?`)
|
|
||||||
case qcode.OpHasKeyAny:
|
|
||||||
c.w.WriteString(`?|`)
|
|
||||||
case qcode.OpHasKeyAll:
|
|
||||||
c.w.WriteString(`?&`)
|
|
||||||
case qcode.OpIsNull:
|
|
||||||
if strings.EqualFold(val.Val, "true") {
|
|
||||||
c.w.WriteString(`IS NULL)`)
|
|
||||||
} else {
|
|
||||||
c.w.WriteString(`IS NOT NULL)`)
|
|
||||||
}
|
|
||||||
valExists = false
|
|
||||||
case qcode.OpEqID:
|
|
||||||
if len(ti.PrimaryCol) == 0 {
|
|
||||||
return fmt.Errorf("no primary key column defined for %s", sel.Table)
|
|
||||||
}
|
|
||||||
//fmt.Fprintf(w, `(("%s") =`, c.ti.PrimaryCol)
|
|
||||||
c.w.WriteString(`(("`)
|
|
||||||
c.w.WriteString(ti.PrimaryCol)
|
|
||||||
c.w.WriteString(`") =`)
|
|
||||||
|
|
||||||
case qcode.OpTsQuery:
|
|
||||||
if len(ti.TSVCol) == 0 {
|
|
||||||
return fmt.Errorf("no tsv column defined for %s", sel.Table)
|
|
||||||
}
|
|
||||||
//fmt.Fprintf(w, `(("%s") @@ to_tsquery('%s'))`, c.ti.TSVCol, val.Val)
|
|
||||||
c.w.WriteString(`(("`)
|
|
||||||
c.w.WriteString(ti.TSVCol)
|
|
||||||
c.w.WriteString(`") @@ to_tsquery('`)
|
|
||||||
c.w.WriteString(val.Val)
|
|
||||||
c.w.WriteString(`'))`)
|
|
||||||
valExists = false
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("[Where] unexpected op code %d", val.Op)
|
if val.NestedCol {
|
||||||
}
|
//fmt.Fprintf(w, `(("%s") `, val.Col)
|
||||||
|
c.w.WriteString(`(("`)
|
||||||
|
c.w.WriteString(val.Col)
|
||||||
|
c.w.WriteString(`") `)
|
||||||
|
|
||||||
if valExists {
|
} else if len(val.Col) != 0 {
|
||||||
if val.Type == qcode.ValList {
|
//fmt.Fprintf(w, `(("%s"."%s") `, c.sel.Table, val.Col)
|
||||||
c.renderList(val)
|
c.w.WriteString(`((`)
|
||||||
} else {
|
colWithTable(c.w, ti.Name, val.Col)
|
||||||
c.renderVal(val, c.vars)
|
c.w.WriteString(`) `)
|
||||||
}
|
}
|
||||||
c.w.WriteString(`)`)
|
valExists := true
|
||||||
}
|
|
||||||
|
|
||||||
qcode.FreeExp(val)
|
switch val.Op {
|
||||||
|
case qcode.OpEquals:
|
||||||
|
c.w.WriteString(`=`)
|
||||||
|
case qcode.OpNotEquals:
|
||||||
|
c.w.WriteString(`!=`)
|
||||||
|
case qcode.OpGreaterOrEquals:
|
||||||
|
c.w.WriteString(`>=`)
|
||||||
|
case qcode.OpLesserOrEquals:
|
||||||
|
c.w.WriteString(`<=`)
|
||||||
|
case qcode.OpGreaterThan:
|
||||||
|
c.w.WriteString(`>`)
|
||||||
|
case qcode.OpLesserThan:
|
||||||
|
c.w.WriteString(`<`)
|
||||||
|
case qcode.OpIn:
|
||||||
|
c.w.WriteString(`IN`)
|
||||||
|
case qcode.OpNotIn:
|
||||||
|
c.w.WriteString(`NOT IN`)
|
||||||
|
case qcode.OpLike:
|
||||||
|
c.w.WriteString(`LIKE`)
|
||||||
|
case qcode.OpNotLike:
|
||||||
|
c.w.WriteString(`NOT LIKE`)
|
||||||
|
case qcode.OpILike:
|
||||||
|
c.w.WriteString(`ILIKE`)
|
||||||
|
case qcode.OpNotILike:
|
||||||
|
c.w.WriteString(`NOT ILIKE`)
|
||||||
|
case qcode.OpSimilar:
|
||||||
|
c.w.WriteString(`SIMILAR TO`)
|
||||||
|
case qcode.OpNotSimilar:
|
||||||
|
c.w.WriteString(`NOT SIMILAR TO`)
|
||||||
|
case qcode.OpContains:
|
||||||
|
c.w.WriteString(`@>`)
|
||||||
|
case qcode.OpContainedIn:
|
||||||
|
c.w.WriteString(`<@`)
|
||||||
|
case qcode.OpHasKey:
|
||||||
|
c.w.WriteString(`?`)
|
||||||
|
case qcode.OpHasKeyAny:
|
||||||
|
c.w.WriteString(`?|`)
|
||||||
|
case qcode.OpHasKeyAll:
|
||||||
|
c.w.WriteString(`?&`)
|
||||||
|
case qcode.OpIsNull:
|
||||||
|
if strings.EqualFold(val.Val, "true") {
|
||||||
|
c.w.WriteString(`IS NULL)`)
|
||||||
|
} else {
|
||||||
|
c.w.WriteString(`IS NOT NULL)`)
|
||||||
|
}
|
||||||
|
valExists = false
|
||||||
|
case qcode.OpEqID:
|
||||||
|
if len(ti.PrimaryCol) == 0 {
|
||||||
|
return fmt.Errorf("no primary key column defined for %s", ti.Name)
|
||||||
|
}
|
||||||
|
//fmt.Fprintf(w, `(("%s") =`, c.ti.PrimaryCol)
|
||||||
|
c.w.WriteString(`((`)
|
||||||
|
colWithTable(c.w, ti.Name, ti.PrimaryCol)
|
||||||
|
//c.w.WriteString(ti.PrimaryCol)
|
||||||
|
c.w.WriteString(`) =`)
|
||||||
|
case qcode.OpTsQuery:
|
||||||
|
if len(ti.TSVCol) == 0 {
|
||||||
|
return fmt.Errorf("no tsv column defined for %s", ti.Name)
|
||||||
|
}
|
||||||
|
//fmt.Fprintf(w, `(("%s") @@ to_tsquery('%s'))`, c.ti.TSVCol, val.Val)
|
||||||
|
c.w.WriteString(`(("`)
|
||||||
|
c.w.WriteString(ti.TSVCol)
|
||||||
|
c.w.WriteString(`") @@ to_tsquery('`)
|
||||||
|
c.w.WriteString(val.Val)
|
||||||
|
c.w.WriteString(`'))`)
|
||||||
|
valExists = false
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("[Where] unexpected op code %d", val.Op)
|
||||||
|
}
|
||||||
|
|
||||||
|
if valExists {
|
||||||
|
if val.Type == qcode.ValList {
|
||||||
|
c.renderList(val)
|
||||||
|
} else {
|
||||||
|
c.renderVal(val, c.vars)
|
||||||
|
}
|
||||||
|
c.w.WriteString(`)`)
|
||||||
|
}
|
||||||
|
|
||||||
|
qcode.FreeExp(val)
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("12: unexpected value %v (%t)", intf, intf)
|
return fmt.Errorf("12: unexpected value %v (%t)", intf, intf)
|
||||||
@ -806,7 +807,7 @@ func (c *compilerContext) renderWhere(sel *qcode.Select, ti *DBTableInfo) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderOrderBy(sel *qcode.Select) error {
|
func (c *compilerContext) renderOrderBy(sel *qcode.Select, ti *DBTableInfo) error {
|
||||||
c.w.WriteString(` ORDER BY `)
|
c.w.WriteString(` ORDER BY `)
|
||||||
for i := range sel.OrderBy {
|
for i := range sel.OrderBy {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
@ -817,27 +818,27 @@ func (c *compilerContext) renderOrderBy(sel *qcode.Select) error {
|
|||||||
switch ob.Order {
|
switch ob.Order {
|
||||||
case qcode.OrderAsc:
|
case qcode.OrderAsc:
|
||||||
//fmt.Fprintf(w, `"%s_%d.ob.%s" ASC`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `"%s_%d.ob.%s" ASC`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` ASC`)
|
c.w.WriteString(` ASC`)
|
||||||
case qcode.OrderDesc:
|
case qcode.OrderDesc:
|
||||||
//fmt.Fprintf(w, `"%s_%d.ob.%s" DESC`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `"%s_%d.ob.%s" DESC`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` DESC`)
|
c.w.WriteString(` DESC`)
|
||||||
case qcode.OrderAscNullsFirst:
|
case qcode.OrderAscNullsFirst:
|
||||||
//fmt.Fprintf(w, `"%s_%d.ob.%s" ASC NULLS FIRST`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `"%s_%d.ob.%s" ASC NULLS FIRST`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` ASC NULLS FIRST`)
|
c.w.WriteString(` ASC NULLS FIRST`)
|
||||||
case qcode.OrderDescNullsFirst:
|
case qcode.OrderDescNullsFirst:
|
||||||
//fmt.Fprintf(w, `%s_%d.ob.%s DESC NULLS FIRST`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `%s_%d.ob.%s DESC NULLS FIRST`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` DESC NULLLS FIRST`)
|
c.w.WriteString(` DESC NULLLS FIRST`)
|
||||||
case qcode.OrderAscNullsLast:
|
case qcode.OrderAscNullsLast:
|
||||||
//fmt.Fprintf(w, `"%s_%d.ob.%s ASC NULLS LAST`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `"%s_%d.ob.%s ASC NULLS LAST`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` ASC NULLS LAST`)
|
c.w.WriteString(` ASC NULLS LAST`)
|
||||||
case qcode.OrderDescNullsLast:
|
case qcode.OrderDescNullsLast:
|
||||||
//fmt.Fprintf(w, `%s_%d.ob.%s DESC NULLS LAST`, sel.Table, sel.ID, ob.Col)
|
//fmt.Fprintf(w, `%s_%d.ob.%s DESC NULLS LAST`, sel.Table, sel.ID, ob.Col)
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, ob.Col, "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, ob.Col, "_ob")
|
||||||
c.w.WriteString(` DESC NULLS LAST`)
|
c.w.WriteString(` DESC NULLS LAST`)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("13: unexpected value %v", ob.Order)
|
return fmt.Errorf("13: unexpected value %v", ob.Order)
|
||||||
@ -846,14 +847,14 @@ func (c *compilerContext) renderOrderBy(sel *qcode.Select) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderDistinctOn(sel *qcode.Select) {
|
func (c *compilerContext) renderDistinctOn(sel *qcode.Select, ti *DBTableInfo) {
|
||||||
io.WriteString(c.w, `DISTINCT ON (`)
|
io.WriteString(c.w, `DISTINCT ON (`)
|
||||||
for i := range sel.DistinctOn {
|
for i := range sel.DistinctOn {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
c.w.WriteString(`, `)
|
c.w.WriteString(`, `)
|
||||||
}
|
}
|
||||||
//fmt.Fprintf(w, `"%s_%d.ob.%s"`, c.sel.Table, c.sel.ID, c.sel.DistinctOn[i])
|
//fmt.Fprintf(w, `"%s_%d.ob.%s"`, c.sel.Table, c.sel.ID, c.sel.DistinctOn[i])
|
||||||
tableIDColSuffix(c.w, sel.Table, sel.ID, sel.DistinctOn[i], "_ob")
|
tableIDColSuffix(c.w, ti.Name, sel.ID, sel.DistinctOn[i], "_ob")
|
||||||
}
|
}
|
||||||
c.w.WriteString(`) `)
|
c.w.WriteString(`) `)
|
||||||
}
|
}
|
||||||
@ -876,10 +877,9 @@ func (c *compilerContext) renderList(ex *qcode.Exp) {
|
|||||||
c.w.WriteString(`)`)
|
c.w.WriteString(`)`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderVal(ex *qcode.Exp,
|
func (c *compilerContext) renderVal(ex *qcode.Exp, vars map[string]string) {
|
||||||
vars map[string]string) {
|
|
||||||
|
|
||||||
io.WriteString(c.w, ` `)
|
io.WriteString(c.w, ` `)
|
||||||
|
|
||||||
switch ex.Type {
|
switch ex.Type {
|
||||||
case qcode.ValBool, qcode.ValInt, qcode.ValFloat:
|
case qcode.ValBool, qcode.ValInt, qcode.ValFloat:
|
||||||
if len(ex.Val) != 0 {
|
if len(ex.Val) != 0 {
|
||||||
|
@ -58,45 +58,45 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
columns := [][]*DBColumn{
|
columns := [][]*DBColumn{
|
||||||
[]*DBColumn{
|
[]*DBColumn{
|
||||||
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 2, Name: "full_name", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 2, Name: "full_name", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 3, Name: "phone", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 3, Name: "phone", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 4, Name: "email", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 4, Name: "email", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 5, Name: "encrypted_password", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 5, Name: "encrypted_password", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 6, Name: "reset_password_token", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 6, Name: "reset_password_token", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 7, Name: "reset_password_sent_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 7, Name: "reset_password_sent_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 8, Name: "remember_created_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 8, Name: "remember_created_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 9, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 9, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 10, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)}},
|
&DBColumn{ID: 10, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)}},
|
||||||
[]*DBColumn{
|
[]*DBColumn{
|
||||||
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 2, Name: "full_name", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 2, Name: "full_name", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 3, Name: "phone", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 3, Name: "phone", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 4, Name: "avatar", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 4, Name: "avatar", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 5, Name: "email", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 5, Name: "email", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 6, Name: "encrypted_password", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 6, Name: "encrypted_password", Type: "character varying", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 7, Name: "reset_password_token", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 7, Name: "reset_password_token", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 8, Name: "reset_password_sent_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 8, Name: "reset_password_sent_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 9, Name: "remember_created_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 9, Name: "remember_created_at", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 10, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 10, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 11, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)}},
|
&DBColumn{ID: 11, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)}},
|
||||||
[]*DBColumn{
|
[]*DBColumn{
|
||||||
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 2, Name: "name", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 2, Name: "name", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 3, Name: "description", Type: "text", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 3, Name: "description", Type: "text", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 4, Name: "price", Type: "numeric(7,2)", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 4, Name: "price", Type: "numeric(7,2)", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 5, Name: "user_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "users", FKeyColID: []int{1}},
|
&DBColumn{ID: 5, Name: "user_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "users", FKeyColID: []int16{1}},
|
||||||
&DBColumn{ID: 6, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 6, Name: "created_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 7, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 7, Name: "updated_at", Type: "timestamp without time zone", NotNull: true, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 8, Name: "tsv", Type: "tsvector", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)}},
|
&DBColumn{ID: 8, Name: "tsv", Type: "tsvector", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)}},
|
||||||
[]*DBColumn{
|
[]*DBColumn{
|
||||||
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 1, Name: "id", Type: "bigint", NotNull: true, PrimaryKey: true, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 2, Name: "customer_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "customers", FKeyColID: []int{1}},
|
&DBColumn{ID: 2, Name: "customer_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "customers", FKeyColID: []int16{1}},
|
||||||
&DBColumn{ID: 3, Name: "product_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "products", FKeyColID: []int{1}},
|
&DBColumn{ID: 3, Name: "product_id", Type: "bigint", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "products", FKeyColID: []int16{1}},
|
||||||
&DBColumn{ID: 4, Name: "sale_type", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 4, Name: "sale_type", Type: "character varying", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 5, Name: "quantity", Type: "integer", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 5, Name: "quantity", Type: "integer", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 6, Name: "due_date", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)},
|
&DBColumn{ID: 6, Name: "due_date", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)},
|
||||||
&DBColumn{ID: 7, Name: "returned", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int(nil)}},
|
&DBColumn{ID: 7, Name: "returned", Type: "timestamp without time zone", NotNull: false, PrimaryKey: false, UniqueKey: false, FKeyTable: "", FKeyColID: []int16(nil)}},
|
||||||
}
|
}
|
||||||
|
|
||||||
schema := &DBSchema{
|
schema := &DBSchema{
|
||||||
@ -126,6 +126,7 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func compileGQLToPSQL(gql string, vars Variables) ([]byte, error) {
|
func compileGQLToPSQL(gql string, vars Variables) ([]byte, error) {
|
||||||
|
|
||||||
qc, err := qcompile.Compile([]byte(gql))
|
qc, err := qcompile.Compile([]byte(gql))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -154,7 +155,7 @@ func withComplexArgs(t *testing.T) {
|
|||||||
# no duplicate prices returned
|
# no duplicate prices returned
|
||||||
distinct: [ price ]
|
distinct: [ price ]
|
||||||
|
|
||||||
# only items with an id >= 30 and < 30 are returned
|
# only items with an id >= 20 and < 28 are returned
|
||||||
where: { id: { and: { greater_or_equals: 20, lt: 28 } } }) {
|
where: { id: { and: { greater_or_equals: 20, lt: 28 } } }) {
|
||||||
id
|
id
|
||||||
NAME
|
NAME
|
||||||
@ -162,7 +163,7 @@ func withComplexArgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products" ORDER BY "products_0_price_ob" DESC), '[]') AS "products" FROM (SELECT DISTINCT ON ("products_0_price_ob") row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "products", "products_0"."price" AS "products_0_price_ob" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") < 28) AND (("products"."id") >= 20)) LIMIT ('30') :: integer) AS "products_0" ORDER BY "products_0_price_ob" DESC LIMIT ('30') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0" ORDER BY "products_0_price_ob" DESC), '[]') AS "products" FROM (SELECT DISTINCT ON ("products_0_price_ob") row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "sel_json_0", "products_0"."price" AS "products_0_price_ob" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") < 28) AND (("products"."id") >= 20)) LIMIT ('30') :: integer) AS "products_0" ORDER BY "products_0_price_ob" DESC LIMIT ('30') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -190,7 +191,7 @@ func withWhereMultiOr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "products" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") < 20) OR (("products"."price") > 10) OR NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") < 20) OR (("products"."price") > 10) OR NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -216,7 +217,7 @@ func withWhereIsNull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "products" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") > 10) AND NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") > 10) AND NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -242,7 +243,7 @@ func withWhereAndList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "products" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") > 10) AND NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") > 10) AND NOT (("products"."id") IS NULL)) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -262,7 +263,7 @@ func fetchByID(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("id") = 15)) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") = 15)) LIMIT ('1') :: integer) AS "products_0" LIMIT ('1') :: integer) AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -282,7 +283,7 @@ func searchQuery(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "products" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("tsv") @@ to_tsquery('Imperial'))) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("tsv") @@ to_tsquery('Imperial'))) LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -305,7 +306,7 @@ func oneToMany(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('users', users) FROM (SELECT coalesce(json_agg("users"), '[]') AS "users" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "users_0"."email" AS "email", "products_1_join"."products" AS "products") AS "sel_0")) AS "users" FROM (SELECT "users"."email", "users"."id" FROM "users" WHERE ((("users"."id") = {{user_id}})) LIMIT ('20') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "products_1"."name" AS "name", "products_1"."price" AS "price") AS "sel_1")) AS "products" FROM (SELECT "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('20') :: integer) AS "products_1" LIMIT ('20') :: integer) AS "products_1") AS "products_1_join" ON ('true') LIMIT ('20') :: integer) AS "users_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('users', users) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "users" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "users_0"."email" AS "email", "products_1_join"."products" AS "products") AS "sel_0")) AS "sel_json_0" FROM (SELECT "users"."email", "users"."id" FROM "users" WHERE ((("users"."id") = {{user_id}})) LIMIT ('20') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("sel_json_1"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "products_1"."name" AS "name", "products_1"."price" AS "price") AS "sel_1")) AS "sel_json_1" FROM (SELECT "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('20') :: integer) AS "products_1" LIMIT ('20') :: integer) AS "sel_json_agg_1") AS "products_1_join" ON ('true') LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -328,7 +329,7 @@ func belongsTo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "products_0"."price" AS "price", "users_1_join"."users" AS "users") AS "sel_0")) AS "products" FROM (SELECT "products"."name", "products"."price", "products"."user_id" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("users"), '[]') AS "users" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "users_1"."email" AS "email") AS "sel_1")) AS "users" FROM (SELECT "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('20') :: integer) AS "users_1" LIMIT ('20') :: integer) AS "users_1") AS "users_1_join" ON ('true') LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "products_0"."price" AS "price", "users_1_join"."users" AS "users") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."name", "products"."price", "products"."user_id" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("sel_json_1"), '[]') AS "users" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "users_1"."email" AS "email") AS "sel_1")) AS "sel_json_1" FROM (SELECT "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('20') :: integer) AS "users_1" LIMIT ('20') :: integer) AS "sel_json_agg_1") AS "users_1_join" ON ('true') LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -351,7 +352,7 @@ func manyToMany(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "customers_1_join"."customers" AS "customers") AS "sel_0")) AS "products" FROM (SELECT "products"."name", "products"."id" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("customers"), '[]') AS "customers" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "customers_1"."email" AS "email", "customers_1"."full_name" AS "full_name") AS "sel_1")) AS "customers" FROM (SELECT "customers"."email", "customers"."full_name" FROM "customers" LEFT OUTER JOIN "purchases" ON (("purchases"."product_id") = ("products_0"."id")) WHERE ((("customers"."id") = ("purchases"."customer_id"))) LIMIT ('20') :: integer) AS "customers_1" LIMIT ('20') :: integer) AS "customers_1") AS "customers_1_join" ON ('true') LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "customers_1_join"."customers" AS "customers") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."name", "products"."id" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("sel_json_1"), '[]') AS "customers" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "customers_1"."email" AS "email", "customers_1"."full_name" AS "full_name") AS "sel_1")) AS "sel_json_1" FROM (SELECT "customers"."email", "customers"."full_name" FROM "customers" LEFT OUTER JOIN "purchases" ON (("purchases"."product_id") = ("products_0"."id")) WHERE ((("customers"."id") = ("purchases"."customer_id"))) LIMIT ('20') :: integer) AS "customers_1" LIMIT ('20') :: integer) AS "sel_json_agg_1") AS "customers_1_join" ON ('true') LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -374,7 +375,7 @@ func manyToManyReverse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('customers', customers) FROM (SELECT coalesce(json_agg("customers"), '[]') AS "customers" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "customers_0"."email" AS "email", "customers_0"."full_name" AS "full_name", "products_1_join"."products" AS "products") AS "sel_0")) AS "customers" FROM (SELECT "customers"."email", "customers"."full_name", "customers"."id" FROM "customers" LIMIT ('20') :: integer) AS "customers_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "products_1"."name" AS "name") AS "sel_1")) AS "products" FROM (SELECT "products"."name" FROM "products" LEFT OUTER JOIN "purchases" ON (("purchases"."customer_id") = ("customers_0"."id")) WHERE ((("products"."id") = ("purchases"."product_id"))) LIMIT ('20') :: integer) AS "products_1" LIMIT ('20') :: integer) AS "products_1") AS "products_1_join" ON ('true') LIMIT ('20') :: integer) AS "customers_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('customers', customers) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "customers" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "customers_0"."email" AS "email", "customers_0"."full_name" AS "full_name", "products_1_join"."products" AS "products") AS "sel_0")) AS "sel_json_0" FROM (SELECT "customers"."email", "customers"."full_name", "customers"."id" FROM "customers" LIMIT ('20') :: integer) AS "customers_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(json_agg("sel_json_1"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_1" FROM (SELECT "products_1"."name" AS "name") AS "sel_1")) AS "sel_json_1" FROM (SELECT "products"."name" FROM "products" LEFT OUTER JOIN "purchases" ON (("purchases"."customer_id") = ("customers_0"."id")) WHERE ((("products"."id") = ("purchases"."product_id"))) LIMIT ('20') :: integer) AS "products_1" LIMIT ('20') :: integer) AS "sel_json_agg_1") AS "products_1_join" ON ('true') LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -394,7 +395,7 @@ func aggFunction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "products_0"."count_price" AS "count_price") AS "sel_0")) AS "products" FROM (SELECT "products"."name", count("products"."price") AS "count_price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) GROUP BY "products"."name" LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."name" AS "name", "products_0"."count_price" AS "count_price") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."name", count("products"."price") AS "count_price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8)) GROUP BY "products"."name" LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -414,7 +415,7 @@ func aggFunctionWithFilter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("products"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."max_price" AS "max_price") AS "sel_0")) AS "products" FROM (SELECT "products"."id", max("products"."price") AS "max_price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") > 10)) GROUP BY "products"."id" LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "products_0") AS "done_1337";`
|
sql := `SELECT json_object_agg('products', products) FROM (SELECT coalesce(json_agg("sel_json_0"), '[]') AS "products" FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."max_price" AS "max_price") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", max("products"."price") AS "max_price" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."id") > 10)) GROUP BY "products"."id" LIMIT ('20') :: integer) AS "products_0" LIMIT ('20') :: integer) AS "sel_json_agg_0") AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -434,7 +435,7 @@ func queryWithVariables(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('product', product) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "product_0"."id" AS "id", "product_0"."name" AS "name") AS "sel_0")) AS "product" FROM (SELECT "product"."id", "product"."name" FROM "products" AS "product" WHERE ((("product"."price") > 0) AND (("product"."price") < 8) AND (("product"."price") = {{product_price}}) AND (("id") = {{product_id}})) LIMIT ('1') :: integer) AS "product_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `SELECT json_object_agg('product', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name") AS "sel_0")) AS "sel_json_0" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((("products"."price") > 0) AND (("products"."price") < 8) AND (("products"."price") = {{product_price}}) AND (("products"."id") = {{product_id}})) LIMIT ('1') :: integer) AS "products_0" LIMIT ('1') :: integer) AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -453,7 +454,7 @@ func syntheticTables(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
sql := `SELECT json_object_agg('me', me) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "me_0"."email" AS "email") AS "sel_0")) AS "me" FROM (SELECT "me"."email" FROM "users" AS "me" WHERE ((("me"."id") = {{user_id}})) LIMIT ('1') :: integer) AS "me_0" LIMIT ('1') :: integer) AS "done_1337";`
|
sql := `SELECT json_object_agg('me', sel_json_0) FROM (SELECT row_to_json((SELECT "sel_0" FROM (SELECT "users_0"."email" AS "email") AS "sel_0")) AS "sel_json_0" FROM (SELECT "users"."email" FROM "users" WHERE ((("users"."id") = {{user_id}})) LIMIT ('1') :: integer) AS "users_0" LIMIT ('1') :: integer) AS "done_1337";`
|
||||||
|
|
||||||
resSQL, err := compileGQLToPSQL(gql, nil)
|
resSQL, err := compileGQLToPSQL(gql, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -478,8 +479,9 @@ func TestCompileSelect(t *testing.T) {
|
|||||||
t.Run("manyToManyReverse", manyToManyReverse)
|
t.Run("manyToManyReverse", manyToManyReverse)
|
||||||
t.Run("aggFunction", aggFunction)
|
t.Run("aggFunction", aggFunction)
|
||||||
t.Run("aggFunctionWithFilter", aggFunctionWithFilter)
|
t.Run("aggFunctionWithFilter", aggFunctionWithFilter)
|
||||||
t.Run("queryWithVariables", queryWithVariables)
|
|
||||||
t.Run("syntheticTables", syntheticTables)
|
t.Run("syntheticTables", syntheticTables)
|
||||||
|
t.Run("queryWithVariables", queryWithVariables)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var benchGQL = []byte(`query {
|
var benchGQL = []byte(`query {
|
||||||
|
@ -27,9 +27,9 @@ SELECT
|
|||||||
FROM pg_catalog.pg_class c
|
FROM pg_catalog.pg_class c
|
||||||
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
|
||||||
WHERE c.relkind IN ('r','v','m','f','')
|
WHERE c.relkind IN ('r','v','m','f','')
|
||||||
AND n.nspname <> 'pg_catalog'
|
AND n.nspname <> ('pg_catalog')
|
||||||
AND n.nspname <> 'information_schema'
|
AND n.nspname <> ('information_schema')
|
||||||
AND n.nspname !~ '^pg_toast'
|
AND n.nspname !~ ('^pg_toast')
|
||||||
AND pg_catalog.pg_table_is_visible(c.oid);`
|
AND pg_catalog.pg_table_is_visible(c.oid);`
|
||||||
|
|
||||||
var tables []*DBTable
|
var tables []*DBTable
|
||||||
@ -53,14 +53,14 @@ AND pg_catalog.pg_table_is_visible(c.oid);`
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DBColumn struct {
|
type DBColumn struct {
|
||||||
ID int
|
ID int16
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
NotNull bool
|
NotNull bool
|
||||||
PrimaryKey bool
|
PrimaryKey bool
|
||||||
UniqueKey bool
|
UniqueKey bool
|
||||||
FKeyTable string
|
FKeyTable string
|
||||||
FKeyColID []int
|
FKeyColID []int16
|
||||||
fKeyColID pgtype.Int2Array
|
fKeyColID pgtype.Int2Array
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ ORDER BY id;`
|
|||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
cmap := make(map[int]*DBColumn)
|
cmap := make(map[int16]*DBColumn)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
c := DBColumn{}
|
c := DBColumn{}
|
||||||
@ -115,7 +115,6 @@ ORDER BY id;`
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.fKeyColID.AssignTo(&c.FKeyColID)
|
|
||||||
|
|
||||||
if v, ok := cmap[c.ID]; ok {
|
if v, ok := cmap[c.ID]; ok {
|
||||||
if c.PrimaryKey {
|
if c.PrimaryKey {
|
||||||
@ -128,6 +127,10 @@ ORDER BY id;`
|
|||||||
v.UniqueKey = true
|
v.UniqueKey = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
err := c.fKeyColID.AssignTo(&c.FKeyColID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
cmap[c.ID] = &c
|
cmap[c.ID] = &c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -208,7 +211,7 @@ func (s *DBSchema) updateSchema(
|
|||||||
aliases map[string][]string) {
|
aliases map[string][]string) {
|
||||||
|
|
||||||
// Foreign key columns in current table
|
// Foreign key columns in current table
|
||||||
colByID := make(map[int]*DBColumn)
|
colByID := make(map[int16]*DBColumn)
|
||||||
columns := make(map[string]*DBColumn, len(cols))
|
columns := make(map[string]*DBColumn, len(cols))
|
||||||
colNames := make([]string, 0, len(cols))
|
colNames := make([]string, 0, len(cols))
|
||||||
|
|
||||||
@ -309,7 +312,7 @@ func (s *DBSchema) updateSchema(
|
|||||||
func (s *DBSchema) updateSchemaOTMT(
|
func (s *DBSchema) updateSchemaOTMT(
|
||||||
ct string,
|
ct string,
|
||||||
col1, col2 *DBColumn,
|
col1, col2 *DBColumn,
|
||||||
colByID map[int]*DBColumn) {
|
colByID map[int16]*DBColumn) {
|
||||||
|
|
||||||
t1 := strings.ToLower(col1.FKeyTable)
|
t1 := strings.ToLower(col1.FKeyTable)
|
||||||
t2 := strings.ToLower(col2.FKeyTable)
|
t2 := strings.ToLower(col2.FKeyTable)
|
||||||
|
@ -164,7 +164,7 @@ var opMap = map[parserType]QType{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var expPool = sync.Pool{
|
var expPool = sync.Pool{
|
||||||
New: func() interface{} { return new(Exp) },
|
New: func() interface{} { return &Exp{doFree: true} },
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCompiler(c Config) (*Compiler, error) {
|
func NewCompiler(c Config) (*Compiler, error) {
|
||||||
@ -195,6 +195,7 @@ func NewCompiler(c Config) (*Compiler, error) {
|
|||||||
|
|
||||||
seedExp := [100]Exp{}
|
seedExp := [100]Exp{}
|
||||||
for i := range seedExp {
|
for i := range seedExp {
|
||||||
|
seedExp[i].doFree = true
|
||||||
expPool.Put(&seedExp[i])
|
expPool.Put(&seedExp[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +319,6 @@ func (com *Compiler) compileQuery(op *Operation) ([]Select, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fil != nil && fil.Op != OpNop {
|
if fil != nil && fil.Op != OpNop {
|
||||||
|
|
||||||
if root.Where != nil {
|
if root.Where != nil {
|
||||||
ow := root.Where
|
ow := root.Where
|
||||||
|
|
||||||
@ -695,7 +695,7 @@ func newExp(st *util.Stack, node *Node, usePool bool) (*Exp, error) {
|
|||||||
ex = expPool.Get().(*Exp)
|
ex = expPool.Get().(*Exp)
|
||||||
ex.Reset()
|
ex.Reset()
|
||||||
} else {
|
} else {
|
||||||
ex = &Exp{}
|
ex = &Exp{doFree: false}
|
||||||
}
|
}
|
||||||
ex.Children = ex.childrenA[:0]
|
ex.Children = ex.childrenA[:0]
|
||||||
|
|
||||||
@ -881,7 +881,7 @@ func compileFilter(filter []string) (*Exp, error) {
|
|||||||
st := util.NewStack()
|
st := util.NewStack()
|
||||||
|
|
||||||
if len(filter) == 0 {
|
if len(filter) == 0 {
|
||||||
return &Exp{Op: OpNop}, nil
|
return &Exp{Op: OpNop, doFree: false}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range filter {
|
for i := range filter {
|
||||||
@ -893,10 +893,11 @@ func compileFilter(filter []string) (*Exp, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if fl == nil {
|
if fl == nil {
|
||||||
fl = f
|
fl = f
|
||||||
} else {
|
} else {
|
||||||
fl = &Exp{Op: OpAnd, Children: []*Exp{fl, f}}
|
fl = &Exp{Op: OpAnd, Children: []*Exp{fl, f}, doFree: false}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fl, nil
|
return fl, nil
|
||||||
@ -986,6 +987,7 @@ func (t ExpOp) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FreeExp(ex *Exp) {
|
func FreeExp(ex *Exp) {
|
||||||
|
// fmt.Println(">", ex.doFree)
|
||||||
if ex.doFree {
|
if ex.doFree {
|
||||||
expPool.Put(ex)
|
expPool.Put(ex)
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM ruby:2.5
|
FROM ruby:2.5.7
|
||||||
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
|
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
|
||||||
RUN mkdir /app
|
RUN mkdir /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||||
|
|
||||||
ruby '2.5.5'
|
ruby '2.5.7'
|
||||||
|
|
||||||
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
||||||
gem 'rails', '~> 6.0.0.rc1'
|
gem 'rails', '~> 6.0.0.rc1'
|
||||||
|
@ -1,95 +1,90 @@
|
|||||||
GIT
|
GIT
|
||||||
remote: https://github.com/stympy/faker.git
|
remote: https://github.com/stympy/faker.git
|
||||||
revision: 32bac72d67d275bfb26ee7049efe5f3489fff3d0
|
revision: e7c898c05306409cedf5b795a622a326ec87e279
|
||||||
branch: master
|
branch: master
|
||||||
specs:
|
specs:
|
||||||
faker (1.9.3)
|
faker (2.5.0)
|
||||||
i18n (>= 0.7)
|
i18n (~> 1.6.0)
|
||||||
pastel (~> 0.7.2)
|
|
||||||
thor (~> 0.20.0)
|
|
||||||
tty-pager (~> 0.12.0)
|
|
||||||
tty-screen (~> 0.6.5)
|
|
||||||
tty-tree (~> 0.2.0)
|
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.0.0.rc1)
|
actioncable (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.0.0.rc1)
|
actionmailbox (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
activejob (= 6.0.0.rc1)
|
activejob (= 6.0.0)
|
||||||
activerecord (= 6.0.0.rc1)
|
activerecord (= 6.0.0)
|
||||||
activestorage (= 6.0.0.rc1)
|
activestorage (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.0.0.rc1)
|
actionmailer (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
actionview (= 6.0.0.rc1)
|
actionview (= 6.0.0)
|
||||||
activejob (= 6.0.0.rc1)
|
activejob (= 6.0.0)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.0.0.rc1)
|
actionpack (6.0.0)
|
||||||
actionview (= 6.0.0.rc1)
|
actionview (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.0.0.rc1)
|
actiontext (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
activerecord (= 6.0.0.rc1)
|
activerecord (= 6.0.0)
|
||||||
activestorage (= 6.0.0.rc1)
|
activestorage (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.0.0.rc1)
|
actionview (6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||||
activejob (6.0.0.rc1)
|
activejob (6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.0.0.rc1)
|
activemodel (6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
activerecord (6.0.0.rc1)
|
activerecord (6.0.0)
|
||||||
activemodel (= 6.0.0.rc1)
|
activemodel (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
activestorage (6.0.0.rc1)
|
activestorage (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
activejob (= 6.0.0.rc1)
|
activejob (= 6.0.0)
|
||||||
activerecord (= 6.0.0.rc1)
|
activerecord (= 6.0.0)
|
||||||
marcel (~> 0.3.1)
|
marcel (~> 0.3.1)
|
||||||
activesupport (6.0.0.rc1)
|
activesupport (6.0.0)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 0.7, < 2)
|
i18n (>= 0.7, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
zeitwerk (~> 2.1, >= 2.1.4)
|
zeitwerk (~> 2.1, >= 2.1.8)
|
||||||
addressable (2.6.0)
|
addressable (2.7.0)
|
||||||
public_suffix (>= 2.0.2, < 4.0)
|
public_suffix (>= 2.0.2, < 5.0)
|
||||||
archive-zip (0.12.0)
|
archive-zip (0.12.0)
|
||||||
io-like (~> 0.3.0)
|
io-like (~> 0.3.0)
|
||||||
bcrypt (3.1.12)
|
bcrypt (3.1.13)
|
||||||
bindex (0.5.0)
|
bindex (0.8.1)
|
||||||
bootsnap (1.4.1)
|
bootsnap (1.4.5)
|
||||||
msgpack (~> 1.0)
|
msgpack (~> 1.0)
|
||||||
builder (3.2.3)
|
builder (3.2.3)
|
||||||
byebug (11.0.1)
|
byebug (11.0.1)
|
||||||
capybara (3.15.0)
|
capybara (3.29.0)
|
||||||
addressable
|
addressable
|
||||||
mini_mime (>= 0.1.3)
|
mini_mime (>= 0.1.3)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
rack (>= 1.6.0)
|
rack (>= 1.6.0)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
regexp_parser (~> 1.2)
|
regexp_parser (~> 1.5)
|
||||||
xpath (~> 3.2)
|
xpath (~> 3.2)
|
||||||
childprocess (0.9.0)
|
childprocess (2.0.0)
|
||||||
ffi (~> 1.0, >= 1.0.11)
|
rake (< 13.0)
|
||||||
chromedriver-helper (2.1.0)
|
chromedriver-helper (2.1.1)
|
||||||
archive-zip (~> 0.10)
|
archive-zip (~> 0.10)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
coffee-rails (4.2.2)
|
coffee-rails (4.2.2)
|
||||||
@ -101,29 +96,27 @@ GEM
|
|||||||
coffee-script-source (1.12.2)
|
coffee-script-source (1.12.2)
|
||||||
concurrent-ruby (1.1.5)
|
concurrent-ruby (1.1.5)
|
||||||
crass (1.0.4)
|
crass (1.0.4)
|
||||||
devise (4.6.1)
|
devise (4.7.1)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0, < 6.0)
|
railties (>= 4.1.0)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
equatable (0.5.0)
|
erubi (1.9.0)
|
||||||
erubi (1.8.0)
|
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
ffi (1.10.0)
|
ffi (1.11.1)
|
||||||
globalid (0.4.2)
|
globalid (0.4.2)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
i18n (1.6.0)
|
i18n (1.6.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
io-like (0.3.0)
|
io-like (0.3.0)
|
||||||
jbuilder (2.8.0)
|
jbuilder (2.9.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
multi_json (>= 1.2)
|
|
||||||
listen (3.1.5)
|
listen (3.1.5)
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
ruby_dep (~> 1.2)
|
ruby_dep (~> 1.2)
|
||||||
loofah (2.2.3)
|
loofah (2.3.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
@ -132,93 +125,88 @@ GEM
|
|||||||
mimemagic (~> 0.3.2)
|
mimemagic (~> 0.3.2)
|
||||||
method_source (0.9.2)
|
method_source (0.9.2)
|
||||||
mimemagic (0.3.3)
|
mimemagic (0.3.3)
|
||||||
mini_mime (1.0.1)
|
mini_mime (1.0.2)
|
||||||
mini_portile2 (2.4.0)
|
mini_portile2 (2.4.0)
|
||||||
minitest (5.11.3)
|
minitest (5.12.2)
|
||||||
msgpack (1.2.9)
|
msgpack (1.3.1)
|
||||||
multi_json (1.13.1)
|
nio4r (2.5.2)
|
||||||
nio4r (2.3.1)
|
nokogiri (1.10.4)
|
||||||
nokogiri (1.10.3)
|
|
||||||
mini_portile2 (~> 2.4.0)
|
mini_portile2 (~> 2.4.0)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
pastel (0.7.2)
|
|
||||||
equatable (~> 0.5.0)
|
|
||||||
tty-color (~> 0.4.0)
|
|
||||||
pg (1.1.4)
|
pg (1.1.4)
|
||||||
public_suffix (3.0.3)
|
public_suffix (4.0.1)
|
||||||
puma (3.12.1)
|
puma (3.12.1)
|
||||||
rack (2.0.7)
|
rack (2.0.7)
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.0.0.rc1)
|
rails (6.0.0)
|
||||||
actioncable (= 6.0.0.rc1)
|
actioncable (= 6.0.0)
|
||||||
actionmailbox (= 6.0.0.rc1)
|
actionmailbox (= 6.0.0)
|
||||||
actionmailer (= 6.0.0.rc1)
|
actionmailer (= 6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
actiontext (= 6.0.0.rc1)
|
actiontext (= 6.0.0)
|
||||||
actionview (= 6.0.0.rc1)
|
actionview (= 6.0.0)
|
||||||
activejob (= 6.0.0.rc1)
|
activejob (= 6.0.0)
|
||||||
activemodel (= 6.0.0.rc1)
|
activemodel (= 6.0.0)
|
||||||
activerecord (= 6.0.0.rc1)
|
activerecord (= 6.0.0)
|
||||||
activestorage (= 6.0.0.rc1)
|
activestorage (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0)
|
||||||
railties (= 6.0.0.rc1)
|
railties (= 6.0.0)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.0.4)
|
rails-html-sanitizer (1.2.0)
|
||||||
loofah (~> 2.2, >= 2.2.2)
|
loofah (~> 2.2, >= 2.2.2)
|
||||||
railties (6.0.0.rc1)
|
railties (6.0.0)
|
||||||
actionpack (= 6.0.0.rc1)
|
actionpack (= 6.0.0)
|
||||||
activesupport (= 6.0.0.rc1)
|
activesupport (= 6.0.0)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.20.3, < 2.0)
|
thor (>= 0.20.3, < 2.0)
|
||||||
rake (12.3.2)
|
rake (12.3.3)
|
||||||
rb-fsevent (0.10.3)
|
rb-fsevent (0.10.3)
|
||||||
rb-inotify (0.10.0)
|
rb-inotify (0.10.0)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
redis (4.1.0)
|
redis (4.1.3)
|
||||||
redis-actionpack (5.0.2)
|
redis-actionpack (5.1.0)
|
||||||
actionpack (>= 4.0, < 6)
|
actionpack (>= 4.0, < 7)
|
||||||
redis-rack (>= 1, < 3)
|
redis-rack (>= 1, < 3)
|
||||||
redis-store (>= 1.1.0, < 2)
|
redis-store (>= 1.1.0, < 2)
|
||||||
redis-activesupport (5.0.7)
|
redis-activesupport (5.2.0)
|
||||||
activesupport (>= 3, < 6)
|
activesupport (>= 3, < 7)
|
||||||
redis-store (>= 1.3, < 2)
|
redis-store (>= 1.3, < 2)
|
||||||
redis-rack (2.0.5)
|
redis-rack (2.0.6)
|
||||||
rack (>= 1.5, < 3)
|
rack (>= 1.5, < 3)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-rails (5.0.2)
|
redis-rails (5.0.2)
|
||||||
redis-actionpack (>= 5.0, < 6)
|
redis-actionpack (>= 5.0, < 6)
|
||||||
redis-activesupport (>= 5.0, < 6)
|
redis-activesupport (>= 5.0, < 6)
|
||||||
redis-store (>= 1.2, < 2)
|
redis-store (>= 1.2, < 2)
|
||||||
redis-store (1.6.0)
|
redis-store (1.8.0)
|
||||||
redis (>= 2.2, < 5)
|
redis (>= 4, < 5)
|
||||||
regexp_parser (1.3.0)
|
regexp_parser (1.6.0)
|
||||||
responders (2.4.1)
|
responders (3.0.0)
|
||||||
actionpack (>= 4.2.0, < 6.0)
|
actionpack (>= 5.0)
|
||||||
railties (>= 4.2.0, < 6.0)
|
railties (>= 5.0)
|
||||||
ruby_dep (1.5.0)
|
ruby_dep (1.5.0)
|
||||||
rubyzip (1.2.2)
|
rubyzip (2.0.0)
|
||||||
sass (3.7.3)
|
sass (3.7.4)
|
||||||
sass-listen (~> 4.0.0)
|
sass-listen (~> 4.0.0)
|
||||||
sass-listen (4.0.0)
|
sass-listen (4.0.0)
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
sass-rails (5.0.7)
|
sass-rails (5.1.0)
|
||||||
railties (>= 4.0.0, < 6)
|
railties (>= 5.2.0)
|
||||||
sass (~> 3.1)
|
sass (~> 3.1)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
tilt (>= 1.1, < 3)
|
tilt (>= 1.1, < 3)
|
||||||
selenium-webdriver (3.141.0)
|
selenium-webdriver (3.142.5)
|
||||||
childprocess (~> 0.5)
|
childprocess (>= 0.5, < 3.0)
|
||||||
rubyzip (~> 1.2, >= 1.2.2)
|
rubyzip (>= 1.2.2)
|
||||||
spring (2.0.2)
|
spring (2.1.0)
|
||||||
activesupport (>= 4.2)
|
|
||||||
spring-watcher-listen (2.0.1)
|
spring-watcher-listen (2.0.1)
|
||||||
listen (>= 2.7, < 4.0)
|
listen (>= 2.7, < 4.0)
|
||||||
spring (>= 1.2, < 3.0)
|
spring (>= 1.2, < 3.0)
|
||||||
@ -229,44 +217,29 @@ GEM
|
|||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
strings (0.1.4)
|
|
||||||
strings-ansi (~> 0.1.0)
|
|
||||||
unicode-display_width (~> 1.4.0)
|
|
||||||
unicode_utils (~> 1.4.0)
|
|
||||||
strings-ansi (0.1.0)
|
|
||||||
thor (0.20.3)
|
thor (0.20.3)
|
||||||
thread_safe (0.3.6)
|
thread_safe (0.3.6)
|
||||||
tilt (2.0.9)
|
tilt (2.0.10)
|
||||||
tty-color (0.4.3)
|
turbolinks (5.2.1)
|
||||||
tty-pager (0.12.1)
|
|
||||||
strings (~> 0.1.4)
|
|
||||||
tty-screen (~> 0.6)
|
|
||||||
tty-which (~> 0.4)
|
|
||||||
tty-screen (0.6.5)
|
|
||||||
tty-tree (0.2.0)
|
|
||||||
tty-which (0.4.0)
|
|
||||||
turbolinks (5.2.0)
|
|
||||||
turbolinks-source (~> 5.2)
|
turbolinks-source (~> 5.2)
|
||||||
turbolinks-source (5.2.0)
|
turbolinks-source (5.2.0)
|
||||||
tzinfo (1.2.5)
|
tzinfo (1.2.5)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (4.1.20)
|
uglifier (4.2.0)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unicode-display_width (1.4.1)
|
|
||||||
unicode_utils (1.4.0)
|
|
||||||
warden (1.2.8)
|
warden (1.2.8)
|
||||||
rack (>= 2.0.6)
|
rack (>= 2.0.6)
|
||||||
web-console (3.7.0)
|
web-console (4.0.1)
|
||||||
actionview (>= 5.0)
|
actionview (>= 6.0.0)
|
||||||
activemodel (>= 5.0)
|
activemodel (>= 6.0.0)
|
||||||
bindex (>= 0.4.0)
|
bindex (>= 0.4.0)
|
||||||
railties (>= 5.0)
|
railties (>= 6.0.0)
|
||||||
websocket-driver (0.7.0)
|
websocket-driver (0.7.1)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.3)
|
websocket-extensions (0.1.4)
|
||||||
xpath (3.2.0)
|
xpath (3.2.0)
|
||||||
nokogiri (~> 1.8)
|
nokogiri (~> 1.8)
|
||||||
zeitwerk (2.1.6)
|
zeitwerk (2.1.10)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
@ -295,7 +268,7 @@ DEPENDENCIES
|
|||||||
web-console (>= 3.3.0)
|
web-console (>= 3.3.0)
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.5.5p157
|
ruby 2.5.7p206
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.17.3
|
1.17.3
|
||||||
|
@ -97,9 +97,23 @@ func (al *allowList) add(req *gqlReq) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var query string
|
||||||
|
|
||||||
|
for i := 0; i < len(req.Query); i++ {
|
||||||
|
c := req.Query[i]
|
||||||
|
if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' {
|
||||||
|
query = req.Query
|
||||||
|
break
|
||||||
|
|
||||||
|
} else if c == '{' {
|
||||||
|
query = "query " + req.Query
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
al.saveChan <- &allowItem{
|
al.saveChan <- &allowItem{
|
||||||
uri: req.ref,
|
uri: req.ref,
|
||||||
gql: req.Query,
|
gql: query,
|
||||||
vars: req.Vars,
|
vars: req.Vars,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,8 @@ e.g. db:migrate -+1
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initLog() *zerolog.Logger {
|
func initLog() *zerolog.Logger {
|
||||||
logger := zerolog.New(zerolog.ConsoleWriter{Out: os.Stderr}).
|
out := zerolog.ConsoleWriter{Out: os.Stderr}
|
||||||
|
logger := zerolog.New(out).
|
||||||
With().
|
With().
|
||||||
Timestamp().
|
Timestamp().
|
||||||
Caller().
|
Caller().
|
||||||
|
@ -292,7 +292,7 @@ func cmdDBStatus(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("status: ", status)
|
fmt.Println("status: ", status)
|
||||||
fmt.Println("version: %d of %d\n", mver, len(m.Migrations))
|
fmt.Printf("version: %d of %d\n", mver, len(m.Migrations))
|
||||||
fmt.Println("host: ", conf.DB.Host)
|
fmt.Println("host: ", conf.DB.Host)
|
||||||
fmt.Println("database:", conf.DB.DBName)
|
fmt.Println("database:", conf.DB.DBName)
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package serv_test
|
package serv_test
|
||||||
|
|
||||||
import (
|
/*
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestErrorLineExtract(t *testing.T) {
|
func TestErrorLineExtract(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
source string
|
source string
|
||||||
@ -102,3 +99,4 @@ error`,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
@ -105,7 +105,7 @@ func Do(log func(string, ...interface{}), additional ...dir) error {
|
|||||||
// Panic, and Fatal :-/ Printf() is probably best.
|
// Panic, and Fatal :-/ Printf() is probably best.
|
||||||
log("reload error: %v", err)
|
log("reload error: %v", err)
|
||||||
case event := <-watcher.Events:
|
case event := <-watcher.Events:
|
||||||
// Ensure that we use the correct events, as they are not uniform accross
|
// Ensure that we use the correct events, as they are not uniform across
|
||||||
// platforms. See https://github.com/fsnotify/fsnotify/issues/74
|
// platforms. See https://github.com/fsnotify/fsnotify/issues/74
|
||||||
var trigger bool
|
var trigger bool
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
|
@ -56,7 +56,7 @@ func gqlHash(b string, vars []byte) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if vars == nil {
|
if vars == nil || len(vars) == 0 {
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,39 @@ func TestRelaxHash2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRelaxHash3(t *testing.T) {
|
||||||
|
var v1 = `users {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
picture: avatar
|
||||||
|
products(limit: 2, where: {price: {gt: 10}}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
var v2 = `
|
||||||
|
users {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
picture: avatar
|
||||||
|
products(limit: 2, where: {price: {gt: 10}}) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
h1 := gqlHash(v1, nil)
|
||||||
|
h2 := gqlHash(v2, nil)
|
||||||
|
|
||||||
|
if strings.Compare(h1, h2) != 0 {
|
||||||
|
t.Fatal("Hashes don't match they should")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRelaxHashWithVars1(t *testing.T) {
|
func TestRelaxHashWithVars1(t *testing.T) {
|
||||||
var q1 = `
|
var q1 = `
|
||||||
products(
|
products(
|
||||||
|
57
test.yml
57
test.yml
@ -1,57 +0,0 @@
|
|||||||
app_name: Test App
|
|
||||||
auth:
|
|
||||||
cookie: _app_session
|
|
||||||
header: X-User-ID
|
|
||||||
rails:
|
|
||||||
max_active: 12000
|
|
||||||
max_idle: 80
|
|
||||||
secret_key_base: 0a248500a64c01184edb4d7ad3a805488f8097ac761b76aaa6c17c01dcb7af03a2f18ba61b2868134b9c7b79a122bc0dadff4367414a2d173297bfea92be5566
|
|
||||||
version: 5.2
|
|
||||||
type: rails
|
|
||||||
auth_fail_block: never
|
|
||||||
database:
|
|
||||||
dbname: app_development
|
|
||||||
defaults:
|
|
||||||
blocklist:
|
|
||||||
- ar_internal_metadata
|
|
||||||
- schema_migrations
|
|
||||||
- secret
|
|
||||||
- password
|
|
||||||
- encrypted
|
|
||||||
- token
|
|
||||||
host: db
|
|
||||||
password: ""
|
|
||||||
port: 5432
|
|
||||||
schema: public
|
|
||||||
tables:
|
|
||||||
- name: users
|
|
||||||
- filter: none
|
|
||||||
name: customers
|
|
||||||
remotes:
|
|
||||||
- id: stripe_id
|
|
||||||
name: payments
|
|
||||||
pass_headers:
|
|
||||||
- cookie
|
|
||||||
path: data
|
|
||||||
set_headers:
|
|
||||||
- name: Host
|
|
||||||
value: 0.0.0.0
|
|
||||||
url: http://rails_app:3000/stripe/$id
|
|
||||||
- filter:
|
|
||||||
- '{ id: { eq: $user_id } }'
|
|
||||||
name: me
|
|
||||||
table: users
|
|
||||||
type: postgres
|
|
||||||
user: postgres
|
|
||||||
variables:
|
|
||||||
account_id: (select account_id from users where id = $user_id)
|
|
||||||
enable_tracing: true
|
|
||||||
env: development
|
|
||||||
host_port: 0.0.0.0:8080
|
|
||||||
log_level: debug
|
|
||||||
migrations_path: ./config/migrations
|
|
||||||
port: "8080"
|
|
||||||
reload_on_config_change: true
|
|
||||||
seed_file: seed.js
|
|
||||||
use_allow_list: false
|
|
||||||
web_ui: true
|
|
@ -10,7 +10,8 @@ CREATE TABLE public.users (
|
|||||||
|
|
||||||
---- create above / drop below ----
|
---- create above / drop below ----
|
||||||
|
|
||||||
-- Write your migrate down statements here. If this migration is irreversible
|
-- Write your down migrate statements here. If this migration is irreversible
|
||||||
-- Then delete the separator line above.
|
-- then delete the separator line above.
|
||||||
|
|
||||||
|
DROP TABLE public.users
|
||||||
|
|
||||||
DROP TABLE public.users
|
|
Reference in New Issue
Block a user