Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
2241364d00 | |||
f63e270c73 | |||
ccab367351 | |||
67ddc148a9 | |||
31afdac3af | |||
1344246287 | |||
7b25873438 | |||
d572b4f753 | |||
cd69b5a78f | |||
01ad9b71ba | |||
b64daaf034 | |||
c7837bf758 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -38,4 +38,5 @@ release
|
|||||||
.gofuzz
|
.gofuzz
|
||||||
*-fuzz.zip
|
*-fuzz.zip
|
||||||
*.test
|
*.test
|
||||||
|
.firebase
|
||||||
|
|
||||||
|
@ -52,7 +52,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
res, err := sg.GraphQL(context.Background(), query, nil)
|
ctx = context.WithValue(ctx, core.UserIDKey, 1)
|
||||||
|
|
||||||
|
res, err := sg.GraphQL(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -90,7 +92,8 @@ This compiler is what sits at the heart of Super Graph, with layers of useful fu
|
|||||||
- Fuzz tested for security
|
- Fuzz tested for security
|
||||||
- Database migrations tool
|
- Database migrations tool
|
||||||
- Database seeding tool
|
- Database seeding tool
|
||||||
- Works with Postgres and YugabyteDB
|
- Works with Postgres and Yugabyte DB
|
||||||
|
- OpenCensus Support: Zipkin, Prometheus, X-Ray, Stackdriver
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
@ -68,6 +68,18 @@ cors_debug: true
|
|||||||
# person: people
|
# person: people
|
||||||
# sheep: sheep
|
# sheep: sheep
|
||||||
|
|
||||||
|
# open opencensus tracing and metrics
|
||||||
|
# telemetry:
|
||||||
|
# debug: true
|
||||||
|
# metrics:
|
||||||
|
# exporter: "prometheus"
|
||||||
|
# tracing:
|
||||||
|
# exporter: "zipkin"
|
||||||
|
# endpoint: "http://zipkin:9411/api/v2/spans"
|
||||||
|
# sample: 0.2
|
||||||
|
# include_query: false
|
||||||
|
# include_params: false
|
||||||
|
|
||||||
auth:
|
auth:
|
||||||
# Can be 'rails' or 'jwt'
|
# Can be 'rails' or 'jwt'
|
||||||
type: rails
|
type: rails
|
||||||
|
@ -12,7 +12,7 @@ log_level: "info"
|
|||||||
# enable or disable http compression (uses gzip)
|
# enable or disable http compression (uses gzip)
|
||||||
http_compress: true
|
http_compress: true
|
||||||
|
|
||||||
# When production mode is 'true' only queries
|
# When production mode is 'true' only queries
|
||||||
# from the allow list are permitted.
|
# from the allow list are permitted.
|
||||||
# When it's 'false' all queries are saved to the
|
# When it's 'false' all queries are saved to the
|
||||||
# the allow list in ./config/allow.list
|
# the allow list in ./config/allow.list
|
||||||
@ -32,7 +32,7 @@ enable_tracing: true
|
|||||||
# Path pointing to where the migrations can be found
|
# Path pointing to where the migrations can be found
|
||||||
# migrations_path: ./migrations
|
# migrations_path: ./migrations
|
||||||
|
|
||||||
# Secret key for general encryption operations like
|
# Secret key for general encryption operations like
|
||||||
# encrypting the cursor data
|
# encrypting the cursor data
|
||||||
# secret_key: supercalifajalistics
|
# secret_key: supercalifajalistics
|
||||||
|
|
||||||
@ -57,11 +57,20 @@ database:
|
|||||||
password: postgres
|
password: postgres
|
||||||
#pool_size: 10
|
#pool_size: 10
|
||||||
#max_retries: 0
|
#max_retries: 0
|
||||||
#log_level: "debug"
|
#log_level: "debug"
|
||||||
|
|
||||||
# Set session variable "user.id" to the user id
|
# Set session variable "user.id" to the user id
|
||||||
# Enable this if you need the user id in triggers, etc
|
# Enable this if you need the user id in triggers, etc
|
||||||
set_user_id: false
|
set_user_id: false
|
||||||
|
|
||||||
# database ping timeout is used for db health checking
|
# database ping timeout is used for db health checking
|
||||||
ping_timeout: 5m
|
ping_timeout: 5m
|
||||||
|
# open opencensus tracing and metrics
|
||||||
|
# telemetry:
|
||||||
|
# debug: false
|
||||||
|
# metrics:
|
||||||
|
# exporter: "prometheus"
|
||||||
|
# tracing:
|
||||||
|
# exporter: "zipkin"
|
||||||
|
# endpoint: "http://zipkin:9411/api/v2/spans"
|
||||||
|
# sample: 0.6
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
res, err := sg.GraphQL(context.Background(), query, nil)
|
ctx = context.WithValue(ctx, core.UserIDKey, 1)
|
||||||
|
|
||||||
|
res, err := sg.GraphQL(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ func BenchmarkGraphQL(b *testing.B) {
|
|||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// mock.ExpectQuery(`^SELECT jsonb_build_object`).WithArgs()
|
// mock.ExpectQuery(`^SELECT jsonb_build_object`).WithArgs()
|
||||||
c := &Config{DefaultBlock: true}
|
c := &Config{}
|
||||||
sg, err := newSuperGraph(c, db, psql.GetTestDBInfo())
|
sg, err := newSuperGraph(c, db, psql.GetTestDBInfo())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
|
129
core/args.go
129
core/args.go
@ -1,72 +1,18 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
|
"github.com/dosco/super-graph/core/internal/psql"
|
||||||
"github.com/dosco/super-graph/jsn"
|
"github.com/dosco/super-graph/jsn"
|
||||||
)
|
)
|
||||||
|
|
||||||
// argMap function is used to string replace variables with values by
|
|
||||||
// the fasttemplate code
|
|
||||||
func (c *scontext) argMap() func(w io.Writer, tag string) (int, error) {
|
|
||||||
return func(w io.Writer, tag string) (int, error) {
|
|
||||||
switch tag {
|
|
||||||
case "user_id_provider":
|
|
||||||
if v := c.Value(UserIDProviderKey); v != nil {
|
|
||||||
return io.WriteString(w, v.(string))
|
|
||||||
}
|
|
||||||
return 0, argErr("user_id_provider")
|
|
||||||
|
|
||||||
case "user_id":
|
|
||||||
if v := c.Value(UserIDKey); v != nil {
|
|
||||||
return io.WriteString(w, v.(string))
|
|
||||||
}
|
|
||||||
return 0, argErr("user_id")
|
|
||||||
|
|
||||||
case "user_role":
|
|
||||||
if v := c.Value(UserRoleKey); v != nil {
|
|
||||||
return io.WriteString(w, v.(string))
|
|
||||||
}
|
|
||||||
return 0, argErr("user_role")
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := jsn.Get(c.vars, [][]byte{[]byte(tag)})
|
|
||||||
|
|
||||||
if len(fields) == 0 {
|
|
||||||
return 0, argErr(tag)
|
|
||||||
|
|
||||||
}
|
|
||||||
v := fields[0].Value
|
|
||||||
|
|
||||||
// Open and close quotes
|
|
||||||
if len(v) >= 2 && v[0] == '"' && v[len(v)-1] == '"' {
|
|
||||||
fields[0].Value = v[1 : len(v)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
if tag == "cursor" {
|
|
||||||
if bytes.EqualFold(v, []byte("null")) {
|
|
||||||
return io.WriteString(w, ``)
|
|
||||||
}
|
|
||||||
v1, err := c.sg.decrypt(string(fields[0].Value))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Write(v1)
|
|
||||||
}
|
|
||||||
|
|
||||||
return w.Write(escSQuote(fields[0].Value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// argList function is used to create a list of arguments to pass
|
// argList function is used to create a list of arguments to pass
|
||||||
// to a prepared statement. FYI no escaping of single quotes is
|
// to a prepared statement.
|
||||||
// needed here
|
|
||||||
func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
func (c *scontext) argList(md psql.Metadata) ([]interface{}, error) {
|
||||||
vars := make([]interface{}, len(args))
|
vars := make([]interface{}, len(md.Params))
|
||||||
|
|
||||||
var fields map[string]json.RawMessage
|
var fields map[string]json.RawMessage
|
||||||
var err error
|
var err error
|
||||||
@ -79,31 +25,30 @@ func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range args {
|
for i, p := range md.Params {
|
||||||
av := args[i]
|
switch p.Name {
|
||||||
switch {
|
case "user_id":
|
||||||
case bytes.Equal(av, []byte("user_id")):
|
|
||||||
if v := c.Value(UserIDKey); v != nil {
|
if v := c.Value(UserIDKey); v != nil {
|
||||||
vars[i] = v.(string)
|
vars[i] = v.(string)
|
||||||
} else {
|
} else {
|
||||||
return nil, argErr("user_id")
|
return nil, argErr(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case bytes.Equal(av, []byte("user_id_provider")):
|
case "user_id_provider":
|
||||||
if v := c.Value(UserIDProviderKey); v != nil {
|
if v := c.Value(UserIDProviderKey); v != nil {
|
||||||
vars[i] = v.(string)
|
vars[i] = v.(string)
|
||||||
} else {
|
} else {
|
||||||
return nil, argErr("user_id_provider")
|
return nil, argErr(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case bytes.Equal(av, []byte("user_role")):
|
case "user_role":
|
||||||
if v := c.Value(UserRoleKey); v != nil {
|
if v := c.Value(UserRoleKey); v != nil {
|
||||||
vars[i] = v.(string)
|
vars[i] = v.(string)
|
||||||
} else {
|
} else {
|
||||||
return nil, argErr("user_role")
|
return nil, argErr(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
case bytes.Equal(av, []byte("cursor")):
|
case "cursor":
|
||||||
if v, ok := fields["cursor"]; ok && v[0] == '"' {
|
if v, ok := fields["cursor"]; ok && v[0] == '"' {
|
||||||
v1, err := c.sg.decrypt(string(v[1 : len(v)-1]))
|
v1, err := c.sg.decrypt(string(v[1 : len(v)-1]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -111,25 +56,33 @@ func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
|||||||
}
|
}
|
||||||
vars[i] = v1
|
vars[i] = v1
|
||||||
} else {
|
} else {
|
||||||
return nil, argErr("cursor")
|
return nil, argErr(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if v, ok := fields[string(av)]; ok {
|
if v, ok := fields[p.Name]; ok {
|
||||||
|
switch {
|
||||||
|
case p.IsArray && v[0] != '[':
|
||||||
|
return nil, fmt.Errorf("variable '%s' should be an array of type '%s'", p.Name, p.Type)
|
||||||
|
|
||||||
|
case p.Type == "json" && v[0] != '[' && v[0] != '{':
|
||||||
|
return nil, fmt.Errorf("variable '%s' should be an array or object", p.Name)
|
||||||
|
}
|
||||||
|
|
||||||
switch v[0] {
|
switch v[0] {
|
||||||
case '[', '{':
|
case '[', '{':
|
||||||
vars[i] = v
|
vars[i] = v
|
||||||
|
|
||||||
default:
|
default:
|
||||||
var val interface{}
|
var val interface{}
|
||||||
if err := json.Unmarshal(v, &val); err != nil {
|
if err := json.Unmarshal(v, &val); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vars[i] = val
|
vars[i] = val
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return nil, argErr(string(av))
|
return nil, argErr(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,32 +90,6 @@ func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
|||||||
return vars, nil
|
return vars, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
func argErr(p psql.Param) error {
|
||||||
func escSQuote(b []byte) []byte {
|
return fmt.Errorf("required variable '%s' of type '%s' must be set", p.Name, p.Type)
|
||||||
var buf *bytes.Buffer
|
|
||||||
s := 0
|
|
||||||
for i := range b {
|
|
||||||
if b[i] == '\'' {
|
|
||||||
if buf == nil {
|
|
||||||
buf = &bytes.Buffer{}
|
|
||||||
}
|
|
||||||
buf.Write(b[s:i])
|
|
||||||
buf.WriteString(`''`)
|
|
||||||
s = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if buf == nil {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
l := len(b)
|
|
||||||
if s < (l - 1) {
|
|
||||||
buf.Write(b[s:l])
|
|
||||||
}
|
|
||||||
return buf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func argErr(name string) error {
|
|
||||||
return fmt.Errorf("query requires variable '%s' to be set", name)
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestEscQuote(t *testing.T) {
|
|
||||||
val := "That's the worst, don''t be calling me's again"
|
|
||||||
exp := "That''s the worst, don''''t be calling me''s again"
|
|
||||||
ret := escSQuote([]byte(val))
|
|
||||||
|
|
||||||
if exp != string(ret) {
|
|
||||||
t.Errorf("escSQuote failed: %s", string(ret))
|
|
||||||
}
|
|
||||||
}
|
|
@ -12,10 +12,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type stmt struct {
|
type stmt struct {
|
||||||
role *Role
|
role *Role
|
||||||
qc *qcode.QCode
|
qc *qcode.QCode
|
||||||
skipped uint32
|
md psql.Metadata
|
||||||
sql string
|
sql string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sg *SuperGraph) buildStmt(qt qcode.QType, query, vars []byte, role string) ([]stmt, error) {
|
func (sg *SuperGraph) buildStmt(qt qcode.QType, query, vars []byte, role string) ([]stmt, error) {
|
||||||
@ -62,12 +62,11 @@ func (sg *SuperGraph) buildRoleStmt(query, vars []byte, role string) ([]stmt, er
|
|||||||
stmts := []stmt{stmt{role: ro, qc: qc}}
|
stmts := []stmt{stmt{role: ro, qc: qc}}
|
||||||
w := &bytes.Buffer{}
|
w := &bytes.Buffer{}
|
||||||
|
|
||||||
skipped, err := sg.pc.Compile(qc, w, psql.Variables(vm))
|
stmts[0].md, err = sg.pc.Compile(w, qc, psql.Variables(vm))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
stmts[0].skipped = skipped
|
|
||||||
stmts[0].sql = w.String()
|
stmts[0].sql = w.String()
|
||||||
|
|
||||||
return stmts, nil
|
return stmts, nil
|
||||||
@ -104,14 +103,13 @@ func (sg *SuperGraph) buildMultiStmt(query, vars []byte) ([]stmt, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stmts = append(stmts, stmt{role: role, qc: qc})
|
stmts = append(stmts, stmt{role: role, qc: qc})
|
||||||
|
s := &stmts[len(stmts)-1]
|
||||||
|
|
||||||
skipped, err := sg.pc.Compile(qc, w, psql.Variables(vm))
|
s.md, err = sg.pc.Compile(w, qc, psql.Variables(vm))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s := &stmts[len(stmts)-1]
|
|
||||||
s.skipped = skipped
|
|
||||||
s.sql = w.String()
|
s.sql = w.String()
|
||||||
w.Reset()
|
w.Reset()
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,12 @@ type Config struct {
|
|||||||
// or other database functions
|
// or other database functions
|
||||||
SetUserID bool `mapstructure:"set_user_id"`
|
SetUserID bool `mapstructure:"set_user_id"`
|
||||||
|
|
||||||
// DefaultBlock ensures only tables configured under the `anon` role
|
// DefaultAllow reverses the blocked by default behaviour for queries in
|
||||||
// config can be queries if the `anon` role. For example if the table
|
// anonymous mode. (anon role)
|
||||||
// `users` is not listed under the anon role then it will be filtered
|
// For example if the table `users` is not listed under the anon role then
|
||||||
// out of any unauthenticated queries that mention it.
|
// access to it would by default for unauthenticated queries this reverses
|
||||||
DefaultBlock bool `mapstructure:"default_block"`
|
// this behavior (!!! Use with caution !!!!)
|
||||||
|
DefaultAllow bool `mapstructure:"default_allow"`
|
||||||
|
|
||||||
// Vars is a map of hardcoded variables that can be leveraged in your
|
// Vars is a map of hardcoded variables that can be leveraged in your
|
||||||
// queries (eg variable admin_id will be $admin_id in the query)
|
// queries (eg variable admin_id will be $admin_id in the query)
|
||||||
|
@ -5,11 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
openVar = "{{"
|
|
||||||
closeVar = "}}"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errNotFound = errors.New("not found in prepared statements")
|
errNotFound = errors.New("not found in prepared statements")
|
||||||
)
|
)
|
||||||
|
34
core/core.go
34
core/core.go
@ -1,7 +1,6 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -10,8 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/dosco/super-graph/core/internal/psql"
|
"github.com/dosco/super-graph/core/internal/psql"
|
||||||
"github.com/dosco/super-graph/core/internal/qcode"
|
"github.com/dosco/super-graph/core/internal/qcode"
|
||||||
|
|
||||||
"github.com/valyala/fasttemplate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type OpType int
|
type OpType int
|
||||||
@ -93,8 +90,7 @@ func (sg *SuperGraph) initCompilers() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sg.qc, err = qcode.NewCompiler(qcode.Config{
|
sg.qc, err = qcode.NewCompiler(qcode.Config{
|
||||||
DefaultBlock: sg.conf.DefaultBlock,
|
Blocklist: sg.conf.Blocklist,
|
||||||
Blocklist: sg.conf.Blocklist,
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -127,7 +123,7 @@ func (c *scontext) execQuery() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(data) == 0 || st.skipped == 0 {
|
if len(data) == 0 || st.md.Skipped == 0 {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +178,7 @@ func (c *scontext) resolvePreparedSQL() ([]byte, *stmt, error) {
|
|||||||
var root []byte
|
var root []byte
|
||||||
var row *sql.Row
|
var row *sql.Row
|
||||||
|
|
||||||
varsList, err := c.argList(ps.args)
|
varsList, err := c.argList(ps.st.md)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -253,15 +249,23 @@ func (c *scontext) resolveSQL() ([]byte, *stmt, error) {
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
st := &stmts[0]
|
st := &stmts[0]
|
||||||
|
c.res.sql = st.sql
|
||||||
|
|
||||||
t := fasttemplate.New(st.sql, openVar, closeVar)
|
varList, err := c.argList(st.md)
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
|
|
||||||
_, err = t.ExecuteFunc(buf, c.argMap())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
finalSQL := buf.String()
|
// finalSQL := buf.String()
|
||||||
|
|
||||||
|
////
|
||||||
|
|
||||||
|
// _, err = t.ExecuteFunc(buf, c.argMap(st.md))
|
||||||
|
// if err != nil {
|
||||||
|
// return nil, nil, err
|
||||||
|
// }
|
||||||
|
// finalSQL := buf.String()
|
||||||
|
|
||||||
|
/////
|
||||||
|
|
||||||
// var stime time.Time
|
// var stime time.Time
|
||||||
|
|
||||||
@ -276,9 +280,9 @@ func (c *scontext) resolveSQL() ([]byte, *stmt, error) {
|
|||||||
// defaultRole := c.role
|
// defaultRole := c.role
|
||||||
|
|
||||||
if useTx {
|
if useTx {
|
||||||
row = tx.QueryRow(finalSQL)
|
row = tx.QueryRowContext(c, st.sql, varList...)
|
||||||
} else {
|
} else {
|
||||||
row = c.sg.db.QueryRow(finalSQL)
|
row = c.sg.db.QueryRowContext(c, st.sql, varList...)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(stmts) > 1 {
|
if len(stmts) > 1 {
|
||||||
@ -287,8 +291,6 @@ func (c *scontext) resolveSQL() ([]byte, *stmt, error) {
|
|||||||
err = row.Scan(&root)
|
err = row.Scan(&root)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.res.sql = finalSQL
|
|
||||||
|
|
||||||
if len(role) == 0 {
|
if len(role) == 0 {
|
||||||
c.res.role = c.role
|
c.res.role = c.role
|
||||||
} else {
|
} else {
|
||||||
|
89
core/init.go
89
core/init.go
@ -2,9 +2,7 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/dosco/super-graph/core/internal/psql"
|
"github.com/dosco/super-graph/core/internal/psql"
|
||||||
"github.com/dosco/super-graph/core/internal/qcode"
|
"github.com/dosco/super-graph/core/internal/qcode"
|
||||||
@ -18,11 +16,6 @@ func (sg *SuperGraph) initConfig() error {
|
|||||||
flect.AddPlural(k, v)
|
flect.AddPlural(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variables: Validate and sanitize
|
|
||||||
for k, v := range c.Vars {
|
|
||||||
c.Vars[k] = sanitizeVars(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tables: Validate and sanitize
|
// Tables: Validate and sanitize
|
||||||
tm := make(map[string]struct{})
|
tm := make(map[string]struct{})
|
||||||
|
|
||||||
@ -70,8 +63,8 @@ func (sg *SuperGraph) initConfig() error {
|
|||||||
sg.roles["user"] = &ur
|
sg.roles["user"] = &ur
|
||||||
}
|
}
|
||||||
|
|
||||||
// If anon role is not defined and DefaultBlock is not then then create it
|
// If anon role is not defined then create it
|
||||||
if _, ok := sg.roles["anon"]; !ok && !c.DefaultBlock {
|
if _, ok := sg.roles["anon"]; !ok {
|
||||||
ur := Role{
|
ur := Role{
|
||||||
Name: "anon",
|
Name: "anon",
|
||||||
tm: make(map[string]*RoleTable),
|
tm: make(map[string]*RoleTable),
|
||||||
@ -80,17 +73,14 @@ func (sg *SuperGraph) initConfig() error {
|
|||||||
sg.roles["anon"] = &ur
|
sg.roles["anon"] = &ur
|
||||||
}
|
}
|
||||||
|
|
||||||
// Roles: validate and sanitize
|
if c.RolesQuery == "" {
|
||||||
c.RolesQuery = sanitizeVars(c.RolesQuery)
|
|
||||||
|
|
||||||
if len(c.RolesQuery) == 0 {
|
|
||||||
sg.log.Printf("WRN roles_query not defined: attribute based access control disabled")
|
sg.log.Printf("WRN roles_query not defined: attribute based access control disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, userExists := sg.roles["user"]
|
_, userExists := sg.roles["user"]
|
||||||
_, sg.anonExists = sg.roles["anon"]
|
_, sg.anonExists = sg.roles["anon"]
|
||||||
|
|
||||||
sg.abacEnabled = userExists && len(c.RolesQuery) != 0
|
sg.abacEnabled = userExists && c.RolesQuery != ""
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -112,7 +102,7 @@ func getDBTableAliases(c *Config) map[string][]string {
|
|||||||
|
|
||||||
func addTables(c *Config, di *psql.DBInfo) error {
|
func addTables(c *Config, di *psql.DBInfo) error {
|
||||||
for _, t := range c.Tables {
|
for _, t := range c.Tables {
|
||||||
if len(t.Table) == 0 || len(t.Columns) == 0 {
|
if t.Table == "" || len(t.Columns) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := addTable(di, t.Columns, t); err != nil {
|
if err := addTable(di, t.Columns, t); err != nil {
|
||||||
@ -163,7 +153,7 @@ func addTable(di *psql.DBInfo, cols []Column, t Table) error {
|
|||||||
func addForeignKeys(c *Config, di *psql.DBInfo) error {
|
func addForeignKeys(c *Config, di *psql.DBInfo) error {
|
||||||
for _, t := range c.Tables {
|
for _, t := range c.Tables {
|
||||||
for _, c := range t.Columns {
|
for _, c := range t.Columns {
|
||||||
if len(c.ForeignKey) == 0 {
|
if c.ForeignKey == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := addForeignKey(di, c, t); err != nil {
|
if err := addForeignKey(di, c, t); err != nil {
|
||||||
@ -206,7 +196,7 @@ func addForeignKey(di *psql.DBInfo, c Column, t Table) error {
|
|||||||
func addRoles(c *Config, qc *qcode.Compiler) error {
|
func addRoles(c *Config, qc *qcode.Compiler) error {
|
||||||
for _, r := range c.Roles {
|
for _, r := range c.Roles {
|
||||||
for _, t := range r.Tables {
|
for _, t := range r.Tables {
|
||||||
if err := addRole(qc, r, t); err != nil {
|
if err := addRole(qc, r, t, c.DefaultAllow); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,28 +205,28 @@ func addRoles(c *Config, qc *qcode.Compiler) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addRole(qc *qcode.Compiler, r Role, t RoleTable) error {
|
func addRole(qc *qcode.Compiler, r Role, t RoleTable, defaultAllow bool) error {
|
||||||
blocked := struct {
|
ro := true // read-only
|
||||||
readOnly bool
|
|
||||||
query bool
|
|
||||||
insert bool
|
|
||||||
update bool
|
|
||||||
delete bool
|
|
||||||
}{true, true, true, true, true}
|
|
||||||
|
|
||||||
if r.Name == "anon" {
|
if defaultAllow {
|
||||||
blocked.query = false
|
ro = false
|
||||||
} else {
|
}
|
||||||
blocked.readOnly = false
|
|
||||||
blocked.query = false
|
if r.Name != "anon" {
|
||||||
blocked.insert = false
|
ro = false
|
||||||
blocked.update = false
|
|
||||||
blocked.delete = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.ReadOnly != nil {
|
if t.ReadOnly != nil {
|
||||||
blocked.readOnly = *t.ReadOnly
|
ro = *t.ReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blocked := struct {
|
||||||
|
query bool
|
||||||
|
insert bool
|
||||||
|
update bool
|
||||||
|
delete bool
|
||||||
|
}{false, ro, ro, ro}
|
||||||
|
|
||||||
if t.Query.Block != nil {
|
if t.Query.Block != nil {
|
||||||
blocked.query = *t.Query.Block
|
blocked.query = *t.Query.Block
|
||||||
}
|
}
|
||||||
@ -272,18 +262,17 @@ func addRole(qc *qcode.Compiler, r Role, t RoleTable) error {
|
|||||||
Block: blocked.update,
|
Block: blocked.update,
|
||||||
}
|
}
|
||||||
|
|
||||||
delete := qcode.DeleteConfig{
|
del := qcode.DeleteConfig{
|
||||||
Filters: t.Delete.Filters,
|
Filters: t.Delete.Filters,
|
||||||
Columns: t.Delete.Columns,
|
Columns: t.Delete.Columns,
|
||||||
Block: blocked.delete,
|
Block: blocked.delete,
|
||||||
}
|
}
|
||||||
|
|
||||||
return qc.AddRole(r.Name, t.Name, qcode.TRConfig{
|
return qc.AddRole(r.Name, t.Name, qcode.TRConfig{
|
||||||
ReadOnly: blocked.readOnly,
|
Query: query,
|
||||||
Query: query,
|
Insert: insert,
|
||||||
Insert: insert,
|
Update: update,
|
||||||
Update: update,
|
Delete: del,
|
||||||
Delete: delete,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,23 +283,3 @@ func (r *Role) GetTable(name string) *RoleTable {
|
|||||||
func sanitize(value string) string {
|
func sanitize(value string) string {
|
||||||
return strings.ToLower(strings.TrimSpace(value))
|
return strings.ToLower(strings.TrimSpace(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
varRe1 = regexp.MustCompile(`(?mi)\$([a-zA-Z0-9_.]+)`)
|
|
||||||
varRe2 = regexp.MustCompile(`\{\{([a-zA-Z0-9_.]+)\}\}`)
|
|
||||||
)
|
|
||||||
|
|
||||||
func sanitizeVars(s string) string {
|
|
||||||
s0 := varRe1.ReplaceAllString(s, `{{$1}}`)
|
|
||||||
|
|
||||||
s1 := strings.Map(func(r rune) rune {
|
|
||||||
if unicode.IsSpace(r) {
|
|
||||||
return ' '
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}, s0)
|
|
||||||
|
|
||||||
return varRe2.ReplaceAllStringFunc(s1, func(m string) string {
|
|
||||||
return strings.ToLower(m)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -40,7 +40,7 @@ type Config struct {
|
|||||||
func New(filename string, conf Config) (*List, error) {
|
func New(filename string, conf Config) (*List, error) {
|
||||||
al := List{}
|
al := List{}
|
||||||
|
|
||||||
if len(filename) != 0 {
|
if filename != "" {
|
||||||
fp := filename
|
fp := filename
|
||||||
|
|
||||||
if _, err := os.Stat(fp); err == nil {
|
if _, err := os.Stat(fp); err == nil {
|
||||||
@ -50,7 +50,7 @@ func New(filename string, conf Config) (*List, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(al.filepath) == 0 {
|
if al.filepath == "" {
|
||||||
fp := "./allow.list"
|
fp := "./allow.list"
|
||||||
|
|
||||||
if _, err := os.Stat(fp); err == nil {
|
if _, err := os.Stat(fp); err == nil {
|
||||||
@ -60,7 +60,7 @@ func New(filename string, conf Config) (*List, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(al.filepath) == 0 {
|
if al.filepath == "" {
|
||||||
fp := "./config/allow.list"
|
fp := "./config/allow.list"
|
||||||
|
|
||||||
if _, err := os.Stat(fp); err == nil {
|
if _, err := os.Stat(fp); err == nil {
|
||||||
@ -70,12 +70,12 @@ func New(filename string, conf Config) (*List, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(al.filepath) == 0 {
|
if al.filepath == "" {
|
||||||
if !conf.CreateIfNotExists {
|
if !conf.CreateIfNotExists {
|
||||||
return nil, errors.New("allow.list not found")
|
return nil, errors.New("allow.list not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(filename) == 0 {
|
if filename == "" {
|
||||||
al.filepath = "./config/allow.list"
|
al.filepath = "./config/allow.list"
|
||||||
} else {
|
} else {
|
||||||
al.filepath = filename
|
al.filepath = filename
|
||||||
@ -112,7 +112,7 @@ func (al *List) Set(vars []byte, query, comment string) error {
|
|||||||
return errors.New("allow.list is read-only")
|
return errors.New("allow.list is read-only")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(query) == 0 {
|
if query == "" {
|
||||||
return errors.New("empty query")
|
return errors.New("empty query")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,8 +239,6 @@ func (al *List) save(item Item) error {
|
|||||||
qd := &schema.QueryDocument{}
|
qd := &schema.QueryDocument{}
|
||||||
|
|
||||||
if err := qd.Parse(item.Query); err != nil {
|
if err := qd.Parse(item.Query); err != nil {
|
||||||
fmt.Println("##", item.Query)
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,12 +246,10 @@ func (al *List) save(item Item) error {
|
|||||||
query := buf.String()
|
query := buf.String()
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
|
|
||||||
// fmt.Println(">", query)
|
|
||||||
|
|
||||||
item.Name = QueryName(query)
|
item.Name = QueryName(query)
|
||||||
item.key = strings.ToLower(item.Name)
|
item.key = strings.ToLower(item.Name)
|
||||||
|
|
||||||
if len(item.Name) == 0 {
|
if item.Name == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +268,7 @@ func (al *List) save(item Item) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if index != -1 {
|
if index != -1 {
|
||||||
if len(list[index].Comment) != 0 {
|
if list[index].Comment != "" {
|
||||||
item.Comment = list[index].Comment
|
item.Comment = list[index].Comment
|
||||||
}
|
}
|
||||||
list[index] = item
|
list[index] = item
|
||||||
@ -296,7 +292,7 @@ func (al *List) save(item Item) error {
|
|||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for _, c := range cmtLines {
|
for _, c := range cmtLines {
|
||||||
if c = strings.TrimSpace(c); len(c) == 0 {
|
if c = strings.TrimSpace(c); c == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestCockroachDB(t *testing.T) {
|
func TestCockroachDB(t *testing.T) {
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "temp-cockraochdb-")
|
dir, err := ioutil.TempDir("", "temp-cockraochdb-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -33,6 +32,7 @@ func TestCockroachDB(t *testing.T) {
|
|||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Skip("is CockroachDB installed?: " + err.Error())
|
t.Skip("is CockroachDB installed?: " + err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
fmt.Println("started temporary cockroach db")
|
fmt.Println("started temporary cockroach db")
|
||||||
|
|
||||||
|
@ -50,18 +50,20 @@ func DropSchema(t *testing.T, db *sql.DB) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSuperGraph(t *testing.T, db *sql.DB, before func(t *testing.T)) {
|
func TestSuperGraph(t *testing.T, db *sql.DB, before func(t *testing.T)) {
|
||||||
config := core.Config{DefaultBlock: true}
|
config := core.Config{}
|
||||||
config.UseAllowList = false
|
config.UseAllowList = false
|
||||||
config.AllowListFile = "./allow.list"
|
config.AllowListFile = "./allow.list"
|
||||||
config.RolesQuery = `SELECT * FROM users WHERE id = $user_id`
|
config.RolesQuery = `SELECT * FROM users WHERE id = $user_id`
|
||||||
|
|
||||||
|
blockFalse := false
|
||||||
|
|
||||||
config.Roles = []core.Role{
|
config.Roles = []core.Role{
|
||||||
core.Role{
|
core.Role{
|
||||||
Name: "anon",
|
Name: "anon",
|
||||||
Tables: []core.RoleTable{
|
Tables: []core.RoleTable{
|
||||||
core.RoleTable{Name: "users", Query: core.Query{Limit: 100}},
|
core.RoleTable{Name: "users", ReadOnly: &blockFalse, Query: core.Query{Limit: 100}},
|
||||||
core.RoleTable{Name: "product", Query: core.Query{Limit: 100}},
|
core.RoleTable{Name: "product", ReadOnly: &blockFalse, Query: core.Query{Limit: 100}},
|
||||||
core.RoleTable{Name: "line_item", Query: core.Query{Limit: 100}},
|
core.RoleTable{Name: "line_item", ReadOnly: &blockFalse, Query: core.Query{Limit: 100}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ func TestCockroachDB(t *testing.T) {
|
|||||||
url, found := os.LookupEnv("SG_POSTGRESQL_TEST_URL")
|
url, found := os.LookupEnv("SG_POSTGRESQL_TEST_URL")
|
||||||
if !found {
|
if !found {
|
||||||
t.Skip("set the SG_POSTGRESQL_TEST_URL env variable if you want to run integration tests against a PostgreSQL database")
|
t.Skip("set the SG_POSTGRESQL_TEST_URL env variable if you want to run integration tests against a PostgreSQL database")
|
||||||
|
} else {
|
||||||
|
db, err := sql.Open("pgx", url)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
integration_tests.DropSchema(t, db)
|
||||||
|
integration_tests.SetupSchema(t, db)
|
||||||
|
integration_tests.TestSuperGraph(t, db, func(t *testing.T) {
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := sql.Open("pgx", url)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
integration_tests.DropSchema(t, db)
|
|
||||||
integration_tests.SetupSchema(t, db)
|
|
||||||
integration_tests.TestSuperGraph(t, db, func(t *testing.T) {
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,7 @@ import (
|
|||||||
func (c *compilerContext) renderBaseColumns(
|
func (c *compilerContext) renderBaseColumns(
|
||||||
sel *qcode.Select,
|
sel *qcode.Select,
|
||||||
ti *DBTableInfo,
|
ti *DBTableInfo,
|
||||||
childCols []*qcode.Column,
|
childCols []*qcode.Column) ([]int, bool, error) {
|
||||||
skipped uint32) ([]int, bool, error) {
|
|
||||||
|
|
||||||
var realColsRendered []int
|
var realColsRendered []int
|
||||||
|
|
||||||
@ -116,12 +115,12 @@ func (c *compilerContext) renderColumnSearchRank(sel *qcode.Select, ti *DBTableI
|
|||||||
io.WriteString(c.w, `ts_rank(`)
|
io.WriteString(c.w, `ts_rank(`)
|
||||||
colWithTable(c.w, ti.Name, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
if c.schema.ver >= 110000 {
|
if c.schema.ver >= 110000 {
|
||||||
io.WriteString(c.w, `, websearch_to_tsquery('{{`)
|
io.WriteString(c.w, `, websearch_to_tsquery(`)
|
||||||
} else {
|
} else {
|
||||||
io.WriteString(c.w, `, to_tsquery('{{`)
|
io.WriteString(c.w, `, to_tsquery(`)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, arg.Val)
|
c.renderValueExp(Param{Name: arg.Val, Type: "string"})
|
||||||
io.WriteString(c.w, `}}'))`)
|
io.WriteString(c.w, `))`)
|
||||||
alias(c.w, col.Name)
|
alias(c.w, col.Name)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -141,12 +140,12 @@ func (c *compilerContext) renderColumnSearchHeadline(sel *qcode.Select, ti *DBTa
|
|||||||
io.WriteString(c.w, `ts_headline(`)
|
io.WriteString(c.w, `ts_headline(`)
|
||||||
colWithTable(c.w, ti.Name, cn)
|
colWithTable(c.w, ti.Name, cn)
|
||||||
if c.schema.ver >= 110000 {
|
if c.schema.ver >= 110000 {
|
||||||
io.WriteString(c.w, `, websearch_to_tsquery('{{`)
|
io.WriteString(c.w, `, websearch_to_tsquery(`)
|
||||||
} else {
|
} else {
|
||||||
io.WriteString(c.w, `, to_tsquery('{{`)
|
io.WriteString(c.w, `, to_tsquery(`)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, arg.Val)
|
c.renderValueExp(Param{Name: arg.Val, Type: "string"})
|
||||||
io.WriteString(c.w, `}}'))`)
|
io.WriteString(c.w, `))`)
|
||||||
alias(c.w, col.Name)
|
alias(c.w, col.Name)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -4,6 +4,7 @@ package psql
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/dosco/super-graph/core/internal/qcode"
|
"github.com/dosco/super-graph/core/internal/qcode"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -12,9 +13,9 @@ var (
|
|||||||
|
|
||||||
schema = GetTestSchema()
|
schema = GetTestSchema()
|
||||||
|
|
||||||
vars = NewVariables(map[string]string{
|
vars = map[string]string{
|
||||||
"admin_account_id": "5",
|
"admin_account_id": "5",
|
||||||
})
|
}
|
||||||
|
|
||||||
pcompileTest = NewCompiler(Config{
|
pcompileTest = NewCompiler(Config{
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/dosco/super-graph/core/internal/util"
|
"github.com/dosco/super-graph/core/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *compilerContext) renderInsert(qc *qcode.QCode, w io.Writer,
|
func (c *compilerContext) renderInsert(
|
||||||
vars Variables, ti *DBTableInfo) (uint32, error) {
|
w io.Writer, qc *qcode.QCode, vars Variables, ti *DBTableInfo) (uint32, error) {
|
||||||
|
|
||||||
insert, ok := vars[qc.ActionVar]
|
insert, ok := vars[qc.ActionVar]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -25,9 +25,8 @@ func (c *compilerContext) renderInsert(qc *qcode.QCode, w io.Writer,
|
|||||||
if insert[0] == '[' {
|
if insert[0] == '[' {
|
||||||
io.WriteString(c.w, `json_array_elements(`)
|
io.WriteString(c.w, `json_array_elements(`)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, `'{{`)
|
c.renderValueExp(Param{Name: qc.ActionVar, Type: "json"})
|
||||||
io.WriteString(c.w, qc.ActionVar)
|
io.WriteString(c.w, ` :: json`)
|
||||||
io.WriteString(c.w, `}}' :: json`)
|
|
||||||
if insert[0] == '[' {
|
if insert[0] == '[' {
|
||||||
io.WriteString(c.w, `)`)
|
io.WriteString(c.w, `)`)
|
||||||
}
|
}
|
||||||
@ -90,12 +89,12 @@ func (c *compilerContext) renderInsertStmt(qc *qcode.QCode, w io.Writer, item re
|
|||||||
io.WriteString(w, `INSERT INTO `)
|
io.WriteString(w, `INSERT INTO `)
|
||||||
quoted(w, ti.Name)
|
quoted(w, ti.Name)
|
||||||
io.WriteString(w, ` (`)
|
io.WriteString(w, ` (`)
|
||||||
renderInsertUpdateColumns(w, qc, jt, ti, sk, false)
|
c.renderInsertUpdateColumns(qc, jt, ti, sk, false)
|
||||||
renderNestedInsertRelColumns(w, item.kvitem, false)
|
renderNestedInsertRelColumns(w, item.kvitem, false)
|
||||||
io.WriteString(w, `)`)
|
io.WriteString(w, `)`)
|
||||||
|
|
||||||
io.WriteString(w, ` SELECT `)
|
io.WriteString(w, ` SELECT `)
|
||||||
renderInsertUpdateColumns(w, qc, jt, ti, sk, true)
|
c.renderInsertUpdateColumns(qc, jt, ti, sk, true)
|
||||||
renderNestedInsertRelColumns(w, item.kvitem, true)
|
renderNestedInsertRelColumns(w, item.kvitem, true)
|
||||||
|
|
||||||
io.WriteString(w, ` FROM "_sg_input" i`)
|
io.WriteString(w, ` FROM "_sg_input" i`)
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/dosco/super-graph/core/internal/qcode"
|
"github.com/dosco/super-graph/core/internal/qcode"
|
||||||
"github.com/dosco/super-graph/core/internal/util"
|
"github.com/dosco/super-graph/core/internal/util"
|
||||||
@ -33,42 +34,44 @@ var updateTypes = map[string]itemType{
|
|||||||
|
|
||||||
var noLimit = qcode.Paging{NoLimit: true}
|
var noLimit = qcode.Paging{NoLimit: true}
|
||||||
|
|
||||||
func (co *Compiler) compileMutation(qc *qcode.QCode, w io.Writer, vars Variables) (uint32, error) {
|
func (co *Compiler) compileMutation(w io.Writer, qc *qcode.QCode, vars Variables) (Metadata, error) {
|
||||||
|
md := Metadata{}
|
||||||
|
|
||||||
if len(qc.Selects) == 0 {
|
if len(qc.Selects) == 0 {
|
||||||
return 0, errors.New("empty query")
|
return md, errors.New("empty query")
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &compilerContext{w, qc.Selects, co}
|
c := &compilerContext{md, w, qc.Selects, co}
|
||||||
root := &qc.Selects[0]
|
root := &qc.Selects[0]
|
||||||
|
|
||||||
ti, err := c.schema.GetTable(root.Name)
|
ti, err := c.schema.GetTable(root.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch qc.Type {
|
switch qc.Type {
|
||||||
case qcode.QTInsert:
|
case qcode.QTInsert:
|
||||||
if _, err := c.renderInsert(qc, w, vars, ti); err != nil {
|
if _, err := c.renderInsert(w, qc, vars, ti); err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case qcode.QTUpdate:
|
case qcode.QTUpdate:
|
||||||
if _, err := c.renderUpdate(qc, w, vars, ti); err != nil {
|
if _, err := c.renderUpdate(w, qc, vars, ti); err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case qcode.QTUpsert:
|
case qcode.QTUpsert:
|
||||||
if _, err := c.renderUpsert(qc, w, vars, ti); err != nil {
|
if _, err := c.renderUpsert(w, qc, vars, ti); err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
case qcode.QTDelete:
|
case qcode.QTDelete:
|
||||||
if _, err := c.renderDelete(qc, w, vars, ti); err != nil {
|
if _, err := c.renderDelete(w, qc, vars, ti); err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, errors.New("valid mutations are 'insert', 'update', 'upsert' and 'delete'")
|
return c.md, errors.New("valid mutations are 'insert', 'update', 'upsert' and 'delete'")
|
||||||
}
|
}
|
||||||
|
|
||||||
root.Paging = noLimit
|
root.Paging = noLimit
|
||||||
@ -77,7 +80,7 @@ func (co *Compiler) compileMutation(qc *qcode.QCode, w io.Writer, vars Variables
|
|||||||
root.Where = nil
|
root.Where = nil
|
||||||
root.Args = nil
|
root.Args = nil
|
||||||
|
|
||||||
return c.compileQuery(qc, w, vars)
|
return co.compileQueryWithMetadata(w, qc, vars, c.md)
|
||||||
}
|
}
|
||||||
|
|
||||||
type kvitem struct {
|
type kvitem struct {
|
||||||
@ -365,12 +368,12 @@ func (c *compilerContext) renderUnionStmt(w io.Writer, item renitem) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderInsertUpdateColumns(w io.Writer,
|
func (c *compilerContext) renderInsertUpdateColumns(
|
||||||
qc *qcode.QCode,
|
qc *qcode.QCode,
|
||||||
jt map[string]json.RawMessage,
|
jt map[string]json.RawMessage,
|
||||||
ti *DBTableInfo,
|
ti *DBTableInfo,
|
||||||
skipcols map[string]struct{},
|
skipcols map[string]struct{},
|
||||||
values bool) (uint32, error) {
|
isValues bool) (uint32, error) {
|
||||||
|
|
||||||
root := &qc.Selects[0]
|
root := &qc.Selects[0]
|
||||||
renderedCol := false
|
renderedCol := false
|
||||||
@ -392,18 +395,18 @@ func renderInsertUpdateColumns(w io.Writer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if n != 0 {
|
if n != 0 {
|
||||||
io.WriteString(w, `, `)
|
io.WriteString(c.w, `, `)
|
||||||
}
|
}
|
||||||
|
|
||||||
if values {
|
if isValues {
|
||||||
io.WriteString(w, `CAST( i.j ->>`)
|
io.WriteString(c.w, `CAST( i.j ->>`)
|
||||||
io.WriteString(w, `'`)
|
io.WriteString(c.w, `'`)
|
||||||
io.WriteString(w, cn.Name)
|
io.WriteString(c.w, cn.Name)
|
||||||
io.WriteString(w, `' AS `)
|
io.WriteString(c.w, `' AS `)
|
||||||
io.WriteString(w, cn.Type)
|
io.WriteString(c.w, cn.Type)
|
||||||
io.WriteString(w, `)`)
|
io.WriteString(c.w, `)`)
|
||||||
} else {
|
} else {
|
||||||
quoted(w, cn.Name)
|
quoted(c.w, cn.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !renderedCol {
|
if !renderedCol {
|
||||||
@ -422,16 +425,28 @@ func renderInsertUpdateColumns(w io.Writer,
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if i != 0 || n != 0 {
|
if i != 0 || n != 0 {
|
||||||
io.WriteString(w, `, `)
|
io.WriteString(c.w, `, `)
|
||||||
}
|
}
|
||||||
|
|
||||||
if values {
|
if isValues {
|
||||||
io.WriteString(w, `'`)
|
val := root.PresetMap[cn]
|
||||||
io.WriteString(w, root.PresetMap[cn])
|
switch {
|
||||||
io.WriteString(w, `' :: `)
|
case ok && len(val) > 1 && val[0] == '$':
|
||||||
io.WriteString(w, col.Type)
|
c.renderValueExp(Param{Name: val[1:], Type: col.Type})
|
||||||
|
|
||||||
|
case ok && strings.HasPrefix(val, "sql:"):
|
||||||
|
io.WriteString(c.w, `(`)
|
||||||
|
c.renderVar(val[4:], c.renderValueExp)
|
||||||
|
io.WriteString(c.w, `)`)
|
||||||
|
|
||||||
|
case ok:
|
||||||
|
squoted(c.w, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
io.WriteString(c.w, ` :: `)
|
||||||
|
io.WriteString(c.w, col.Type)
|
||||||
} else {
|
} else {
|
||||||
quoted(w, cn)
|
quoted(c.w, cn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !renderedCol {
|
if !renderedCol {
|
||||||
@ -440,15 +455,15 @@ func renderInsertUpdateColumns(w io.Writer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(skipcols) != 0 && renderedCol {
|
if len(skipcols) != 0 && renderedCol {
|
||||||
io.WriteString(w, `, `)
|
io.WriteString(c.w, `, `)
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderUpsert(qc *qcode.QCode, w io.Writer,
|
func (c *compilerContext) renderUpsert(
|
||||||
vars Variables, ti *DBTableInfo) (uint32, error) {
|
w io.Writer, qc *qcode.QCode, vars Variables, ti *DBTableInfo) (uint32, error) {
|
||||||
root := &qc.Selects[0]
|
|
||||||
|
|
||||||
|
root := &qc.Selects[0]
|
||||||
upsert, ok := vars[qc.ActionVar]
|
upsert, ok := vars[qc.ActionVar]
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, fmt.Errorf("variable '%s' not defined", qc.ActionVar)
|
return 0, fmt.Errorf("variable '%s' not defined", qc.ActionVar)
|
||||||
@ -466,7 +481,7 @@ func (c *compilerContext) renderUpsert(qc *qcode.QCode, w io.Writer,
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.renderInsert(qc, w, vars, ti); err != nil {
|
if _, err := c.renderInsert(w, qc, vars, ti); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -672,7 +687,7 @@ func renderCteName(w io.Writer, item kvitem) error {
|
|||||||
io.WriteString(w, item.ti.Name)
|
io.WriteString(w, item.ti.Name)
|
||||||
if item._type == itemConnect || item._type == itemDisconnect {
|
if item._type == itemConnect || item._type == itemDisconnect {
|
||||||
io.WriteString(w, `_`)
|
io.WriteString(w, `_`)
|
||||||
int2string(w, item.id)
|
int32String(w, item.id)
|
||||||
}
|
}
|
||||||
io.WriteString(w, `"`)
|
io.WriteString(w, `"`)
|
||||||
return nil
|
return nil
|
||||||
|
@ -72,7 +72,7 @@ func delete(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 WHERE false RETURNING *) SELECT json_object_agg('user', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "users_0"."id" AS "id") AS "json_row_0")) AS "json_0" FROM (SELECT "users"."id" FROM "users" LIMIT ('1') :: integer) AS "users_0" LIMIT ('1') :: integer) AS "sel_0"`
|
// sql := `WITH "users" AS (WITH "input" AS (SELECT '$1' :: json AS j) INSERT INTO "users" ("full_name", "email") SELECT "full_name", "email" FROM input i, json_populate_record(NULL::users, i.j) t WHERE false RETURNING *) SELECT json_object_agg('user', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "users_0"."id" AS "id") AS "json_row_0")) AS "json_0" FROM (SELECT "users"."id" FROM "users" LIMIT ('1') :: integer) AS "users_0" LIMIT ('1') :: integer) AS "sel_0"`
|
||||||
|
|
||||||
// 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"}`),
|
||||||
@ -97,7 +97,7 @@ func delete(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
// }`
|
// }`
|
||||||
|
|
||||||
// sql := `WITH "users" AS (WITH "input" AS (SELECT '{{data}}' :: json AS j) UPDATE "users" SET ("full_name", "email") = (SELECT "full_name", "email" FROM input i, json_populate_record(NULL::users, i.j) t) WHERE false RETURNING *) SELECT json_object_agg('user', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "users_0"."id" AS "id", "users_0"."email" AS "email") AS "json_row_0")) AS "json_0" FROM (SELECT "users"."id", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LIMIT ('1') :: integer) AS "sel_0"`
|
// sql := `WITH "users" AS (WITH "input" AS (SELECT '$1' :: json AS j) UPDATE "users" SET ("full_name", "email") = (SELECT "full_name", "email" FROM input i, json_populate_record(NULL::users, i.j) t) WHERE false RETURNING *) SELECT json_object_agg('user', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "users_0"."id" AS "id", "users_0"."email" AS "email") AS "json_row_0")) AS "json_0" FROM (SELECT "users"."id", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LIMIT ('1') :: integer) AS "sel_0"`
|
||||||
|
|
||||||
// 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"}`),
|
||||||
|
@ -139,9 +139,9 @@ func TestMain(m *testing.M) {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
vars := psql.NewVariables(map[string]string{
|
vars := map[string]string{
|
||||||
"admin_account_id": "5",
|
"admin_account_id": "5",
|
||||||
})
|
}
|
||||||
|
|
||||||
pcompile = psql.NewCompiler(psql.Config{
|
pcompile = psql.NewCompiler(psql.Config{
|
||||||
Schema: schema,
|
Schema: schema,
|
||||||
|
@ -17,9 +17,24 @@ const (
|
|||||||
closeBlock = 500
|
closeBlock = 500
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
type Param struct {
|
||||||
ErrAllTablesSkipped = errors.New("all tables skipped. cannot render query")
|
Name string
|
||||||
)
|
Type string
|
||||||
|
IsArray bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Metadata struct {
|
||||||
|
Skipped uint32
|
||||||
|
Params []Param
|
||||||
|
pindex map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
type compilerContext struct {
|
||||||
|
md Metadata
|
||||||
|
w io.Writer
|
||||||
|
s []qcode.Select
|
||||||
|
*Compiler
|
||||||
|
}
|
||||||
|
|
||||||
type Variables map[string]json.RawMessage
|
type Variables map[string]json.RawMessage
|
||||||
|
|
||||||
@ -40,12 +55,12 @@ func NewCompiler(conf Config) *Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) AddRelationship(child, parent string, rel *DBRel) error {
|
func (co *Compiler) AddRelationship(child, parent string, rel *DBRel) error {
|
||||||
return c.schema.SetRel(child, parent, rel)
|
return co.schema.SetRel(child, parent, rel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) IDColumn(table string) (*DBColumn, error) {
|
func (co *Compiler) IDColumn(table string) (*DBColumn, error) {
|
||||||
ti, err := c.schema.GetTable(table)
|
ti, err := co.schema.GetTable(table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -57,65 +72,71 @@ func (c *Compiler) IDColumn(table string) (*DBColumn, error) {
|
|||||||
return ti.PrimaryCol, nil
|
return ti.PrimaryCol, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type compilerContext struct {
|
func (co *Compiler) CompileEx(qc *qcode.QCode, vars Variables) (Metadata, []byte, error) {
|
||||||
w io.Writer
|
|
||||||
s []qcode.Select
|
|
||||||
*Compiler
|
|
||||||
}
|
|
||||||
|
|
||||||
func (co *Compiler) CompileEx(qc *qcode.QCode, vars Variables) (uint32, []byte, error) {
|
|
||||||
w := &bytes.Buffer{}
|
w := &bytes.Buffer{}
|
||||||
skipped, err := co.Compile(qc, w, vars)
|
metad, err := co.Compile(w, qc, vars)
|
||||||
return skipped, w.Bytes(), err
|
return metad, w.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (co *Compiler) Compile(qc *qcode.QCode, w io.Writer, vars Variables) (uint32, error) {
|
func (co *Compiler) Compile(w io.Writer, qc *qcode.QCode, vars Variables) (Metadata, error) {
|
||||||
switch qc.Type {
|
switch qc.Type {
|
||||||
case qcode.QTQuery:
|
case qcode.QTQuery:
|
||||||
return co.compileQuery(qc, w, vars)
|
return co.compileQuery(w, qc, vars)
|
||||||
case qcode.QTInsert, qcode.QTUpdate, qcode.QTDelete, qcode.QTUpsert:
|
|
||||||
return co.compileMutation(qc, w, vars)
|
case qcode.QTInsert,
|
||||||
|
qcode.QTUpdate,
|
||||||
|
qcode.QTDelete,
|
||||||
|
qcode.QTUpsert:
|
||||||
|
return co.compileMutation(w, qc, vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, fmt.Errorf("Unknown operation type %d", qc.Type)
|
return Metadata{}, fmt.Errorf("Unknown operation type %d", qc.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (co *Compiler) compileQuery(qc *qcode.QCode, w io.Writer, vars Variables) (uint32, error) {
|
func (co *Compiler) compileQuery(w io.Writer, qc *qcode.QCode, vars Variables) (Metadata, error) {
|
||||||
|
return co.compileQueryWithMetadata(w, qc, vars, Metadata{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (co *Compiler) compileQueryWithMetadata(
|
||||||
|
w io.Writer, qc *qcode.QCode, vars Variables, md Metadata) (Metadata, error) {
|
||||||
|
|
||||||
if len(qc.Selects) == 0 {
|
if len(qc.Selects) == 0 {
|
||||||
return 0, errors.New("empty query")
|
return md, errors.New("empty query")
|
||||||
}
|
}
|
||||||
|
|
||||||
c := &compilerContext{w, qc.Selects, co}
|
c := &compilerContext{md, w, qc.Selects, co}
|
||||||
|
|
||||||
st := NewIntStack()
|
st := NewIntStack()
|
||||||
i := 0
|
i := 0
|
||||||
|
|
||||||
io.WriteString(c.w, `SELECT jsonb_build_object(`)
|
io.WriteString(c.w, `SELECT jsonb_build_object(`)
|
||||||
for _, id := range qc.Roots {
|
for _, id := range qc.Roots {
|
||||||
root := &qc.Selects[id]
|
|
||||||
if root.SkipRender || len(root.Cols) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
st.Push(root.ID + closeBlock)
|
|
||||||
st.Push(root.ID)
|
|
||||||
|
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
io.WriteString(c.w, `, `)
|
io.WriteString(c.w, `, `)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.renderRootSelect(root)
|
root := &qc.Selects[id]
|
||||||
|
|
||||||
|
if root.SkipRender || len(root.Cols) == 0 {
|
||||||
|
squoted(c.w, root.FieldName)
|
||||||
|
io.WriteString(c.w, `, `)
|
||||||
|
io.WriteString(c.w, `NULL`)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
st.Push(root.ID + closeBlock)
|
||||||
|
st.Push(root.ID)
|
||||||
|
c.renderRootSelect(root)
|
||||||
|
}
|
||||||
|
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(c.w, `) as "__root" FROM `)
|
if st.Len() != 0 {
|
||||||
|
io.WriteString(c.w, `) as "__root" FROM `)
|
||||||
if i == 0 {
|
} else {
|
||||||
return 0, ErrAllTablesSkipped
|
io.WriteString(c.w, `) as "__root"`)
|
||||||
|
return c.md, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ignored uint32
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if st.Len() == 0 {
|
if st.Len() == 0 {
|
||||||
break
|
break
|
||||||
@ -132,7 +153,7 @@ func (co *Compiler) compileQuery(qc *qcode.QCode, w io.Writer, vars Variables) (
|
|||||||
|
|
||||||
ti, err := c.schema.GetTable(sel.Name)
|
ti, err := c.schema.GetTable(sel.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sel.ParentID == -1 {
|
if sel.ParentID == -1 {
|
||||||
@ -145,14 +166,12 @@ func (co *Compiler) compileQuery(qc *qcode.QCode, w io.Writer, vars Variables) (
|
|||||||
c.renderPluralSelect(sel, ti)
|
c.renderPluralSelect(sel, ti)
|
||||||
}
|
}
|
||||||
|
|
||||||
skipped, err := c.renderSelect(sel, ti, vars)
|
if err := c.renderSelect(sel, ti, vars); err != nil {
|
||||||
if err != nil {
|
return c.md, err
|
||||||
return 0, err
|
|
||||||
}
|
}
|
||||||
ignored |= skipped
|
|
||||||
|
|
||||||
for _, cid := range sel.Children {
|
for _, cid := range sel.Children {
|
||||||
if hasBit(skipped, uint32(cid)) {
|
if hasBit(c.md.Skipped, uint32(cid)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
child := &c.s[cid]
|
child := &c.s[cid]
|
||||||
@ -169,7 +188,7 @@ func (co *Compiler) compileQuery(qc *qcode.QCode, w io.Writer, vars Variables) (
|
|||||||
|
|
||||||
ti, err := c.schema.GetTable(sel.Name)
|
ti, err := c.schema.GetTable(sel.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return c.md, err
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(c.w, `)`)
|
io.WriteString(c.w, `)`)
|
||||||
@ -201,12 +220,12 @@ func (co *Compiler) compileQuery(qc *qcode.QCode, w io.Writer, vars Variables) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ignored, nil
|
return c.md, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderPluralSelect(sel *qcode.Select, ti *DBTableInfo) error {
|
func (c *compilerContext) renderPluralSelect(sel *qcode.Select, ti *DBTableInfo) error {
|
||||||
io.WriteString(c.w, `SELECT coalesce(jsonb_agg("__sj_`)
|
io.WriteString(c.w, `SELECT coalesce(jsonb_agg("__sj_`)
|
||||||
int2string(c.w, sel.ID)
|
int32String(c.w, sel.ID)
|
||||||
io.WriteString(c.w, `"."json"), '[]') as "json"`)
|
io.WriteString(c.w, `"."json"), '[]') as "json"`)
|
||||||
|
|
||||||
if sel.Paging.Type != qcode.PtOffset {
|
if sel.Paging.Type != qcode.PtOffset {
|
||||||
@ -230,7 +249,7 @@ func (c *compilerContext) renderPluralSelect(sel *qcode.Select, ti *DBTableInfo)
|
|||||||
io.WriteString(c.w, `, CONCAT_WS(','`)
|
io.WriteString(c.w, `, CONCAT_WS(','`)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
io.WriteString(c.w, `, max("__cur_`)
|
io.WriteString(c.w, `, max("__cur_`)
|
||||||
int2string(c.w, int32(i))
|
int32String(c.w, int32(i))
|
||||||
io.WriteString(c.w, `")`)
|
io.WriteString(c.w, `")`)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, `) as "cursor"`)
|
io.WriteString(c.w, `) as "cursor"`)
|
||||||
@ -246,7 +265,7 @@ func (c *compilerContext) renderRootSelect(sel *qcode.Select) error {
|
|||||||
io.WriteString(c.w, `', `)
|
io.WriteString(c.w, `', `)
|
||||||
|
|
||||||
io.WriteString(c.w, `"__sj_`)
|
io.WriteString(c.w, `"__sj_`)
|
||||||
int2string(c.w, sel.ID)
|
int32String(c.w, sel.ID)
|
||||||
io.WriteString(c.w, `"."json"`)
|
io.WriteString(c.w, `"."json"`)
|
||||||
|
|
||||||
if sel.Paging.Type != qcode.PtOffset {
|
if sel.Paging.Type != qcode.PtOffset {
|
||||||
@ -255,16 +274,14 @@ func (c *compilerContext) renderRootSelect(sel *qcode.Select) error {
|
|||||||
io.WriteString(c.w, `_cursor', `)
|
io.WriteString(c.w, `_cursor', `)
|
||||||
|
|
||||||
io.WriteString(c.w, `"__sj_`)
|
io.WriteString(c.w, `"__sj_`)
|
||||||
int2string(c.w, sel.ID)
|
int32String(c.w, sel.ID)
|
||||||
io.WriteString(c.w, `"."cursor"`)
|
io.WriteString(c.w, `"."cursor"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) initSelect(sel *qcode.Select, ti *DBTableInfo, vars Variables) (uint32, []*qcode.Column, error) {
|
func (c *compilerContext) initSelect(sel *qcode.Select, ti *DBTableInfo, vars Variables) ([]*qcode.Column, error) {
|
||||||
var skipped uint32
|
|
||||||
|
|
||||||
cols := make([]*qcode.Column, 0, len(sel.Cols))
|
cols := make([]*qcode.Column, 0, len(sel.Cols))
|
||||||
colmap := make(map[string]struct{}, len(sel.Cols))
|
colmap := make(map[string]struct{}, len(sel.Cols))
|
||||||
|
|
||||||
@ -306,9 +323,7 @@ func (c *compilerContext) initSelect(sel *qcode.Select, ti *DBTableInfo, vars Va
|
|||||||
|
|
||||||
rel, err := c.schema.GetRel(child.Name, ti.Name)
|
rel, err := c.schema.GetRel(child.Name, ti.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return nil, err
|
||||||
//skipped |= (1 << uint(id))
|
|
||||||
//continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rel.Type {
|
switch rel.Type {
|
||||||
@ -334,16 +349,15 @@ func (c *compilerContext) initSelect(sel *qcode.Select, ti *DBTableInfo, vars Va
|
|||||||
if _, ok := colmap[rel.Left.Col]; !ok {
|
if _, ok := colmap[rel.Left.Col]; !ok {
|
||||||
cols = append(cols, &qcode.Column{Table: ti.Name, Name: rel.Left.Col, FieldName: rel.Right.Col})
|
cols = append(cols, &qcode.Column{Table: ti.Name, Name: rel.Left.Col, FieldName: rel.Right.Col})
|
||||||
colmap[rel.Left.Col] = struct{}{}
|
colmap[rel.Left.Col] = struct{}{}
|
||||||
skipped |= (1 << uint(id))
|
c.md.Skipped |= (1 << uint(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, nil, fmt.Errorf("unknown relationship %s", rel)
|
return nil, fmt.Errorf("unknown relationship %s", rel)
|
||||||
//skipped |= (1 << uint(id))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return skipped, cols, nil
|
return cols, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// This
|
// This
|
||||||
@ -412,7 +426,7 @@ func (c *compilerContext) addSeekPredicate(sel *qcode.Select) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars Variables) (uint32, error) {
|
func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars Variables) error {
|
||||||
var rel *DBRel
|
var rel *DBRel
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -421,13 +435,13 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
|
|
||||||
rel, err = c.schema.GetRel(ti.Name, parent.Name)
|
rel, err = c.schema.GetRel(ti.Name, parent.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skipped, childCols, err := c.initSelect(sel, ti, vars)
|
childCols, err := c.initSelect(sel, ti, vars)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SELECT
|
// SELECT
|
||||||
@ -437,13 +451,13 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
io.WriteString(c.w, `SELECT to_jsonb("__sr_`)
|
io.WriteString(c.w, `SELECT to_jsonb("__sr_`)
|
||||||
int2string(c.w, sel.ID)
|
int32String(c.w, sel.ID)
|
||||||
io.WriteString(c.w, `".*) `)
|
io.WriteString(c.w, `".*) `)
|
||||||
|
|
||||||
if sel.Paging.Type != qcode.PtOffset {
|
if sel.Paging.Type != qcode.PtOffset {
|
||||||
for i := range sel.OrderBy {
|
for i := range sel.OrderBy {
|
||||||
io.WriteString(c.w, `- '__cur_`)
|
io.WriteString(c.w, `- '__cur_`)
|
||||||
int2string(c.w, int32(i))
|
int32String(c.w, int32(i))
|
||||||
io.WriteString(c.w, `' `)
|
io.WriteString(c.w, `' `)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -453,15 +467,15 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
if sel.Paging.Type != qcode.PtOffset {
|
if sel.Paging.Type != qcode.PtOffset {
|
||||||
for i := range sel.OrderBy {
|
for i := range sel.OrderBy {
|
||||||
io.WriteString(c.w, `, "__cur_`)
|
io.WriteString(c.w, `, "__cur_`)
|
||||||
int2string(c.w, int32(i))
|
int32String(c.w, int32(i))
|
||||||
io.WriteString(c.w, `"`)
|
io.WriteString(c.w, `"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(c.w, `FROM (SELECT `)
|
io.WriteString(c.w, `FROM (SELECT `)
|
||||||
|
|
||||||
if err := c.renderColumns(sel, ti, skipped); err != nil {
|
if err := c.renderColumns(sel, ti); err != nil {
|
||||||
return 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if sel.Paging.Type != qcode.PtOffset {
|
if sel.Paging.Type != qcode.PtOffset {
|
||||||
@ -469,7 +483,7 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
io.WriteString(c.w, `, LAST_VALUE(`)
|
io.WriteString(c.w, `, LAST_VALUE(`)
|
||||||
colWithTableID(c.w, ti.Name, sel.ID, ob.Col)
|
colWithTableID(c.w, ti.Name, sel.ID, ob.Col)
|
||||||
io.WriteString(c.w, `) OVER() AS "__cur_`)
|
io.WriteString(c.w, `) OVER() AS "__cur_`)
|
||||||
int2string(c.w, int32(i))
|
int32String(c.w, int32(i))
|
||||||
io.WriteString(c.w, `"`)
|
io.WriteString(c.w, `"`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,9 +491,8 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
io.WriteString(c.w, ` FROM (`)
|
io.WriteString(c.w, ` FROM (`)
|
||||||
|
|
||||||
// FROM (SELECT .... )
|
// FROM (SELECT .... )
|
||||||
err = c.renderBaseSelect(sel, ti, rel, childCols, skipped)
|
if err = c.renderBaseSelect(sel, ti, rel, childCols); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return skipped, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Fprintf(w, `) AS "%s_%d"`, c.sel.Name, c.sel.ID)
|
//fmt.Fprintf(w, `) AS "%s_%d"`, c.sel.Name, c.sel.ID)
|
||||||
@ -488,7 +501,7 @@ func (c *compilerContext) renderSelect(sel *qcode.Select, ti *DBTableInfo, vars
|
|||||||
|
|
||||||
// END-FROM
|
// END-FROM
|
||||||
|
|
||||||
return skipped, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderLateralJoin(sel *qcode.Select) error {
|
func (c *compilerContext) renderLateralJoin(sel *qcode.Select) error {
|
||||||
@ -538,7 +551,7 @@ func (c *compilerContext) renderJoinByName(table, parent string, id int32) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo, skipped uint32) error {
|
func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo) error {
|
||||||
i := 0
|
i := 0
|
||||||
var cn string
|
var cn string
|
||||||
|
|
||||||
@ -574,7 +587,7 @@ func (c *compilerContext) renderColumns(sel *qcode.Select, ti *DBTableInfo, skip
|
|||||||
|
|
||||||
i += c.renderRemoteRelColumns(sel, ti, i)
|
i += c.renderRemoteRelColumns(sel, ti, i)
|
||||||
|
|
||||||
return c.renderJoinColumns(sel, ti, skipped, i)
|
return c.renderJoinColumns(sel, ti, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select, ti *DBTableInfo, colsRendered int) int {
|
func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select, ti *DBTableInfo, colsRendered int) int {
|
||||||
@ -599,12 +612,12 @@ func (c *compilerContext) renderRemoteRelColumns(sel *qcode.Select, ti *DBTableI
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderJoinColumns(sel *qcode.Select, ti *DBTableInfo, skipped uint32, colsRendered int) error {
|
func (c *compilerContext) renderJoinColumns(sel *qcode.Select, ti *DBTableInfo, colsRendered int) error {
|
||||||
// columns previously rendered
|
// columns previously rendered
|
||||||
i := colsRendered
|
i := colsRendered
|
||||||
|
|
||||||
for _, id := range sel.Children {
|
for _, id := range sel.Children {
|
||||||
if hasBit(skipped, uint32(id)) {
|
if hasBit(c.md.Skipped, uint32(id)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
childSel := &c.s[id]
|
childSel := &c.s[id]
|
||||||
@ -620,13 +633,13 @@ func (c *compilerContext) renderJoinColumns(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(c.w, `"__sj_`)
|
io.WriteString(c.w, `"__sj_`)
|
||||||
int2string(c.w, childSel.ID)
|
int32String(c.w, childSel.ID)
|
||||||
io.WriteString(c.w, `"."json"`)
|
io.WriteString(c.w, `"."json"`)
|
||||||
alias(c.w, childSel.FieldName)
|
alias(c.w, childSel.FieldName)
|
||||||
|
|
||||||
if childSel.Paging.Type != qcode.PtOffset {
|
if childSel.Paging.Type != qcode.PtOffset {
|
||||||
io.WriteString(c.w, `, "__sj_`)
|
io.WriteString(c.w, `, "__sj_`)
|
||||||
int2string(c.w, childSel.ID)
|
int32String(c.w, childSel.ID)
|
||||||
io.WriteString(c.w, `"."cursor" AS "`)
|
io.WriteString(c.w, `"."cursor" AS "`)
|
||||||
io.WriteString(c.w, childSel.FieldName)
|
io.WriteString(c.w, childSel.FieldName)
|
||||||
io.WriteString(c.w, `_cursor"`)
|
io.WriteString(c.w, `_cursor"`)
|
||||||
@ -639,7 +652,7 @@ func (c *compilerContext) renderJoinColumns(sel *qcode.Select, ti *DBTableInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo, rel *DBRel,
|
func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo, rel *DBRel,
|
||||||
childCols []*qcode.Column, skipped uint32) error {
|
childCols []*qcode.Column) error {
|
||||||
isRoot := (rel == nil)
|
isRoot := (rel == nil)
|
||||||
isFil := (sel.Where != nil && sel.Where.Op != qcode.OpNop)
|
isFil := (sel.Where != nil && sel.Where.Op != qcode.OpNop)
|
||||||
hasOrder := len(sel.OrderBy) != 0
|
hasOrder := len(sel.OrderBy) != 0
|
||||||
@ -654,7 +667,7 @@ func (c *compilerContext) renderBaseSelect(sel *qcode.Select, ti *DBTableInfo, r
|
|||||||
c.renderDistinctOn(sel, ti)
|
c.renderDistinctOn(sel, ti)
|
||||||
}
|
}
|
||||||
|
|
||||||
realColsRendered, isAgg, err := c.renderBaseColumns(sel, ti, childCols, skipped)
|
realColsRendered, isAgg, err := c.renderBaseColumns(sel, ti, childCols)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -781,11 +794,13 @@ func (c *compilerContext) renderCursorCTE(sel *qcode.Select) error {
|
|||||||
io.WriteString(c.w, `, `)
|
io.WriteString(c.w, `, `)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, `a[`)
|
io.WriteString(c.w, `a[`)
|
||||||
int2string(c.w, int32(i+1))
|
int32String(c.w, int32(i+1))
|
||||||
io.WriteString(c.w, `] as `)
|
io.WriteString(c.w, `] as `)
|
||||||
quoted(c.w, ob.Col)
|
quoted(c.w, ob.Col)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, ` FROM string_to_array('{{cursor}}', ',') as a) `)
|
io.WriteString(c.w, ` FROM string_to_array(`)
|
||||||
|
c.renderValueExp(Param{Name: "cursor", Type: "json"})
|
||||||
|
io.WriteString(c.w, `, ',') as a) `)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1026,9 +1041,9 @@ func (c *compilerContext) renderOp(ex *qcode.Exp, ti *DBTableInfo) error {
|
|||||||
case qcode.OpLesserThan:
|
case qcode.OpLesserThan:
|
||||||
io.WriteString(c.w, `<`)
|
io.WriteString(c.w, `<`)
|
||||||
case qcode.OpIn:
|
case qcode.OpIn:
|
||||||
io.WriteString(c.w, `IN`)
|
io.WriteString(c.w, `= ANY`)
|
||||||
case qcode.OpNotIn:
|
case qcode.OpNotIn:
|
||||||
io.WriteString(c.w, `NOT IN`)
|
io.WriteString(c.w, `!= ANY`)
|
||||||
case qcode.OpLike:
|
case qcode.OpLike:
|
||||||
io.WriteString(c.w, `LIKE`)
|
io.WriteString(c.w, `LIKE`)
|
||||||
case qcode.OpNotLike:
|
case qcode.OpNotLike:
|
||||||
@ -1078,12 +1093,13 @@ func (c *compilerContext) renderOp(ex *qcode.Exp, ti *DBTableInfo) error {
|
|||||||
io.WriteString(c.w, `((`)
|
io.WriteString(c.w, `((`)
|
||||||
colWithTable(c.w, ti.Name, ti.TSVCol.Name)
|
colWithTable(c.w, ti.Name, ti.TSVCol.Name)
|
||||||
if c.schema.ver >= 110000 {
|
if c.schema.ver >= 110000 {
|
||||||
io.WriteString(c.w, `) @@ websearch_to_tsquery('{{`)
|
io.WriteString(c.w, `) @@ websearch_to_tsquery(`)
|
||||||
} else {
|
} else {
|
||||||
io.WriteString(c.w, `) @@ to_tsquery('{{`)
|
io.WriteString(c.w, `) @@ to_tsquery(`)
|
||||||
}
|
}
|
||||||
io.WriteString(c.w, ex.Val)
|
c.renderValueExp(Param{Name: ex.Val, Type: "string"})
|
||||||
io.WriteString(c.w, `}}'))`)
|
io.WriteString(c.w, `))`)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1169,15 +1185,25 @@ func (c *compilerContext) renderVal(ex *qcode.Exp, vars map[string]string, col *
|
|||||||
val, ok := vars[ex.Val]
|
val, ok := vars[ex.Val]
|
||||||
switch {
|
switch {
|
||||||
case ok && strings.HasPrefix(val, "sql:"):
|
case ok && strings.HasPrefix(val, "sql:"):
|
||||||
io.WriteString(c.w, ` (`)
|
io.WriteString(c.w, `(`)
|
||||||
io.WriteString(c.w, val[4:])
|
c.renderVar(val[4:], c.renderValueExp)
|
||||||
io.WriteString(c.w, `)`)
|
io.WriteString(c.w, `)`)
|
||||||
|
|
||||||
case ok:
|
case ok:
|
||||||
squoted(c.w, val)
|
squoted(c.w, val)
|
||||||
|
|
||||||
|
case ex.Op == qcode.OpIn || ex.Op == qcode.OpNotIn:
|
||||||
|
io.WriteString(c.w, `(ARRAY(SELECT json_array_elements_text(`)
|
||||||
|
c.renderValueExp(Param{Name: ex.Val, Type: col.Type, IsArray: true})
|
||||||
|
io.WriteString(c.w, `))`)
|
||||||
|
|
||||||
|
io.WriteString(c.w, ` :: `)
|
||||||
|
io.WriteString(c.w, col.Type)
|
||||||
|
io.WriteString(c.w, `[])`)
|
||||||
|
return
|
||||||
|
|
||||||
default:
|
default:
|
||||||
io.WriteString(c.w, ` '{{`)
|
c.renderValueExp(Param{Name: ex.Val, Type: col.Type, IsArray: false})
|
||||||
io.WriteString(c.w, ex.Val)
|
|
||||||
io.WriteString(c.w, `}}'`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case qcode.ValRef:
|
case qcode.ValRef:
|
||||||
@ -1191,6 +1217,54 @@ func (c *compilerContext) renderVal(ex *qcode.Exp, vars map[string]string, col *
|
|||||||
io.WriteString(c.w, col.Type)
|
io.WriteString(c.w, col.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *compilerContext) renderValueExp(p Param) {
|
||||||
|
io.WriteString(c.w, `$`)
|
||||||
|
if v, ok := c.md.pindex[p.Name]; ok {
|
||||||
|
int32String(c.w, int32(v))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c.md.Params = append(c.md.Params, p)
|
||||||
|
n := len(c.md.Params)
|
||||||
|
|
||||||
|
if c.md.pindex == nil {
|
||||||
|
c.md.pindex = make(map[string]int)
|
||||||
|
}
|
||||||
|
c.md.pindex[p.Name] = n
|
||||||
|
int32String(c.w, int32(n))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *compilerContext) renderVar(vv string, fn func(Param)) {
|
||||||
|
f, s := -1, 0
|
||||||
|
|
||||||
|
for i := range vv {
|
||||||
|
v := vv[i]
|
||||||
|
switch {
|
||||||
|
case (i > 0 && vv[i-1] != '\\' && v == '$') || v == '$':
|
||||||
|
if (i - s) > 0 {
|
||||||
|
io.WriteString(c.w, vv[s:i])
|
||||||
|
}
|
||||||
|
f = i
|
||||||
|
|
||||||
|
case (v < 'a' && v > 'z') &&
|
||||||
|
(v < 'A' && v > 'Z') &&
|
||||||
|
(v < '0' && v > '9') &&
|
||||||
|
v != '_' &&
|
||||||
|
f != -1 &&
|
||||||
|
(i-f) > 1:
|
||||||
|
fn(Param{Name: vv[f+1 : i]})
|
||||||
|
s = i
|
||||||
|
f = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f != -1 && (len(vv)-f) > 1 {
|
||||||
|
fn(Param{Name: vv[f+1:]})
|
||||||
|
} else {
|
||||||
|
io.WriteString(c.w, vv[s:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func funcPrefixLen(fm map[string]*DBFunction, fn string) int {
|
func funcPrefixLen(fm map[string]*DBFunction, fn string) int {
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(fn, "avg_"):
|
case strings.HasPrefix(fn, "avg_"):
|
||||||
@ -1242,7 +1316,7 @@ func aliasWithID(w io.Writer, alias string, id int32) {
|
|||||||
io.WriteString(w, ` AS "`)
|
io.WriteString(w, ` AS "`)
|
||||||
io.WriteString(w, alias)
|
io.WriteString(w, alias)
|
||||||
io.WriteString(w, `_`)
|
io.WriteString(w, `_`)
|
||||||
int2string(w, id)
|
int32String(w, id)
|
||||||
io.WriteString(w, `"`)
|
io.WriteString(w, `"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1259,7 +1333,7 @@ func colWithTableID(w io.Writer, table string, id int32, col string) {
|
|||||||
io.WriteString(w, table)
|
io.WriteString(w, table)
|
||||||
if id >= 0 {
|
if id >= 0 {
|
||||||
io.WriteString(w, `_`)
|
io.WriteString(w, `_`)
|
||||||
int2string(w, id)
|
int32String(w, id)
|
||||||
}
|
}
|
||||||
io.WriteString(w, `"."`)
|
io.WriteString(w, `"."`)
|
||||||
io.WriteString(w, col)
|
io.WriteString(w, col)
|
||||||
@ -1280,7 +1354,7 @@ func squoted(w io.Writer, identifier string) {
|
|||||||
|
|
||||||
const charset = "0123456789"
|
const charset = "0123456789"
|
||||||
|
|
||||||
func int2string(w io.Writer, val int32) {
|
func int32String(w io.Writer, val int32) {
|
||||||
if val < 10 {
|
if val < 10 {
|
||||||
w.Write([]byte{charset[val]})
|
w.Write([]byte{charset[val]})
|
||||||
return
|
return
|
||||||
|
@ -32,6 +32,20 @@ func withComplexArgs(t *testing.T) {
|
|||||||
compileGQLToPSQL(t, gql, nil, "user")
|
compileGQLToPSQL(t, gql, nil, "user")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withWhereIn(t *testing.T) {
|
||||||
|
gql := `query {
|
||||||
|
products(where: { id: { in: $list } }) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
vars := map[string]json.RawMessage{
|
||||||
|
"list": json.RawMessage(`[1,2,3]`),
|
||||||
|
}
|
||||||
|
|
||||||
|
compileGQLToPSQL(t, gql, vars, "user")
|
||||||
|
}
|
||||||
|
|
||||||
func withWhereAndList(t *testing.T) {
|
func withWhereAndList(t *testing.T) {
|
||||||
gql := `query {
|
gql := `query {
|
||||||
products(
|
products(
|
||||||
@ -367,6 +381,7 @@ func blockedFunctions(t *testing.T) {
|
|||||||
|
|
||||||
func TestCompileQuery(t *testing.T) {
|
func TestCompileQuery(t *testing.T) {
|
||||||
t.Run("withComplexArgs", withComplexArgs)
|
t.Run("withComplexArgs", withComplexArgs)
|
||||||
|
t.Run("withWhereIn", withWhereIn)
|
||||||
t.Run("withWhereAndList", withWhereAndList)
|
t.Run("withWhereAndList", withWhereAndList)
|
||||||
t.Run("withWhereIsNull", withWhereIsNull)
|
t.Run("withWhereIsNull", withWhereIsNull)
|
||||||
t.Run("withWhereMultiOr", withWhereMultiOr)
|
t.Run("withWhereMultiOr", withWhereMultiOr)
|
||||||
@ -429,7 +444,7 @@ func BenchmarkCompile(b *testing.B) {
|
|||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pcompile.Compile(qc, w, nil)
|
_, err = pcompile.Compile(w, qc, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -450,7 +465,7 @@ func BenchmarkCompileParallel(b *testing.B) {
|
|||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = pcompile.Compile(qc, w, nil)
|
_, err = pcompile.Compile(w, qc, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
=== RUN TestCompileInsert
|
=== RUN TestCompileInsert
|
||||||
=== RUN TestCompileInsert/simpleInsert
|
=== RUN TestCompileInsert/simpleInsert
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id" FROM (SELECT "users"."id" FROM "users" LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id" FROM (SELECT "users"."id" FROM "users" LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/singleInsert
|
=== RUN TestCompileInsert/singleInsert
|
||||||
WITH "_sg_input" AS (SELECT '{{insert}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "description", "price", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'user_id' AS bigint) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "description", "price", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'user_id' AS bigint) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/bulkInsert
|
=== RUN TestCompileInsert/bulkInsert
|
||||||
WITH "_sg_input" AS (SELECT '{{insert}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/simpleInsertWithPresets
|
=== RUN TestCompileInsert/simpleInsertWithPresets
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), 'now' :: timestamp without time zone, 'now' :: timestamp without time zone, '{{user_id}}' :: bigint FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id" FROM (SELECT "products"."id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), 'now' :: timestamp without time zone, 'now' :: timestamp without time zone, $2 :: bigint FROM "_sg_input" i RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id" FROM (SELECT "products"."id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertManyToMany
|
=== RUN TestCompileInsert/nestedInsertManyToMany
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "price") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i RETURNING *), "customers" AS (INSERT INTO "customers" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *), "purchases" AS (INSERT INTO "purchases" ("sale_type", "quantity", "due_date", "customer_id", "product_id") SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone), "customers"."id", "products"."id" FROM "_sg_input" i, "customers", "products" RETURNING *) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "customers" AS (INSERT INTO "customers" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i RETURNING *), "purchases" AS (INSERT INTO "purchases" ("sale_type", "quantity", "due_date", "product_id", "customer_id") SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone), "products"."id", "customers"."id" FROM "_sg_input" i, "products", "customers" RETURNING *) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "customers" AS (INSERT INTO "customers" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i RETURNING *), "purchases" AS (INSERT INTO "purchases" ("sale_type", "quantity", "due_date", "product_id", "customer_id") SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone), "products"."id", "customers"."id" FROM "_sg_input" i, "products", "customers" RETURNING *) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "price") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i RETURNING *), "customers" AS (INSERT INTO "customers" ("full_name", "email") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i RETURNING *), "purchases" AS (INSERT INTO "purchases" ("sale_type", "quantity", "due_date", "customer_id", "product_id") SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone), "customers"."id", "products"."id" FROM "_sg_input" i, "customers", "products" RETURNING *) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertOneToMany
|
=== RUN TestCompileInsert/nestedInsertOneToMany
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "users"."id" FROM "_sg_input" i, "users" RETURNING *) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "users"."id" FROM "_sg_input" i, "users" RETURNING *) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertOneToOne
|
=== RUN TestCompileInsert/nestedInsertOneToOne
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "users"."id" FROM "_sg_input" i, "users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "users"."id" FROM "_sg_input" i, "users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertOneToManyWithConnect
|
=== RUN TestCompileInsert/nestedInsertOneToManyWithConnect
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS ( UPDATE "products" SET "user_id" = "users"."id" FROM "users" WHERE ("products"."id"= ((i.j->'product'->'connect'->>'id'))::bigint) RETURNING "products".*) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (INSERT INTO "users" ("full_name", "email", "created_at", "updated_at") SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i RETURNING *), "products" AS ( UPDATE "products" SET "user_id" = "users"."id" FROM "users" WHERE ("products"."id"= ((i.j->'product'->'connect'->>'id'))::bigint) RETURNING "products".*) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertOneToOneWithConnect
|
=== RUN TestCompileInsert/nestedInsertOneToOneWithConnect
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint LIMIT 1), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "_x_users"."id" FROM "_sg_input" i, "_x_users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user", "__sj_2"."json" AS "tags" FROM (SELECT "products"."id", "products"."name", "products"."user_id", "products"."tags" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_2"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "tags_2"."id" AS "id", "tags_2"."name" AS "name" FROM (SELECT "tags"."id", "tags"."name" FROM "tags" WHERE ((("tags"."slug") = any ("products_0"."tags"))) LIMIT ('20') :: integer) AS "tags_2") AS "__sr_2") AS "__sj_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint LIMIT 1), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "_x_users"."id" FROM "_sg_input" i, "_x_users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user", "__sj_2"."json" AS "tags" FROM (SELECT "products"."id", "products"."name", "products"."user_id", "products"."tags" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_2"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "tags_2"."id" AS "id", "tags_2"."name" AS "name" FROM (SELECT "tags"."id", "tags"."name" FROM "tags" WHERE ((("tags"."slug") = any ("products_0"."tags"))) LIMIT ('20') :: integer) AS "tags_2") AS "__sr_2") AS "__sj_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileInsert/nestedInsertOneToOneWithConnectArray
|
=== RUN TestCompileInsert/nestedInsertOneToOneWithConnectArray
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id" = ANY((select a::bigint AS list from json_array_elements_text((i.j->'user'->'connect'->>'id')::json) AS a)) LIMIT 1), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "_x_users"."id" FROM "_sg_input" i, "_x_users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id" = ANY((select a::bigint AS list from json_array_elements_text((i.j->'user'->'connect'->>'id')::json) AS a)) LIMIT 1), "products" AS (INSERT INTO "products" ("name", "price", "created_at", "updated_at", "user_id") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone), "_x_users"."id" FROM "_sg_input" i, "_x_users" RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
--- PASS: TestCompileInsert (0.02s)
|
--- PASS: TestCompileInsert (0.02s)
|
||||||
--- PASS: TestCompileInsert/simpleInsert (0.00s)
|
--- PASS: TestCompileInsert/simpleInsert (0.00s)
|
||||||
--- PASS: TestCompileInsert/singleInsert (0.00s)
|
--- PASS: TestCompileInsert/singleInsert (0.00s)
|
||||||
@ -33,14 +33,14 @@ WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT "id"
|
|||||||
--- PASS: TestCompileInsert/nestedInsertOneToOneWithConnectArray (0.00s)
|
--- PASS: TestCompileInsert/nestedInsertOneToOneWithConnectArray (0.00s)
|
||||||
=== RUN TestCompileMutate
|
=== RUN TestCompileMutate
|
||||||
=== RUN TestCompileMutate/singleUpsert
|
=== RUN TestCompileMutate/singleUpsert
|
||||||
WITH "_sg_input" AS (SELECT '{{upsert}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileMutate/singleUpsertWhere
|
=== RUN TestCompileMutate/singleUpsertWhere
|
||||||
WITH "_sg_input" AS (SELECT '{{upsert}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) WHERE (("products"."price") > '3' :: numeric(7,2)) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) WHERE (("products"."price") > '3' :: numeric(7,2)) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileMutate/bulkUpsert
|
=== RUN TestCompileMutate/bulkUpsert
|
||||||
WITH "_sg_input" AS (SELECT '{{upsert}}' :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (INSERT INTO "products" ("name", "description") SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i RETURNING *) ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, description = EXCLUDED.description RETURNING *) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileMutate/delete
|
=== RUN TestCompileMutate/delete
|
||||||
WITH "products" AS (DELETE FROM "products" WHERE (((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") = '1' :: bigint)) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "products" AS (DELETE FROM "products" WHERE (((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") = '1' :: bigint)) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
--- PASS: TestCompileMutate (0.00s)
|
--- PASS: TestCompileMutate (0.01s)
|
||||||
--- PASS: TestCompileMutate/singleUpsert (0.00s)
|
--- PASS: TestCompileMutate/singleUpsert (0.00s)
|
||||||
--- PASS: TestCompileMutate/singleUpsertWhere (0.00s)
|
--- PASS: TestCompileMutate/singleUpsertWhere (0.00s)
|
||||||
--- PASS: TestCompileMutate/bulkUpsert (0.00s)
|
--- PASS: TestCompileMutate/bulkUpsert (0.00s)
|
||||||
@ -48,6 +48,8 @@ WITH "products" AS (DELETE FROM "products" WHERE (((("products"."price") > '0' :
|
|||||||
=== RUN TestCompileQuery
|
=== RUN TestCompileQuery
|
||||||
=== RUN TestCompileQuery/withComplexArgs
|
=== RUN TestCompileQuery/withComplexArgs
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT DISTINCT ON ("products"."price") "products"."id", "products"."name", "products"."price" FROM "products" WHERE (((("products"."id") < '28' :: bigint) AND (("products"."id") >= '20' :: bigint) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) ORDER BY "products"."price" DESC LIMIT ('30') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT DISTINCT ON ("products"."price") "products"."id", "products"."name", "products"."price" FROM "products" WHERE (((("products"."id") < '28' :: bigint) AND (("products"."id") >= '20' :: bigint) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) ORDER BY "products"."price" DESC LIMIT ('30') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
|
=== RUN TestCompileQuery/withWhereIn
|
||||||
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id" FROM (SELECT "products"."id" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") = ANY (ARRAY(SELECT json_array_elements_text($1)) :: bigint[])))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/withWhereAndList
|
=== RUN TestCompileQuery/withWhereAndList
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE (((("products"."price") > '10' :: numeric(7,2)) AND NOT (("products"."id") IS NULL) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE (((("products"."price") > '10' :: numeric(7,2)) AND NOT (("products"."id") IS NULL) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/withWhereIsNull
|
=== RUN TestCompileQuery/withWhereIsNull
|
||||||
@ -55,9 +57,9 @@ SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT
|
|||||||
=== RUN TestCompileQuery/withWhereMultiOr
|
=== RUN TestCompileQuery/withWhereMultiOr
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND ((("products"."price") < '20' :: numeric(7,2)) OR (("products"."price") > '10' :: numeric(7,2)) OR NOT (("products"."id") IS NULL)))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND ((("products"."price") < '20' :: numeric(7,2)) OR (("products"."price") > '10' :: numeric(7,2)) OR NOT (("products"."id") IS NULL)))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/fetchByID
|
=== RUN TestCompileQuery/fetchByID
|
||||||
SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") = '{{id}}' :: bigint))) LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") = $1 :: bigint))) LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/searchQuery
|
=== RUN TestCompileQuery/searchQuery
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."search_rank" AS "search_rank", "products_0"."search_headline_description" AS "search_headline_description" FROM (SELECT "products"."id", "products"."name", ts_rank("products"."tsv", websearch_to_tsquery('{{query}}')) AS "search_rank", ts_headline("products"."description", websearch_to_tsquery('{{query}}')) AS "search_headline_description" FROM "products" WHERE ((("products"."tsv") @@ websearch_to_tsquery('{{query}}'))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."search_rank" AS "search_rank", "products_0"."search_headline_description" AS "search_headline_description" FROM (SELECT "products"."id", "products"."name", ts_rank("products"."tsv", websearch_to_tsquery($1)) AS "search_rank", ts_headline("products"."description", websearch_to_tsquery($1)) AS "search_headline_description" FROM "products" WHERE ((("products"."tsv") @@ websearch_to_tsquery($1))) LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/oneToMany
|
=== RUN TestCompileQuery/oneToMany
|
||||||
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."email" AS "email", "__sj_1"."json" AS "products" FROM (SELECT "users"."email", "users"."id" FROM "users" LIMIT ('20') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_1"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id")) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2)))) LIMIT ('20') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."email" AS "email", "__sj_1"."json" AS "products" FROM (SELECT "users"."email", "users"."id" FROM "users" LIMIT ('20') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_1"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id")) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2)))) LIMIT ('20') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/oneToManyReverse
|
=== RUN TestCompileQuery/oneToManyReverse
|
||||||
@ -77,9 +79,9 @@ SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT
|
|||||||
=== RUN TestCompileQuery/aggFunctionWithFilter
|
=== RUN TestCompileQuery/aggFunctionWithFilter
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."max_price" AS "max_price" FROM (SELECT "products"."id", max("products"."price") AS "max_price" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") > '10' :: bigint))) GROUP BY "products"."id" LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."max_price" AS "max_price" FROM (SELECT "products"."id", max("products"."price") AS "max_price" FROM "products" WHERE ((((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))) AND (("products"."id") > '10' :: bigint))) GROUP BY "products"."id" LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/syntheticTables
|
=== RUN TestCompileQuery/syntheticTables
|
||||||
SELECT jsonb_build_object('me', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT FROM (SELECT "users"."email" FROM "users" WHERE ((("users"."id") = '{{user_id}}' :: bigint)) LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
SELECT jsonb_build_object('me', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT FROM (SELECT "users"."email" FROM "users" WHERE ((("users"."id") = $1 :: bigint)) LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/queryWithVariables
|
=== RUN TestCompileQuery/queryWithVariables
|
||||||
SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE (((("products"."price") = '{{product_price}}' :: numeric(7,2)) AND (("products"."id") = '{{product_id}}' :: bigint) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" WHERE (((("products"."price") = $1 :: numeric(7,2)) AND (("products"."id") = $2 :: bigint) AND ((("products"."price") > '0' :: numeric(7,2)) AND (("products"."price") < '8' :: numeric(7,2))))) LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/withWhereOnRelations
|
=== RUN TestCompileQuery/withWhereOnRelations
|
||||||
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."email" AS "email" FROM (SELECT "users"."id", "users"."email" FROM "users" WHERE (NOT EXISTS (SELECT 1 FROM products WHERE (("products"."user_id") = ("users"."id")) AND ((("products"."price") > '3' :: numeric(7,2))))) LIMIT ('20') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."email" AS "email" FROM (SELECT "users"."id", "users"."email" FROM "users" WHERE (NOT EXISTS (SELECT 1 FROM products WHERE (("products"."user_id") = ("users"."id")) AND ((("products"."price") > '3' :: numeric(7,2))))) LIMIT ('20') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/multiRoot
|
=== RUN TestCompileQuery/multiRoot
|
||||||
@ -87,15 +89,16 @@ SELECT jsonb_build_object('customer', "__sj_0"."json", 'user', "__sj_1"."json",
|
|||||||
=== RUN TestCompileQuery/jsonColumnAsTable
|
=== RUN TestCompileQuery/jsonColumnAsTable
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "tag_count" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "tag_count_1"."count" AS "count", "__sj_2"."json" AS "tags" FROM (SELECT "tag_count"."count", "tag_count"."tag_id" FROM "products", json_to_recordset("products"."tag_count") AS "tag_count"(tag_id bigint, count int) WHERE ((("products"."id") = ("products_0"."id"))) LIMIT ('1') :: integer) AS "tag_count_1" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_2"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "tags_2"."name" AS "name" FROM (SELECT "tags"."name" FROM "tags" WHERE ((("tags"."id") = ("tag_count_1"."tag_id"))) LIMIT ('20') :: integer) AS "tags_2") AS "__sr_2") AS "__sj_2") AS "__sj_2" ON ('true')) AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "tag_count" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('20') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "tag_count_1"."count" AS "count", "__sj_2"."json" AS "tags" FROM (SELECT "tag_count"."count", "tag_count"."tag_id" FROM "products", json_to_recordset("products"."tag_count") AS "tag_count"(tag_id bigint, count int) WHERE ((("products"."id") = ("products_0"."id"))) LIMIT ('1') :: integer) AS "tag_count_1" LEFT OUTER JOIN LATERAL (SELECT coalesce(jsonb_agg("__sj_2"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "tags_2"."name" AS "name" FROM (SELECT "tags"."name" FROM "tags" WHERE ((("tags"."id") = ("tag_count_1"."tag_id"))) LIMIT ('20') :: integer) AS "tags_2") AS "__sr_2") AS "__sj_2") AS "__sj_2" ON ('true')) AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/withCursor
|
=== RUN TestCompileQuery/withCursor
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json", 'products_cursor', "__sj_0"."cursor") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json", CONCAT_WS(',', max("__cur_0"), max("__cur_1")) as "cursor" FROM (SELECT to_jsonb("__sr_0".*) - '__cur_0' - '__cur_1' AS "json", "__cur_0", "__cur_1"FROM (SELECT "products_0"."name" AS "name", LAST_VALUE("products_0"."price") OVER() AS "__cur_0", LAST_VALUE("products_0"."id") OVER() AS "__cur_1" FROM (WITH "__cur" AS (SELECT a[1] as "price", a[2] as "id" FROM string_to_array('{{cursor}}', ',') as a) SELECT "products"."name", "products"."id", "products"."price" FROM "products", "__cur" WHERE (((("products"."price") < "__cur"."price" :: numeric(7,2)) OR ((("products"."price") = "__cur"."price" :: numeric(7,2)) AND (("products"."id") > "__cur"."id" :: bigint)))) ORDER BY "products"."price" DESC, "products"."id" ASC LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json", 'products_cursor', "__sj_0"."cursor") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json", CONCAT_WS(',', max("__cur_0"), max("__cur_1")) as "cursor" FROM (SELECT to_jsonb("__sr_0".*) - '__cur_0' - '__cur_1' AS "json", "__cur_0", "__cur_1"FROM (SELECT "products_0"."name" AS "name", LAST_VALUE("products_0"."price") OVER() AS "__cur_0", LAST_VALUE("products_0"."id") OVER() AS "__cur_1" FROM (WITH "__cur" AS (SELECT a[1] as "price", a[2] as "id" FROM string_to_array($1, ',') as a) SELECT "products"."name", "products"."id", "products"."price" FROM "products", "__cur" WHERE (((("products"."price") < "__cur"."price" :: numeric(7,2)) OR ((("products"."price") = "__cur"."price" :: numeric(7,2)) AND (("products"."id") > "__cur"."id" :: bigint)))) ORDER BY "products"."price" DESC, "products"."id" ASC LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/nullForAuthRequiredInAnon
|
=== RUN TestCompileQuery/nullForAuthRequiredInAnon
|
||||||
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", NULL AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('products', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", NULL AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('20') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/blockedQuery
|
=== RUN TestCompileQuery/blockedQuery
|
||||||
SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE (false) LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE (false) LIMIT ('1') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileQuery/blockedFunctions
|
=== RUN TestCompileQuery/blockedFunctions
|
||||||
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."email" AS "email" FROM (SELECT , "users"."email" FROM "users" WHERE (false) GROUP BY "users"."email" LIMIT ('20') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coalesce(jsonb_agg("__sj_0"."json"), '[]') as "json" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."email" AS "email" FROM (SELECT , "users"."email" FROM "users" WHERE (false) GROUP BY "users"."email" LIMIT ('20') :: integer) AS "users_0") AS "__sr_0") AS "__sj_0") AS "__sj_0"
|
||||||
--- PASS: TestCompileQuery (0.02s)
|
--- PASS: TestCompileQuery (0.03s)
|
||||||
--- PASS: TestCompileQuery/withComplexArgs (0.00s)
|
--- PASS: TestCompileQuery/withComplexArgs (0.00s)
|
||||||
|
--- PASS: TestCompileQuery/withWhereIn (0.00s)
|
||||||
--- PASS: TestCompileQuery/withWhereAndList (0.00s)
|
--- PASS: TestCompileQuery/withWhereAndList (0.00s)
|
||||||
--- PASS: TestCompileQuery/withWhereIsNull (0.00s)
|
--- PASS: TestCompileQuery/withWhereIsNull (0.00s)
|
||||||
--- PASS: TestCompileQuery/withWhereMultiOr (0.00s)
|
--- PASS: TestCompileQuery/withWhereMultiOr (0.00s)
|
||||||
@ -121,23 +124,23 @@ SELECT jsonb_build_object('users', "__sj_0"."json") as "__root" FROM (SELECT coa
|
|||||||
--- PASS: TestCompileQuery/blockedFunctions (0.00s)
|
--- PASS: TestCompileQuery/blockedFunctions (0.00s)
|
||||||
=== RUN TestCompileUpdate
|
=== RUN TestCompileUpdate
|
||||||
=== RUN TestCompileUpdate/singleUpdate
|
=== RUN TestCompileUpdate/singleUpdate
|
||||||
WITH "_sg_input" AS (SELECT '{{update}}' :: json AS j), "products" AS (UPDATE "products" SET ("name", "description") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i) WHERE ((("products"."id") = '1' :: bigint) AND (("products"."id") = '{{id}}' :: bigint)) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (UPDATE "products" SET ("name", "description") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'description' AS text) FROM "_sg_input" i) WHERE ((("products"."id") = '1' :: bigint) AND (("products"."id") = $2 :: bigint)) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name" FROM (SELECT "products"."id", "products"."name" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/simpleUpdateWithPresets
|
=== RUN TestCompileUpdate/simpleUpdateWithPresets
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "products" AS (UPDATE "products" SET ("name", "price", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), 'now' :: timestamp without time zone FROM "_sg_input" i) WHERE (("products"."user_id") = '{{user_id}}' :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id" FROM (SELECT "products"."id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (UPDATE "products" SET ("name", "price", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), 'now' :: timestamp without time zone FROM "_sg_input" i) WHERE (("products"."user_id") = $2 :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id" FROM (SELECT "products"."id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateManyToMany
|
=== RUN TestCompileUpdate/nestedUpdateManyToMany
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "purchases" AS (UPDATE "purchases" SET ("sale_type", "quantity", "due_date") = (SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("purchases"."id") = '{{id}}' :: bigint) RETURNING "purchases".*), "products" AS (UPDATE "products" SET ("name", "price") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i) FROM "purchases" WHERE (("products"."id") = ("purchases"."product_id")) RETURNING "products".*), "customers" AS (UPDATE "customers" SET ("full_name", "email") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "purchases" WHERE (("customers"."id") = ("purchases"."customer_id")) RETURNING "customers".*) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "purchases" AS (UPDATE "purchases" SET ("sale_type", "quantity", "due_date") = (SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("purchases"."id") = $2 :: bigint) RETURNING "purchases".*), "products" AS (UPDATE "products" SET ("name", "price") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i) FROM "purchases" WHERE (("products"."id") = ("purchases"."product_id")) RETURNING "products".*), "customers" AS (UPDATE "customers" SET ("full_name", "email") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "purchases" WHERE (("customers"."id") = ("purchases"."customer_id")) RETURNING "customers".*) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "purchases" AS (UPDATE "purchases" SET ("sale_type", "quantity", "due_date") = (SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("purchases"."id") = '{{id}}' :: bigint) RETURNING "purchases".*), "customers" AS (UPDATE "customers" SET ("full_name", "email") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "purchases" WHERE (("customers"."id") = ("purchases"."customer_id")) RETURNING "customers".*), "products" AS (UPDATE "products" SET ("name", "price") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i) FROM "purchases" WHERE (("products"."id") = ("purchases"."product_id")) RETURNING "products".*) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "purchases" AS (UPDATE "purchases" SET ("sale_type", "quantity", "due_date") = (SELECT CAST( i.j ->>'sale_type' AS character varying), CAST( i.j ->>'quantity' AS integer), CAST( i.j ->>'due_date' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("purchases"."id") = $2 :: bigint) RETURNING "purchases".*), "customers" AS (UPDATE "customers" SET ("full_name", "email") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "purchases" WHERE (("customers"."id") = ("purchases"."customer_id")) RETURNING "customers".*), "products" AS (UPDATE "products" SET ("name", "price") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)) FROM "_sg_input" i) FROM "purchases" WHERE (("products"."id") = ("purchases"."product_id")) RETURNING "products".*) SELECT jsonb_build_object('purchase', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "purchases_0"."sale_type" AS "sale_type", "purchases_0"."quantity" AS "quantity", "purchases_0"."due_date" AS "due_date", "__sj_1"."json" AS "product", "__sj_2"."json" AS "customer" FROM (SELECT "purchases"."sale_type", "purchases"."quantity", "purchases"."due_date", "purchases"."product_id", "purchases"."customer_id" FROM "purchases" LIMIT ('1') :: integer) AS "purchases_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_2".*) AS "json"FROM (SELECT "customers_2"."id" AS "id", "customers_2"."full_name" AS "full_name", "customers_2"."email" AS "email" FROM (SELECT "customers"."id", "customers"."full_name", "customers"."email" FROM "customers" WHERE ((("customers"."id") = ("purchases_0"."customer_id"))) LIMIT ('1') :: integer) AS "customers_2") AS "__sr_2") AS "__sj_2" ON ('true') LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."id") = ("purchases_0"."product_id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateOneToMany
|
=== RUN TestCompileUpdate/nestedUpdateOneToMany
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (UPDATE "users" SET ("full_name", "email", "created_at", "updated_at") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("users"."id") = '8' :: bigint) RETURNING "users".*), "products" AS (UPDATE "products" SET ("name", "price", "created_at", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) FROM "users" WHERE (("products"."user_id") = ("users"."id") AND "products"."id"= ((i.j->'product'->'where'->>'id'))::bigint) RETURNING "products".*) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (UPDATE "users" SET ("full_name", "email", "created_at", "updated_at") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("users"."id") = '8' :: bigint) RETURNING "users".*), "products" AS (UPDATE "products" SET ("name", "price", "created_at", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) FROM "users" WHERE (("products"."user_id") = ("users"."id") AND "products"."id"= ((i.j->'product'->'where'->>'id'))::bigint) RETURNING "products".*) SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateOneToOne
|
=== RUN TestCompileUpdate/nestedUpdateOneToOne
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "products" AS (UPDATE "products" SET ("name", "price", "created_at", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("products"."id") = '{{id}}' :: bigint) RETURNING "products".*), "users" AS (UPDATE "users" SET ("email") = (SELECT CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "products" WHERE (("users"."id") = ("products"."user_id")) RETURNING "users".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "products" AS (UPDATE "products" SET ("name", "price", "created_at", "updated_at") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("products"."id") = $2 :: bigint) RETURNING "products".*), "users" AS (UPDATE "users" SET ("email") = (SELECT CAST( i.j ->>'email' AS character varying) FROM "_sg_input" i) FROM "products" WHERE (("users"."id") = ("products"."user_id")) RETURNING "users".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateOneToManyWithConnect
|
=== RUN TestCompileUpdate/nestedUpdateOneToManyWithConnect
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (UPDATE "users" SET ("full_name", "email", "created_at", "updated_at") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("users"."id") = '{{id}}' :: bigint) RETURNING "users".*), "products_c" AS ( UPDATE "products" SET "user_id" = "users"."id" FROM "users" WHERE ("products"."id"= ((i.j->'product'->'connect'->>'id'))::bigint) RETURNING "products".*), "products_d" AS ( UPDATE "products" SET "user_id" = NULL FROM "users" WHERE ("products"."id"= ((i.j->'product'->'disconnect'->>'id'))::bigint) RETURNING "products".*), "products" AS (SELECT * FROM "products_c" UNION ALL SELECT * FROM "products_d") SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (UPDATE "users" SET ("full_name", "email", "created_at", "updated_at") = (SELECT CAST( i.j ->>'full_name' AS character varying), CAST( i.j ->>'email' AS character varying), CAST( i.j ->>'created_at' AS timestamp without time zone), CAST( i.j ->>'updated_at' AS timestamp without time zone) FROM "_sg_input" i) WHERE (("users"."id") = $2 :: bigint) RETURNING "users".*), "products_c" AS ( UPDATE "products" SET "user_id" = "users"."id" FROM "users" WHERE ("products"."id"= ((i.j->'product'->'connect'->>'id'))::bigint) RETURNING "products".*), "products_d" AS ( UPDATE "products" SET "user_id" = NULL FROM "users" WHERE ("products"."id"= ((i.j->'product'->'disconnect'->>'id'))::bigint) RETURNING "products".*), "products" AS (SELECT * FROM "products_c" UNION ALL SELECT * FROM "products_d") SELECT jsonb_build_object('user', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "users_0"."id" AS "id", "users_0"."full_name" AS "full_name", "users_0"."email" AS "email", "__sj_1"."json" AS "product" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" LIMIT ('1') :: integer) AS "users_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "products_1"."id" AS "id", "products_1"."name" AS "name", "products_1"."price" AS "price" FROM (SELECT "products"."id", "products"."name", "products"."price" FROM "products" WHERE ((("products"."user_id") = ("users_0"."id"))) LIMIT ('1') :: integer) AS "products_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateOneToOneWithConnect
|
=== RUN TestCompileUpdate/nestedUpdateOneToOneWithConnect
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint AND "users"."email"= ((i.j->'user'->'connect'->>'email'))::character varying LIMIT 1), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = '{{product_id}}' :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint AND "users"."email"= ((i.j->'user'->'connect'->>'email'))::character varying LIMIT 1), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = $2 :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."email"= ((i.j->'user'->'connect'->>'email'))::character varying AND "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint LIMIT 1), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = '{{product_id}}' :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "_x_users" AS (SELECT "id" FROM "_sg_input" i,"users" WHERE "users"."email"= ((i.j->'user'->'connect'->>'email'))::character varying AND "users"."id"= ((i.j->'user'->'connect'->>'id'))::bigint LIMIT 1), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = $2 :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "__sj_1"."json" AS "user" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LEFT OUTER JOIN LATERAL (SELECT to_jsonb("__sr_1".*) AS "json"FROM (SELECT "users_1"."id" AS "id", "users_1"."full_name" AS "full_name", "users_1"."email" AS "email" FROM (SELECT "users"."id", "users"."full_name", "users"."email" FROM "users" WHERE ((("users"."id") = ("products_0"."user_id"))) LIMIT ('1') :: integer) AS "users_1") AS "__sr_1") AS "__sj_1" ON ('true')) AS "__sr_0") AS "__sj_0"
|
||||||
=== RUN TestCompileUpdate/nestedUpdateOneToOneWithDisconnect
|
=== RUN TestCompileUpdate/nestedUpdateOneToOneWithDisconnect
|
||||||
WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT * FROM (VALUES(NULL::bigint)) AS LOOKUP("id")), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = '{{id}}' :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."user_id" AS "user_id" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
WITH "_sg_input" AS (SELECT $1 :: json AS j), "_x_users" AS (SELECT * FROM (VALUES(NULL::bigint)) AS LOOKUP("id")), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT CAST( i.j ->>'name' AS character varying), CAST( i.j ->>'price' AS numeric(7,2)), "_x_users"."id" FROM "_sg_input" i, "_x_users") WHERE (("products"."id") = $2 :: bigint) RETURNING "products".*) SELECT jsonb_build_object('product', "__sj_0"."json") as "__root" FROM (SELECT to_jsonb("__sr_0".*) AS "json"FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."user_id" AS "user_id" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0") AS "__sr_0") AS "__sj_0"
|
||||||
--- PASS: TestCompileUpdate (0.02s)
|
--- PASS: TestCompileUpdate (0.02s)
|
||||||
--- PASS: TestCompileUpdate/singleUpdate (0.00s)
|
--- PASS: TestCompileUpdate/singleUpdate (0.00s)
|
||||||
--- PASS: TestCompileUpdate/simpleUpdateWithPresets (0.00s)
|
--- PASS: TestCompileUpdate/simpleUpdateWithPresets (0.00s)
|
||||||
@ -148,4 +151,4 @@ WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "_x_users" AS (SELECT * FR
|
|||||||
--- PASS: TestCompileUpdate/nestedUpdateOneToOneWithConnect (0.00s)
|
--- PASS: TestCompileUpdate/nestedUpdateOneToOneWithConnect (0.00s)
|
||||||
--- PASS: TestCompileUpdate/nestedUpdateOneToOneWithDisconnect (0.00s)
|
--- PASS: TestCompileUpdate/nestedUpdateOneToOneWithDisconnect (0.00s)
|
||||||
PASS
|
PASS
|
||||||
ok github.com/dosco/super-graph/core/internal/psql 0.306s
|
ok github.com/dosco/super-graph/core/internal/psql (cached)
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/dosco/super-graph/core/internal/util"
|
"github.com/dosco/super-graph/core/internal/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *compilerContext) renderUpdate(qc *qcode.QCode, w io.Writer,
|
func (c *compilerContext) renderUpdate(
|
||||||
vars Variables, ti *DBTableInfo) (uint32, error) {
|
w io.Writer, qc *qcode.QCode, vars Variables, ti *DBTableInfo) (uint32, error) {
|
||||||
|
|
||||||
update, ok := vars[qc.ActionVar]
|
update, ok := vars[qc.ActionVar]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -21,9 +21,10 @@ func (c *compilerContext) renderUpdate(qc *qcode.QCode, w io.Writer,
|
|||||||
return 0, fmt.Errorf("variable '%s' is empty", qc.ActionVar)
|
return 0, fmt.Errorf("variable '%s' is empty", qc.ActionVar)
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(c.w, `WITH "_sg_input" AS (SELECT '{{`)
|
io.WriteString(c.w, `WITH "_sg_input" AS (SELECT `)
|
||||||
io.WriteString(c.w, qc.ActionVar)
|
c.renderValueExp(Param{Name: qc.ActionVar, Type: "json"})
|
||||||
io.WriteString(c.w, `}}' :: json AS j)`)
|
// io.WriteString(c.w, qc.ActionVar)
|
||||||
|
io.WriteString(c.w, ` :: json AS j)`)
|
||||||
|
|
||||||
st := util.NewStack()
|
st := util.NewStack()
|
||||||
st.Push(kvitem{_type: itemUpdate, key: ti.Name, val: update, ti: ti})
|
st.Push(kvitem{_type: itemUpdate, key: ti.Name, val: update, ti: ti})
|
||||||
@ -84,11 +85,11 @@ func (c *compilerContext) renderUpdateStmt(w io.Writer, qc *qcode.QCode, item re
|
|||||||
io.WriteString(w, `UPDATE `)
|
io.WriteString(w, `UPDATE `)
|
||||||
quoted(w, ti.Name)
|
quoted(w, ti.Name)
|
||||||
io.WriteString(w, ` SET (`)
|
io.WriteString(w, ` SET (`)
|
||||||
renderInsertUpdateColumns(w, qc, jt, ti, sk, false)
|
c.renderInsertUpdateColumns(qc, jt, ti, sk, false)
|
||||||
renderNestedUpdateRelColumns(w, item.kvitem, false)
|
renderNestedUpdateRelColumns(w, item.kvitem, false)
|
||||||
|
|
||||||
io.WriteString(w, `) = (SELECT `)
|
io.WriteString(w, `) = (SELECT `)
|
||||||
renderInsertUpdateColumns(w, qc, jt, ti, sk, true)
|
c.renderInsertUpdateColumns(qc, jt, ti, sk, true)
|
||||||
renderNestedUpdateRelColumns(w, item.kvitem, true)
|
renderNestedUpdateRelColumns(w, item.kvitem, true)
|
||||||
|
|
||||||
io.WriteString(w, ` FROM "_sg_input" i`)
|
io.WriteString(w, ` FROM "_sg_input" i`)
|
||||||
@ -122,7 +123,7 @@ func (c *compilerContext) renderUpdateStmt(w io.Writer, qc *qcode.QCode, item re
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
if qc.Selects[0].Where != nil {
|
if qc.Selects[0].Where != nil {
|
||||||
io.WriteString(w, ` WHERE `)
|
io.WriteString(w, `WHERE `)
|
||||||
if err := c.renderWhere(&qc.Selects[0], ti); err != nil {
|
if err := c.renderWhere(&qc.Selects[0], ti); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -197,8 +198,9 @@ func renderNestedUpdateRelTables(w io.Writer, item kvitem) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compilerContext) renderDelete(qc *qcode.QCode, w io.Writer,
|
func (c *compilerContext) renderDelete(
|
||||||
vars Variables, ti *DBTableInfo) (uint32, error) {
|
w io.Writer, qc *qcode.QCode, vars Variables, ti *DBTableInfo) (uint32, error) {
|
||||||
|
|
||||||
root := &qc.Selects[0]
|
root := &qc.Selects[0]
|
||||||
|
|
||||||
io.WriteString(c.w, `WITH `)
|
io.WriteString(c.w, `WITH `)
|
||||||
|
@ -223,7 +223,7 @@ func nestedUpdateOneToOneWithDisconnect(t *testing.T) {
|
|||||||
// }
|
// }
|
||||||
// }`
|
// }`
|
||||||
|
|
||||||
// sql := `WITH "_sg_input" AS (SELECT '{{data}}' :: json AS j), "users" AS (SELECT * FROM (VALUES(NULL::bigint)) AS LOOKUP("id")), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT "t"."name", "t"."price", "users"."id" FROM "_sg_input" i, "users", json_populate_record(NULL::products, i.j) t) WHERE (("products"."id") = 2) RETURNING "products".*) SELECT json_object_agg('product', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."user_id" AS "user_id") AS "json_row_0")) AS "json_0" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LIMIT ('1') :: integer) AS "sel_0"`
|
// sql := `WITH "_sg_input" AS (SELECT $1 :: json AS j), "users" AS (SELECT * FROM (VALUES(NULL::bigint)) AS LOOKUP("id")), "products" AS (UPDATE "products" SET ("name", "price", "user_id") = (SELECT "t"."name", "t"."price", "users"."id" FROM "_sg_input" i, "users", json_populate_record(NULL::products, i.j) t) WHERE (("products"."id") = 2) RETURNING "products".*) SELECT json_object_agg('product', json_0) FROM (SELECT row_to_json((SELECT "json_row_0" FROM (SELECT "products_0"."id" AS "id", "products_0"."name" AS "name", "products_0"."user_id" AS "user_id") AS "json_row_0")) AS "json_0" FROM (SELECT "products"."id", "products"."name", "products"."user_id" FROM "products" LIMIT ('1') :: integer) AS "products_0" LIMIT ('1') :: integer) AS "sel_0"`
|
||||||
|
|
||||||
// vars := map[string]json.RawMessage{
|
// vars := map[string]json.RawMessage{
|
||||||
// "data": json.RawMessage(`{
|
// "data": json.RawMessage(`{
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
package psql
|
|
||||||
|
|
||||||
import "regexp"
|
|
||||||
|
|
||||||
func NewVariables(varlist map[string]string) map[string]string {
|
|
||||||
re := regexp.MustCompile(`(?mi)\$([a-zA-Z0-9_.]+)`)
|
|
||||||
vars := make(map[string]string, len(varlist))
|
|
||||||
|
|
||||||
for k, v := range varlist {
|
|
||||||
vars[k] = re.ReplaceAllString(v, `{{$1}}`)
|
|
||||||
}
|
|
||||||
return vars
|
|
||||||
}
|
|
@ -1,14 +1,12 @@
|
|||||||
package qcode
|
package qcode
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Blocklist []string
|
Blocklist []string
|
||||||
DefaultBlock bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryConfig struct {
|
type QueryConfig struct {
|
||||||
@ -40,16 +38,14 @@ type DeleteConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TRConfig struct {
|
type TRConfig struct {
|
||||||
ReadOnly bool
|
Query QueryConfig
|
||||||
Query QueryConfig
|
Insert InsertConfig
|
||||||
Insert InsertConfig
|
Update UpdateConfig
|
||||||
Update UpdateConfig
|
Delete DeleteConfig
|
||||||
Delete DeleteConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type trval struct {
|
type trval struct {
|
||||||
readOnly bool
|
query struct {
|
||||||
query struct {
|
|
||||||
limit string
|
limit string
|
||||||
fil *Exp
|
fil *Exp
|
||||||
filNU bool
|
filNU bool
|
||||||
@ -134,12 +130,3 @@ func mapToList(m map[string]string) []string {
|
|||||||
sort.Strings(list)
|
sort.Strings(list)
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
var varRe = regexp.MustCompile(`\$([a-zA-Z0-9_]+)`)
|
|
||||||
|
|
||||||
func parsePresets(m map[string]string) map[string]string {
|
|
||||||
for k, v := range m {
|
|
||||||
m[k] = varRe.ReplaceAllString(v, `{{$1}}`)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
@ -170,7 +170,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Compiler struct {
|
type Compiler struct {
|
||||||
db bool // default block tables if not defined in anon role
|
|
||||||
tr map[string]map[string]*trval
|
tr map[string]map[string]*trval
|
||||||
bl map[string]struct{}
|
bl map[string]struct{}
|
||||||
}
|
}
|
||||||
@ -180,7 +179,7 @@ var expPool = sync.Pool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewCompiler(c Config) (*Compiler, error) {
|
func NewCompiler(c Config) (*Compiler, error) {
|
||||||
co := &Compiler{db: c.DefaultBlock}
|
co := &Compiler{}
|
||||||
co.tr = make(map[string]map[string]*trval)
|
co.tr = make(map[string]map[string]*trval)
|
||||||
co.bl = make(map[string]struct{}, len(c.Blocklist))
|
co.bl = make(map[string]struct{}, len(c.Blocklist))
|
||||||
|
|
||||||
@ -207,7 +206,7 @@ func NewFilter() *Exp {
|
|||||||
|
|
||||||
func (com *Compiler) AddRole(role, table string, trc TRConfig) error {
|
func (com *Compiler) AddRole(role, table string, trc TRConfig) error {
|
||||||
var err error
|
var err error
|
||||||
trv := &trval{readOnly: trc.ReadOnly}
|
trv := &trval{}
|
||||||
|
|
||||||
// query config
|
// query config
|
||||||
trv.query.fil, trv.query.filNU, err = compileFilter(trc.Query.Filters)
|
trv.query.fil, trv.query.filNU, err = compileFilter(trc.Query.Filters)
|
||||||
@ -227,7 +226,7 @@ func (com *Compiler) AddRole(role, table string, trc TRConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
trv.insert.cols = listToMap(trc.Insert.Columns)
|
trv.insert.cols = listToMap(trc.Insert.Columns)
|
||||||
trv.insert.psmap = parsePresets(trc.Insert.Presets)
|
trv.insert.psmap = trc.Insert.Presets
|
||||||
trv.insert.pslist = mapToList(trv.insert.psmap)
|
trv.insert.pslist = mapToList(trv.insert.psmap)
|
||||||
trv.insert.block = trc.Insert.Block
|
trv.insert.block = trc.Insert.Block
|
||||||
|
|
||||||
@ -237,7 +236,7 @@ func (com *Compiler) AddRole(role, table string, trc TRConfig) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
trv.update.cols = listToMap(trc.Update.Columns)
|
trv.update.cols = listToMap(trc.Update.Columns)
|
||||||
trv.update.psmap = parsePresets(trc.Update.Presets)
|
trv.update.psmap = trc.Update.Presets
|
||||||
trv.update.pslist = mapToList(trv.update.psmap)
|
trv.update.pslist = mapToList(trv.update.psmap)
|
||||||
trv.update.block = trc.Update.Block
|
trv.update.block = trc.Update.Block
|
||||||
|
|
||||||
@ -333,59 +332,82 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trv := com.getRole(role, field.Name)
|
trv := com.getRole(role, field.Name)
|
||||||
|
skipRender := false
|
||||||
|
|
||||||
switch action {
|
if trv != nil {
|
||||||
case QTQuery:
|
switch action {
|
||||||
if trv.query.block {
|
case QTQuery:
|
||||||
continue
|
if trv.query.block {
|
||||||
|
skipRender = true
|
||||||
|
}
|
||||||
|
|
||||||
|
case QTInsert:
|
||||||
|
if trv.insert.block {
|
||||||
|
return fmt.Errorf("%s, insert blocked: %s", role, field.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
case QTUpdate:
|
||||||
|
if trv.update.block {
|
||||||
|
return fmt.Errorf("%s, update blocked: %s", role, field.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
case QTDelete:
|
||||||
|
if trv.delete.block {
|
||||||
|
return fmt.Errorf("%s, delete blocked: %s", role, field.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case QTInsert:
|
} else if role == "anon" {
|
||||||
if trv.insert.block || trv.readOnly {
|
skipRender = true
|
||||||
return fmt.Errorf("insert blocked: %s", field.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
case QTUpdate:
|
|
||||||
if trv.update.block || trv.readOnly {
|
|
||||||
return fmt.Errorf("update blocked: %s", field.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
case QTDelete:
|
|
||||||
if trv.delete.block || trv.readOnly {
|
|
||||||
return fmt.Errorf("delete blocked: %s", field.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selects = append(selects, Select{
|
selects = append(selects, Select{
|
||||||
ID: id,
|
ID: id,
|
||||||
ParentID: parentID,
|
ParentID: parentID,
|
||||||
Name: field.Name,
|
Name: field.Name,
|
||||||
Children: make([]int32, 0, 5),
|
SkipRender: skipRender,
|
||||||
Allowed: trv.allowedColumns(action),
|
|
||||||
Functions: true,
|
|
||||||
})
|
})
|
||||||
s := &selects[(len(selects) - 1)]
|
s := &selects[(len(selects) - 1)]
|
||||||
|
|
||||||
switch action {
|
|
||||||
case QTQuery:
|
|
||||||
s.Functions = !trv.query.disable.funcs
|
|
||||||
s.Paging.Limit = trv.query.limit
|
|
||||||
|
|
||||||
case QTInsert:
|
|
||||||
s.PresetMap = trv.insert.psmap
|
|
||||||
s.PresetList = trv.insert.pslist
|
|
||||||
|
|
||||||
case QTUpdate:
|
|
||||||
s.PresetMap = trv.update.psmap
|
|
||||||
s.PresetList = trv.update.pslist
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(field.Alias) != 0 {
|
if len(field.Alias) != 0 {
|
||||||
s.FieldName = field.Alias
|
s.FieldName = field.Alias
|
||||||
} else {
|
} else {
|
||||||
s.FieldName = s.Name
|
s.FieldName = s.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.ParentID == -1 {
|
||||||
|
qc.Roots = append(qc.Roots, s.ID)
|
||||||
|
} else {
|
||||||
|
p := &selects[s.ParentID]
|
||||||
|
p.Children = append(p.Children, s.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if skipRender {
|
||||||
|
id++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Children = make([]int32, 0, 5)
|
||||||
|
s.Functions = true
|
||||||
|
|
||||||
|
if trv != nil {
|
||||||
|
s.Allowed = trv.allowedColumns(action)
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case QTQuery:
|
||||||
|
s.Functions = !trv.query.disable.funcs
|
||||||
|
s.Paging.Limit = trv.query.limit
|
||||||
|
|
||||||
|
case QTInsert:
|
||||||
|
s.PresetMap = trv.insert.psmap
|
||||||
|
s.PresetList = trv.insert.pslist
|
||||||
|
|
||||||
|
case QTUpdate:
|
||||||
|
s.PresetMap = trv.update.psmap
|
||||||
|
s.PresetList = trv.update.pslist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := com.compileArgs(qc, s, field.Args, role)
|
err := com.compileArgs(qc, s, field.Args, role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -394,13 +416,6 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
|
|||||||
// Order is important AddFilters must come after compileArgs
|
// Order is important AddFilters must come after compileArgs
|
||||||
com.AddFilters(qc, s, role)
|
com.AddFilters(qc, s, role)
|
||||||
|
|
||||||
if s.ParentID == -1 {
|
|
||||||
qc.Roots = append(qc.Roots, s.ID)
|
|
||||||
} else {
|
|
||||||
p := &selects[s.ParentID]
|
|
||||||
p.Children = append(p.Children, s.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Cols = make([]Column, 0, len(field.Children))
|
s.Cols = make([]Column, 0, len(field.Children))
|
||||||
action = QTQuery
|
action = QTQuery
|
||||||
|
|
||||||
@ -440,14 +455,10 @@ func (com *Compiler) compileQuery(qc *QCode, op *Operation, role string) error {
|
|||||||
|
|
||||||
func (com *Compiler) AddFilters(qc *QCode, sel *Select, role string) {
|
func (com *Compiler) AddFilters(qc *QCode, sel *Select, role string) {
|
||||||
var fil *Exp
|
var fil *Exp
|
||||||
var nu bool // user required (or not) in this filter
|
var nu bool // need user_id (or not) in this filter
|
||||||
|
|
||||||
if trv, ok := com.tr[role][sel.Name]; ok {
|
if trv, ok := com.tr[role][sel.Name]; ok {
|
||||||
fil, nu = trv.filter(qc.Type)
|
fil, nu = trv.filter(qc.Type)
|
||||||
|
|
||||||
} else if com.db && role == "anon" {
|
|
||||||
// Tables not defined under the anon role will not be rendered
|
|
||||||
sel.SkipRender = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if fil == nil {
|
if fil == nil {
|
||||||
@ -838,14 +849,17 @@ func (com *Compiler) compileArgAfterBefore(sel *Select, arg *Arg, pt PagingType)
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
var zeroTrv = &trval{}
|
// var zeroTrv = &trval{}
|
||||||
|
|
||||||
func (com *Compiler) getRole(role, field string) *trval {
|
func (com *Compiler) getRole(role, field string) *trval {
|
||||||
if trv, ok := com.tr[role][field]; ok {
|
if trv, ok := com.tr[role][field]; ok {
|
||||||
return trv
|
return trv
|
||||||
} else {
|
|
||||||
return zeroTrv
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
// } else {
|
||||||
|
// return zeroTrv
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddFilter(sel *Select, fil *Exp) {
|
func AddFilter(sel *Select, fil *Exp) {
|
||||||
@ -1015,10 +1029,15 @@ func setListVal(ex *Exp, node *Node) {
|
|||||||
case NodeFloat:
|
case NodeFloat:
|
||||||
ex.ListType = ValFloat
|
ex.ListType = ValFloat
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ex.Val = node.Val
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range node.Children {
|
for i := range node.Children {
|
||||||
ex.ListVal = append(ex.ListVal, node.Children[i].Val)
|
ex.ListVal = append(ex.ListVal, node.Children[i].Val)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setWhereColName(ex *Exp, node *Node) {
|
func setWhereColName(ex *Exp, node *Node) {
|
||||||
|
@ -11,14 +11,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dosco/super-graph/core/internal/allow"
|
"github.com/dosco/super-graph/core/internal/allow"
|
||||||
"github.com/dosco/super-graph/core/internal/psql"
|
|
||||||
"github.com/dosco/super-graph/core/internal/qcode"
|
"github.com/dosco/super-graph/core/internal/qcode"
|
||||||
"github.com/valyala/fasttemplate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type preparedItem struct {
|
type preparedItem struct {
|
||||||
sd *sql.Stmt
|
sd *sql.Stmt
|
||||||
args [][]byte
|
|
||||||
st stmt
|
st stmt
|
||||||
roleArg bool
|
roleArg bool
|
||||||
}
|
}
|
||||||
@ -103,9 +100,6 @@ func (sg *SuperGraph) prepareStmt(item allow.Item) error {
|
|||||||
// logger.Debug().Msgf("Prepared statement 'query %s' (anon)", item.Name)
|
// logger.Debug().Msgf("Prepared statement 'query %s' (anon)", item.Name)
|
||||||
|
|
||||||
stmts2, err := sg.buildRoleStmt(qb, vars, "anon")
|
stmts2, err := sg.buildRoleStmt(qb, vars, "anon")
|
||||||
if err == psql.ErrAllTablesSkipped {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -121,9 +115,6 @@ func (sg *SuperGraph) prepareStmt(item allow.Item) error {
|
|||||||
// logger.Debug().Msgf("Prepared statement 'mutation %s' (%s)", item.Name, role.Name)
|
// logger.Debug().Msgf("Prepared statement 'mutation %s' (%s)", item.Name, role.Name)
|
||||||
|
|
||||||
stmts, err := sg.buildRoleStmt(qb, vars, role.Name)
|
stmts, err := sg.buildRoleStmt(qb, vars, role.Name)
|
||||||
if err == psql.ErrAllTablesSkipped {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -139,16 +130,13 @@ func (sg *SuperGraph) prepareStmt(item allow.Item) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sg *SuperGraph) prepare(ct context.Context, st []stmt, key string) error {
|
func (sg *SuperGraph) prepare(ct context.Context, st []stmt, key string) error {
|
||||||
finalSQL, am := processTemplate(st[0].sql)
|
sd, err := sg.db.PrepareContext(ct, st[0].sql)
|
||||||
|
|
||||||
sd, err := sg.db.Prepare(finalSQL)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("prepare failed: %v: %s", err, finalSQL)
|
return fmt.Errorf("prepare failed: %v: %s", err, st[0].sql)
|
||||||
}
|
}
|
||||||
|
|
||||||
sg.prepared[key] = &preparedItem{
|
sg.prepared[key] = &preparedItem{
|
||||||
sd: sd,
|
sd: sd,
|
||||||
args: am,
|
|
||||||
st: st[0],
|
st: st[0],
|
||||||
roleArg: len(st) > 1,
|
roleArg: len(st) > 1,
|
||||||
}
|
}
|
||||||
@ -163,10 +151,11 @@ func (sg *SuperGraph) prepareRoleStmt(tx *sql.Tx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rq := strings.ReplaceAll(sg.conf.RolesQuery, "$user_id", "$1")
|
||||||
w := &bytes.Buffer{}
|
w := &bytes.Buffer{}
|
||||||
|
|
||||||
io.WriteString(w, `SELECT (CASE WHEN EXISTS (`)
|
io.WriteString(w, `SELECT (CASE WHEN EXISTS (`)
|
||||||
io.WriteString(w, sg.conf.RolesQuery)
|
io.WriteString(w, rq)
|
||||||
io.WriteString(w, `) THEN `)
|
io.WriteString(w, `) THEN `)
|
||||||
|
|
||||||
io.WriteString(w, `(SELECT (CASE`)
|
io.WriteString(w, `(SELECT (CASE`)
|
||||||
@ -181,14 +170,12 @@ func (sg *SuperGraph) prepareRoleStmt(tx *sql.Tx) error {
|
|||||||
io.WriteString(w, `'`)
|
io.WriteString(w, `'`)
|
||||||
}
|
}
|
||||||
|
|
||||||
io.WriteString(w, ` ELSE {{role}} END) FROM (`)
|
io.WriteString(w, ` ELSE $2 END) FROM (`)
|
||||||
io.WriteString(w, sg.conf.RolesQuery)
|
io.WriteString(w, sg.conf.RolesQuery)
|
||||||
io.WriteString(w, `) AS "_sg_auth_roles_query" LIMIT 1) `)
|
io.WriteString(w, `) AS "_sg_auth_roles_query" LIMIT 1) `)
|
||||||
io.WriteString(w, `ELSE 'anon' END) FROM (VALUES (1)) AS "_sg_auth_filler" LIMIT 1; `)
|
io.WriteString(w, `ELSE 'anon' END) FROM (VALUES (1)) AS "_sg_auth_filler" LIMIT 1; `)
|
||||||
|
|
||||||
roleSQL, _ := processTemplate(w.String())
|
sg.getRole, err = tx.Prepare(w.String())
|
||||||
|
|
||||||
sg.getRole, err = tx.Prepare(roleSQL)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -196,36 +183,6 @@ func (sg *SuperGraph) prepareRoleStmt(tx *sql.Tx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processTemplate(tmpl string) (string, [][]byte) {
|
|
||||||
st := struct {
|
|
||||||
vmap map[string]int
|
|
||||||
am [][]byte
|
|
||||||
i int
|
|
||||||
}{
|
|
||||||
vmap: make(map[string]int),
|
|
||||||
am: make([][]byte, 0, 5),
|
|
||||||
i: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
execFunc := func(w io.Writer, tag string) (int, error) {
|
|
||||||
if n, ok := st.vmap[tag]; ok {
|
|
||||||
return w.Write([]byte(fmt.Sprintf("$%d", n)))
|
|
||||||
}
|
|
||||||
st.am = append(st.am, []byte(tag))
|
|
||||||
st.i++
|
|
||||||
st.vmap[tag] = st.i
|
|
||||||
return w.Write([]byte(fmt.Sprintf("$%d", st.i)))
|
|
||||||
}
|
|
||||||
|
|
||||||
t1 := fasttemplate.New(tmpl, `'{{`, `}}'`)
|
|
||||||
ts1 := t1.ExecuteFuncString(execFunc)
|
|
||||||
|
|
||||||
t2 := fasttemplate.New(ts1, `{{`, `}}`)
|
|
||||||
ts2 := t2.ExecuteFuncString(execFunc)
|
|
||||||
|
|
||||||
return ts2, st.am
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sg *SuperGraph) initAllowList() error {
|
func (sg *SuperGraph) initAllowList() error {
|
||||||
var ac allow.Config
|
var ac allow.Config
|
||||||
var err error
|
var err error
|
||||||
|
@ -21,7 +21,7 @@ func (sg *SuperGraph) execRemoteJoin(st *stmt, data []byte, hdr http.Header) ([]
|
|||||||
// fetch the field name used within the db response json
|
// fetch the field name used within the db response json
|
||||||
// that are used to mark insertion points and the mapping between
|
// that are used to mark insertion points and the mapping between
|
||||||
// those field names and their select objects
|
// those field names and their select objects
|
||||||
fids, sfmap := sg.parentFieldIds(h, sel, st.skipped)
|
fids, sfmap := sg.parentFieldIds(h, sel, st.md.Skipped)
|
||||||
|
|
||||||
// fetch the field values of the marked insertion points
|
// fetch the field values of the marked insertion points
|
||||||
// these values contain the id to be used with fetching remote data
|
// these values contain the id to be used with fetching remote data
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
01a106d5.06939d67.js,1589776216137,2e1ce67f6cf79a8a8e2070fc4ea4a6104ac73a5b26a1ab10b62f6cd8e45a8074
|
|
||||||
1.1c32171f.js.LICENSE.txt,1589776216144,31b4d50dbbd144da150dcdcf0ccef8f6cf8b6b5204d5c9adde3b24466777fad5
|
|
||||||
0e384e19.7f29b403.js,1589776216137,e2c3882226f2a601b65e4bb1fdb771296c1946f9f125c90af4a8f451dfd2c867
|
|
||||||
19.fdfbe826.js.LICENSE.txt,1589776216145,6ad95a8099127a8d42b5ace6d148064b1d3e922174f08d75d0ee2220ebeacd0b
|
|
||||||
17896441.183211f5.js,1589776216137,7736db62d7498a8d3a10a617b1bdfac08c8f29dc03329f4ad3320f2571c223c0
|
|
||||||
20ac7829.c04b4a1e.js,1589776216137,5b95f479848ccd6959630d4a24bd551d0dbc74457911e9b6f3498655bfaf8ea7
|
|
||||||
1.1c32171f.js,1589776216137,5441b74bfad9f5a37ba0e6123621c73c3e3b9064bda6b9dcf62fdb7381bf8e41
|
|
||||||
2.8f12478f.js,1589776216137,3ac7ca0df8fca86145f5decbd86c8adfbc6b5b11a5be96fc96cc9bc33d6306e6
|
|
||||||
395f47e2.28d67f37.js,1589776216137,8a9b6bc2afdd99ca2b1827c8289352fab6163e30151b9701c29a7863b6cd00b6
|
|
||||||
404.html,1589776218438,0a748eaa7614b1982623360ba8554c0f498b0796ead3cc429a2c84d287084b50
|
|
||||||
3d9c95a4.c89589de.js,1589776216137,d5c45e5a3671f303683451d448e2e5d5b464f041cde683af6e824b9e7f951412
|
|
||||||
9225b3a9.a5e6036b.js,1589776216137,ec9a0d4b34d8751f74348d0da369625a18f320c9ed5ab3c5ccf047ead2551bd8
|
|
||||||
741df2ae.e13b96b2.js,1589776216137,12028f0cbdf783ac91ea42db64d91190ebd4df24cc74162f953aacc75d16d078
|
|
||||||
969d212d.9fc45877.js,1589776216138,8323c9f2db042bfaa2ebba43d9500bed881a694d0bfc27fd796cec95bb032dc5
|
|
||||||
c4f5d8e4.47e70b85.js,1589776216145,6f986b48720724e7c8a715812b5f6625c71c8eca258bb4b410a447eb5da52734
|
|
||||||
index.html,1589776218438,89f81ec3d3be439a827bd61448dcaddb71c33422df7baa88a7bbcdf784dbc0b2
|
|
||||||
98ce8162.b5ace15d.js,1589776216137,935e1c6dd08f7e9d0d00221559b95f0f649e28ddf64be6bbb7b3e65bae1aba72
|
|
||||||
main.e30d99cd.js.LICENSE.txt,1589776216144,1d906c3b83eacffe298d21eeb73e6e73e96310983224783d236195098e6765a7
|
|
||||||
runtime~main.366c29ad.js,1589776216145,0e550cc9522cd99c5fa4097c7db629eef56127a7f8ade0b7c9954cc8f6a01239
|
|
||||||
5043549d.62508ecf.js,1589776216137,383959b80d2b0c6416e83c9640ea03c666fe92c407e13a6f022b58072feeafd2
|
|
||||||
99e04881.197dcef6.js,1589776216144,af99883cbd4d58fbac7cbf814be33032b77bc8daf856aed54bdf0bf27ed5708d
|
|
||||||
sitemap.xml,1589776218455,660ed269bf0306ba47ecdfb638e487147784d614c43c6c4a8e84194973baf183
|
|
||||||
styles.9155f1d2.js,1589776216137,f1e0863928710e67338dc88c37f47ef3ff164d36c4bba40d005561094c9c3284
|
|
||||||
db32d859.a032827a.js,1589776216145,36d575ffad747898726a97cb7a3551e636f744218595bea5c060536eb8d8390f
|
|
||||||
docs/advanced/index.html,1589776218439,31171870786a597597de9417978a27253581c013962e39959ae4c0777bf86c28
|
|
||||||
docs/deploy/index.html,1589776218440,7a4735edb93006311b704e62b843bf89bc4354fdf0fdc22a0c5802e39878c193
|
|
||||||
docs/home/index.html,1589776218440,c7fbb0c1084c6ef8858775c5083b6b416b8188942d4402a5a625eadb3bc00942
|
|
||||||
docs/intro/index.html,1589776218440,c7a50ae98c0b279f422e55c2eeb9f7ba1c7c1a8bcac07be11fd6e05ced224094
|
|
||||||
img/super-graph-logo.svg,1589776218438,66a865c4936f44ea811464b967f221b615b7553e85dca0d6f1ef620da3911857
|
|
||||||
docs/react/index.html,1589776218440,f76fc976f3491d9aacf19ce3b34bee1339f87c673a9da95f192683615618f210
|
|
||||||
docs/why/index.html,1589776218440,4aa380fe4e5d8476645e368d1f708d5d1344331c572383db823c3499fa0c99cc
|
|
||||||
docs/security/index.html,1589776218440,0c7d466dc143935db8c02a448952cae2465635e4b6782b1682449bbd56807917
|
|
||||||
styles.8ee0cad4.css,1589776216137,34b2e79c5c5b1f7afda4376e422e8ccb2c3c04213ca09d788f0c68ecf153d6e6
|
|
||||||
docs/config/index.html,1589776218440,25b6e87a42c163ac966e80acebca8708f56ae95ba8f3ed8b98ff7fd70ca5a222
|
|
||||||
docs/internals/index.html,1589776218440,b6f2136a1c832f421a46329fb1f39269d820c55a0dfc9351848271a5501d8e6e
|
|
||||||
docs/start/index.html,1589776218440,485ec2c61117d8940d8028f34d51d421995a814d5b9d4d5a1870adaed48aec2c
|
|
||||||
docs/graphql/index.html,1589776218440,3bd79f703fe67656884f3121bfddc3a4fc4d9e5bb2bf9271c94014058fbbd806
|
|
||||||
main.e30d99cd.js,1589776216144,98a4087d6f537aaddbc1225aaabfb4d12d1394772deb618d4d457685cee59311
|
|
||||||
19.fdfbe826.js,1589776216144,b8abb73aea5fc0aa50d7e8b8bd38984e3b3aec62de2faf66fb3e55fd1428f8a7
|
|
||||||
server.bundle.js,1589776218438,826db37f1de931e8b088c1ff20b4a3c2fe0c3d54d9ff4020e500f0df1b83a616
|
|
@ -157,7 +157,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
res, err := sg.GraphQL(context.Background(), query, nil)
|
ctx = context.WithValue(ctx, core.UserIDKey, 1)
|
||||||
|
|
||||||
|
res, err := sg.GraphQL(ctx, query, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ Super Graph has a rich feature set like integrating with your existing Ruby on R
|
|||||||
- Fuzz tested for security
|
- Fuzz tested for security
|
||||||
- Database migrations tool
|
- Database migrations tool
|
||||||
- Database seeding tool
|
- Database seeding tool
|
||||||
|
- Works with Postgres and Yugabyte DB
|
||||||
|
- OpenCensus Support: Zipkin, Prometheus, X-Ray, Stackdriver
|
||||||
|
|
||||||
## Try the demo app
|
## Try the demo app
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ You can then add your database schema to the migrations, maybe create some seed
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Download and install Super Graph. You will need Go 1.14 or above
|
# Download and install Super Graph. You will need Go 1.14 or above
|
||||||
go get https://github.com/dosco/super-graph
|
go get github.com/dosco/super-graph
|
||||||
```
|
```
|
||||||
|
|
||||||
And then create and launch your new app
|
And then create and launch your new app
|
||||||
|
82
docs/website/docs/telemetry.md
Normal file
82
docs/website/docs/telemetry.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
---
|
||||||
|
id: telemetry
|
||||||
|
title: Tracing and Metrics
|
||||||
|
sidebar_label: Telemetry
|
||||||
|
---
|
||||||
|
|
||||||
|
import useBaseUrl from '@docusaurus/useBaseUrl'; // Add to the top of the file below the front matter.
|
||||||
|
|
||||||
|
Having observability and telemetry is at the core of any production ready service. Super Graph has built-in support for OpenCensus for tracing requests all the way from HTTP to the database and providing all kinds of metrics.
|
||||||
|
|
||||||
|
OpenCensus has a concept called exporters these are external services that can consume this data and make to give you graphs, charts, alerting etc. Super Graph again has built-in support for Zipkin, Prometheus, Google Stackdriver and the AWS X-Ray exporters.
|
||||||
|
|
||||||
|
## Telemetry config
|
||||||
|
|
||||||
|
The `telemetry` section of the standard config files is where you set values to configure this feature to your needs.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
telemetry:
|
||||||
|
debug: true
|
||||||
|
interval: 5s
|
||||||
|
metrics:
|
||||||
|
exporter: "prometheus"
|
||||||
|
endpoint: ""
|
||||||
|
namespace: "web api"
|
||||||
|
key: "1234xyz"
|
||||||
|
tracing:
|
||||||
|
exporter: "zipkin"
|
||||||
|
endpoint: "http://zipkin:9411/api/v2/spans"
|
||||||
|
sample: 0.2
|
||||||
|
include_query: false
|
||||||
|
include_params: false
|
||||||
|
```
|
||||||
|
|
||||||
|
**debug**: Enabling debug enables an embedded web ui to test and debug tracing and metrics. This UI called `zPages` is provided by OpenCensus and will be made available on the `/telemetry` path. For more information on using `zPages` https://opencensus.io/zpages/. Remeber to disable this in production.
|
||||||
|
|
||||||
|
**interval**: This controls the interval setting for OpenCensus metrics collection. This deafaults to `5 seconds` if not set.
|
||||||
|
|
||||||
|
**metric.exporters** Setting this enables metrics collection. The supported values for this field are `prometheus` and `stackdriver`. The Prometheus exporter requires `metric.namespace` to be set. The Sackdriver exporter requires the `metric.key` to be set to the Google Cloud Project ID.
|
||||||
|
|
||||||
|
**metric.endpoint** Is not currently used by any of the exporters.
|
||||||
|
|
||||||
|
**tracing.exporter** Setting this enables request tracing. The supported values for this field are `zipkin`, `aws` and `xray`. Zipkin requires `tracing.endpoint` to be set. AWS and Xray are the same and do not require any addiitonal settings.
|
||||||
|
|
||||||
|
**tracing.sample** This controls what percentage of the requests should be traced. By default `0.5` or 50% of the requests are traced, `always` is also a valid value for this field and it means all requests will be traced.
|
||||||
|
|
||||||
|
**include_query** Include the Super Graph SQL query to the trace. Be careful with this setting in production it will add the entire SQL query to the trace. This can be veru useful to debug slow requests.
|
||||||
|
|
||||||
|
**include_params** Include the Super Graph SQL query parameters to the trace. Be careful with this setting in production it will it can potentially leak sensitive user information into tracing logs.
|
||||||
|
|
||||||
|
## Using Zipkin
|
||||||
|
|
||||||
|
Zipkin is a really great open source request tracing project. It's easy to add to your current Super Graph app as a way to test tracing in development. Add the following to the Super Graph generated `docker-compose.yml` file. Also add `zipkin` in your current apps `depends_on` list. Once setup the Zipkin UI is available at http://localhost:9411
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
your_api:
|
||||||
|
...
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- zipkin
|
||||||
|
|
||||||
|
zipkin:
|
||||||
|
image: openzipkin/zipkin-slim
|
||||||
|
container_name: zipkin
|
||||||
|
# Environment settings are defined here https://github.com/openzipkin/zipkin/blob/master/zipkin-server/README.md#environment-variables
|
||||||
|
environment:
|
||||||
|
- STORAGE_TYPE=mem
|
||||||
|
# Uncomment to enable self-tracing
|
||||||
|
# - SELF_TRACING_ENABLED=true
|
||||||
|
# Uncomment to enable debug logging
|
||||||
|
# - JAVA_OPTS=-Dorg.slf4j.simpleLogger.log.zipkin2=debug
|
||||||
|
ports:
|
||||||
|
# Port used for the Zipkin UI and HTTP Api
|
||||||
|
- 9411:9411
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zipkin HTTP to DB traces
|
||||||
|
|
||||||
|
<img alt="Zipkin Traces" src={useBaseUrl("img/zipkin1.png")} />
|
||||||
|
|
||||||
|
### Zipkin trace details
|
||||||
|
|
||||||
|
<img alt="Zipkin Traces" src={useBaseUrl('img/zipkin2.png')} />
|
@ -9,6 +9,7 @@ module.exports = {
|
|||||||
"react",
|
"react",
|
||||||
"advanced",
|
"advanced",
|
||||||
"security",
|
"security",
|
||||||
|
"telemetry",
|
||||||
"config",
|
"config",
|
||||||
"deploy",
|
"deploy",
|
||||||
"internals",
|
"internals",
|
||||||
|
BIN
docs/website/static/img/zipkin1.png
Normal file
BIN
docs/website/static/img/zipkin1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 112 KiB |
BIN
docs/website/static/img/zipkin2.png
Normal file
BIN
docs/website/static/img/zipkin2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
8
go.mod
8
go.mod
@ -1,6 +1,11 @@
|
|||||||
module github.com/dosco/super-graph
|
module github.com/dosco/super-graph
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
contrib.go.opencensus.io/exporter/aws v0.0.0-20190807220307-c50fb1bd7f21
|
||||||
|
contrib.go.opencensus.io/exporter/prometheus v0.1.0
|
||||||
|
contrib.go.opencensus.io/exporter/stackdriver v0.13.1
|
||||||
|
contrib.go.opencensus.io/exporter/zipkin v0.1.1
|
||||||
|
contrib.go.opencensus.io/integrations/ocsql v0.1.6
|
||||||
github.com/DATA-DOG/go-sqlmock v1.4.1
|
github.com/DATA-DOG/go-sqlmock v1.4.1
|
||||||
github.com/GeertJohan/go.rice v1.0.0
|
github.com/GeertJohan/go.rice v1.0.0
|
||||||
github.com/NYTimes/gziphandler v1.1.1
|
github.com/NYTimes/gziphandler v1.1.1
|
||||||
@ -21,6 +26,7 @@ require (
|
|||||||
github.com/jackc/pgtype v1.3.0
|
github.com/jackc/pgtype v1.3.0
|
||||||
github.com/jackc/pgx/v4 v4.6.0
|
github.com/jackc/pgx/v4 v4.6.0
|
||||||
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
github.com/mitchellh/mapstructure v1.2.2 // indirect
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.2
|
||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
@ -31,7 +37,7 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.6.3
|
github.com/spf13/viper v1.6.3
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
github.com/valyala/fasttemplate v1.1.0
|
go.opencensus.io v0.22.3
|
||||||
go.uber.org/zap v1.14.1
|
go.uber.org/zap v1.14.1
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
|
||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect
|
||||||
|
173
go.sum
173
go.sum
@ -1,6 +1,25 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
|
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||||
|
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||||
|
cloud.google.com/go v0.45.1 h1:lRi0CHyU+ytlvylOlFKKq0af6JncuyoRh1J+QJBqQx0=
|
||||||
|
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||||
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
|
contrib.go.opencensus.io/exporter/aws v0.0.0-20190807220307-c50fb1bd7f21 h1:H3O7Pfgex4O08w1PyXje7lhiRbPNd687lz48jfWWB1s=
|
||||||
|
contrib.go.opencensus.io/exporter/aws v0.0.0-20190807220307-c50fb1bd7f21/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
|
||||||
|
contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg=
|
||||||
|
contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=
|
||||||
|
contrib.go.opencensus.io/exporter/stackdriver v0.13.1 h1:RX9W6FelAqTVnBi/bRXJLXr9n18v4QkQwZYIdnNS51I=
|
||||||
|
contrib.go.opencensus.io/exporter/stackdriver v0.13.1/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c=
|
||||||
|
contrib.go.opencensus.io/exporter/zipkin v0.1.1 h1:PR+1zWqY8ceXs1qDQQIlgXe+sdiwCf0n32bH4+Epk8g=
|
||||||
|
contrib.go.opencensus.io/exporter/zipkin v0.1.1/go.mod h1:GMvdSl3eJ2gapOaLKzTKE3qDgUkJ86k9k3yY2eqwkzc=
|
||||||
|
contrib.go.opencensus.io/integrations/ocsql v0.1.6 h1:9qmZJBlnMtffShflmfhW4EZK7M+CujIDG4bEwUrg+ms=
|
||||||
|
contrib.go.opencensus.io/integrations/ocsql v0.1.6/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
|
||||||
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/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
|
github.com/DATA-DOG/go-sqlmock v1.4.1 h1:ThlnYciV1iM/V0OSF/dtkqWb6xo5qITT1TJBG1MRDJM=
|
||||||
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
github.com/DATA-DOG/go-sqlmock v1.4.1/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
|
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
|
||||||
@ -10,6 +29,8 @@ github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtix
|
|||||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
||||||
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
||||||
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/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
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 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
|
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
|
||||||
@ -17,12 +38,19 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK
|
|||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
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/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/aws/aws-sdk-go v1.15.27 h1:i75BxN4Es/8rTVQbEKAP1WCiIhhz635xTNeDdZJRAXQ=
|
||||||
|
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||||
|
github.com/aws/aws-sdk-go v1.23.20 h1:2CBuL21P0yKdZN5urf2NxKa1ha8fhnY+A3pBCHFeZoA=
|
||||||
|
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0=
|
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/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
|
||||||
github.com/brianvoe/gofakeit/v5 v5.2.0 h1:De9X+2PQum9U2zCaIDxLV7wx0YBL6c7RN2sFBImzHGI=
|
github.com/brianvoe/gofakeit/v5 v5.2.0 h1:De9X+2PQum9U2zCaIDxLV7wx0YBL6c7RN2sFBImzHGI=
|
||||||
github.com/brianvoe/gofakeit/v5 v5.2.0/go.mod h1:/ZENnKqX+XrN8SORLe/fu5lZDIo1tuPncWuRD+eyhSI=
|
github.com/brianvoe/gofakeit/v5 v5.2.0/go.mod h1:/ZENnKqX+XrN8SORLe/fu5lZDIo1tuPncWuRD+eyhSI=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
||||||
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
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 v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||||
@ -57,6 +85,10 @@ 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-20200424152103-d0b8fda54cd0 h1:EfFAcaAwGai/wlDCWwIObHBm3T2C2CCPX/SaS0fpOJ4=
|
github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0 h1:EfFAcaAwGai/wlDCWwIObHBm3T2C2CCPX/SaS0fpOJ4=
|
||||||
github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
github.com/dop251/goja v0.0.0-20200424152103-d0b8fda54cd0/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
||||||
|
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||||
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
|
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
|
||||||
github.com/friendsofgo/graphiql v0.2.2/go.mod h1:8Y2kZ36AoTGWs78+VRpvATyt3LJBx0SZXmay80ZTRWo=
|
github.com/friendsofgo/graphiql v0.2.2/go.mod h1:8Y2kZ36AoTGWs78+VRpvATyt3LJBx0SZXmay80ZTRWo=
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||||
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=
|
||||||
@ -65,6 +97,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
|
|||||||
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo=
|
||||||
|
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
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.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
@ -75,19 +109,45 @@ github.com/gobuffalo/flect v0.2.1 h1:GPoRjEN0QObosV4XwuoWvSd5uSiL0N3e91/xqyY4crQ
|
|||||||
github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
|
github.com/gobuffalo/flect v0.2.1/go.mod h1:vmkQwuZYhN5Pc4ljYQZzP+1sq+NEkK+lh20jmEmX3jc=
|
||||||
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/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
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/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
|
||||||
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||||
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
|
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
|
||||||
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
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.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
@ -96,8 +156,11 @@ github.com/gosimple/slug v1.9.0/go.mod h1:AMZ+sOVe65uByN3kgEyf9WEBKBCSS+dJjMX9x4
|
|||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
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/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/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
|
||||||
@ -144,8 +207,13 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
|||||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||||
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/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
@ -164,6 +232,7 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||||||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
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/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
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 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
@ -176,6 +245,7 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||||||
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 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||||
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 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
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=
|
||||||
@ -189,30 +259,47 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
|||||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
||||||
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/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.2 h1:nY8Hti+WKaP0cRsSeQ026wU03QsM762XBeCXBb9NAWI=
|
||||||
|
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
|
||||||
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.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||||
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0/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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||||
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.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||||
|
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
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-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
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.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
|
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
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-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
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/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHVHGom5hKW5VXNc2xZIkfCKP8iaqOyYtUQ=
|
||||||
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
@ -261,6 +348,7 @@ 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/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
|
github.com/spf13/viper v1.6.3 h1:pDDu1OyEDTKzpJwdq4TiuLyMsUgRa/BT5cn5O62NoHs=
|
||||||
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw=
|
||||||
|
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
|
||||||
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=
|
||||||
@ -285,12 +373,16 @@ github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6Kllzaw
|
|||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
|
||||||
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/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4=
|
|
||||||
github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
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.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0=
|
||||||
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
|
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
||||||
|
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
||||||
|
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||||
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/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
|
||||||
@ -309,43 +401,74 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90Pveol
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 h1:bXoxMPcSLOq08zI3/c5dEBT6lE4eh+jOh886GHrn6V8=
|
||||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||||
|
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/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/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||||
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/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/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/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/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/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-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-20180909124046-d0be0721c37e/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-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-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/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=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
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=
|
||||||
@ -354,17 +477,29 @@ golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HX
|
|||||||
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/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.1-0.20180807135948-17ff2d5776d2/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-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
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-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
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-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
|
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||||
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/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@ -377,10 +512,37 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||||
|
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||||
|
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
|
google.golang.org/api v0.10.0 h1:7tmAxx3oKE98VMZ+SBZzvYYWRQ9HODBxmC8mXUsraSQ=
|
||||||
|
google.golang.org/api v0.10.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
|
google.golang.org/appengine v1.6.2 h1:j8RI1yW0SkI+paT6uGwMlrMI/6zwYA6/CFil8rxOzGI=
|
||||||
|
google.golang.org/appengine v1.6.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY=
|
||||||
|
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||||
|
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 h1:Ex1mq5jaJof+kRnYi3SlYJ8KKa9Ao3NHyIT5XJ1gF6U=
|
||||||
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
|
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
|
||||||
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
|
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
|
||||||
|
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
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=
|
||||||
@ -389,12 +551,14 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ=
|
||||||
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
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.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=
|
||||||
@ -402,7 +566,12 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099 h1:XJP7lxbSxWLOMNdBE4B/STaqVy6L73o0knwj2vIlxnw=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099 h1:XJP7lxbSxWLOMNdBE4B/STaqVy6L73o0knwj2vIlxnw=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
|
@ -24,8 +24,10 @@ type Config struct {
|
|||||||
Core `mapstructure:",squash"`
|
Core `mapstructure:",squash"`
|
||||||
Serv `mapstructure:",squash"`
|
Serv `mapstructure:",squash"`
|
||||||
|
|
||||||
cpath string
|
closeFn func()
|
||||||
vi *viper.Viper
|
hostPort string
|
||||||
|
cpath string
|
||||||
|
vi *viper.Viper
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serv struct contains config values used by the Super Graph service
|
// Serv struct contains config values used by the Super Graph service
|
||||||
@ -48,9 +50,30 @@ type Serv struct {
|
|||||||
APIPath string `mapstructure:"api_path"`
|
APIPath string `mapstructure:"api_path"`
|
||||||
CacheControl string `mapstructure:"cache_control"`
|
CacheControl string `mapstructure:"cache_control"`
|
||||||
|
|
||||||
|
// Telemetry struct contains OpenCensus metrics and tracing related config
|
||||||
|
Telemetry struct {
|
||||||
|
Debug bool
|
||||||
|
Interval *time.Duration
|
||||||
|
Metrics struct {
|
||||||
|
Exporter string
|
||||||
|
Endpoint string
|
||||||
|
Namespace string
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
Tracing struct {
|
||||||
|
Exporter string
|
||||||
|
Endpoint string
|
||||||
|
Sample string
|
||||||
|
IncludeQuery bool `mapstructure:"include_query"`
|
||||||
|
IncludeParams bool `mapstructure:"include_params"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Auth auth.Auth
|
Auth auth.Auth
|
||||||
Auths []auth.Auth
|
Auths []auth.Auth
|
||||||
|
|
||||||
|
// DB struct contains db config
|
||||||
DB struct {
|
DB struct {
|
||||||
Type string
|
Type string
|
||||||
Host string
|
Host string
|
||||||
|
@ -19,8 +19,8 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// These variables are set using -ldflags
|
// These variables are set using -ldflags
|
||||||
version string
|
version string = "unknown"
|
||||||
gitBranch string
|
gitBranch string = "unknown"
|
||||||
lastCommitSHA string
|
lastCommitSHA string
|
||||||
lastCommitTime string
|
lastCommitTime string
|
||||||
)
|
)
|
||||||
|
@ -55,7 +55,7 @@ func cmdDBReset(cmd *cobra.Command, args []string) {
|
|||||||
func cmdDBCreate(cmd *cobra.Command, args []string) {
|
func cmdDBCreate(cmd *cobra.Command, args []string) {
|
||||||
initConfOnce()
|
initConfOnce()
|
||||||
|
|
||||||
db, err := initDB(conf, false)
|
db, err := initDB(conf, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERR failed to connect to database: %s", err)
|
log.Fatalf("ERR failed to connect to database: %s", err)
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ func cmdDBCreate(cmd *cobra.Command, args []string) {
|
|||||||
func cmdDBDrop(cmd *cobra.Command, args []string) {
|
func cmdDBDrop(cmd *cobra.Command, args []string) {
|
||||||
initConfOnce()
|
initConfOnce()
|
||||||
|
|
||||||
db, err := initDB(conf, false)
|
db, err := initDB(conf, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERR failed to connect to database: %s", err)
|
log.Fatalf("ERR failed to connect to database: %s", err)
|
||||||
}
|
}
|
||||||
@ -132,7 +132,7 @@ func cmdDBMigrate(cmd *cobra.Command, args []string) {
|
|||||||
initConfOnce()
|
initConfOnce()
|
||||||
dest := args[0]
|
dest := args[0]
|
||||||
|
|
||||||
conn, err := initDB(conf, true)
|
conn, err := initDB(conf, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERR failed to connect to database: %s", err)
|
log.Fatalf("ERR failed to connect to database: %s", err)
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ func cmdDBMigrate(cmd *cobra.Command, args []string) {
|
|||||||
func cmdDBStatus(cmd *cobra.Command, args []string) {
|
func cmdDBStatus(cmd *cobra.Command, args []string) {
|
||||||
initConfOnce()
|
initConfOnce()
|
||||||
|
|
||||||
db, err := initDB(conf, true)
|
db, err := initDB(conf, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERR failed to connect to database: %s", err)
|
log.Fatalf("ERR failed to connect to database: %s", err)
|
||||||
}
|
}
|
||||||
@ -298,9 +298,9 @@ func ExtractErrorLine(source string, position int) (ErrorLineExtract, error) {
|
|||||||
|
|
||||||
func getMigrationVars() map[string]interface{} {
|
func getMigrationVars() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"app_name": strings.Title(conf.AppName),
|
"AppName": strings.Title(conf.AppName),
|
||||||
"app_name_slug": strings.ToLower(strings.Replace(conf.AppName, " ", "_", -1)),
|
"AppNameSlug": strings.ToLower(strings.Replace(conf.AppName, " ", "_", -1)),
|
||||||
"env": strings.ToLower(os.Getenv("GO_ENV")),
|
"Env": strings.ToLower(os.Getenv("GO_ENV")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ package serv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"html/template"
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -11,7 +10,6 @@ import (
|
|||||||
|
|
||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/valyala/fasttemplate"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func cmdNew(cmd *cobra.Command, args []string) {
|
func cmdNew(cmd *cobra.Command, args []string) {
|
||||||
@ -21,8 +19,8 @@ func cmdNew(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tmpl := newTempl(map[string]string{
|
tmpl := newTempl(map[string]string{
|
||||||
"app_name": strings.Title(strings.Join(args, " ")),
|
"AppName": strings.Title(strings.Join(args, " ")),
|
||||||
"app_name_slug": strings.ToLower(strings.Join(args, "_")),
|
"AppNameSlug": strings.ToLower(strings.Join(args, "_")),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create app folder and add relevant files
|
// Create app folder and add relevant files
|
||||||
@ -121,19 +119,16 @@ func newTempl(data map[string]string) *Templ {
|
|||||||
func (t *Templ) get(name string) ([]byte, error) {
|
func (t *Templ) get(name string) ([]byte, error) {
|
||||||
v := t.MustString(name)
|
v := t.MustString(name)
|
||||||
b := bytes.Buffer{}
|
b := bytes.Buffer{}
|
||||||
tmpl := fasttemplate.New(v, "{%", "%}")
|
|
||||||
|
|
||||||
_, err := tmpl.ExecuteFunc(&b, func(w io.Writer, tag string) (int, error) {
|
|
||||||
if val, ok := t.data[strings.TrimSpace(tag)]; ok {
|
|
||||||
return w.Write([]byte(val))
|
|
||||||
}
|
|
||||||
return 0, fmt.Errorf("unknown template variable '%s'", tag)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
tmpl, err := template.New(name).Parse(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := tmpl.Execute(&b, t.data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,10 +26,9 @@ func cmdDBSeed(cmd *cobra.Command, args []string) {
|
|||||||
if conf, err = initConf(); err != nil {
|
if conf, err = initConf(); err != nil {
|
||||||
log.Fatalf("ERR failed to read config: %s", err)
|
log.Fatalf("ERR failed to read config: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
conf.Production = false
|
conf.Production = false
|
||||||
|
|
||||||
db, err = initDB(conf, true)
|
db, err = initDB(conf, true, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERR failed to connect to database: %s", err)
|
log.Fatalf("ERR failed to connect to database: %s", err)
|
||||||
}
|
}
|
||||||
@ -80,6 +79,8 @@ func graphQLFunc(sg *core.SuperGraph, query string, data interface{}, opt map[st
|
|||||||
|
|
||||||
if v, ok := opt["user_id"]; ok && len(v) != 0 {
|
if v, ok := opt["user_id"]; ok && len(v) != 0 {
|
||||||
ct = context.WithValue(ct, core.UserIDKey, v)
|
ct = context.WithValue(ct, core.UserIDKey, v)
|
||||||
|
} else {
|
||||||
|
ct = context.WithValue(ct, core.UserIDKey, "-1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// var role string
|
// var role string
|
||||||
@ -349,7 +350,6 @@ func setFakeFuncs(f *goja.Object) {
|
|||||||
f.Set("credit_card", gofakeit.CreditCard)
|
f.Set("credit_card", gofakeit.CreditCard)
|
||||||
f.Set("credit_card_cvv", gofakeit.CreditCardCvv)
|
f.Set("credit_card_cvv", gofakeit.CreditCardCvv)
|
||||||
f.Set("credit_card_number", gofakeit.CreditCardNumber)
|
f.Set("credit_card_number", gofakeit.CreditCardNumber)
|
||||||
f.Set("credit_card_number_luhn", gofakeit.CreditCardNumberLuhn)
|
|
||||||
f.Set("credit_card_type", gofakeit.CreditCardType)
|
f.Set("credit_card_type", gofakeit.CreditCardType)
|
||||||
f.Set("currency", gofakeit.Currency)
|
f.Set("currency", gofakeit.Currency)
|
||||||
f.Set("currency_long", gofakeit.CurrencyLong)
|
f.Set("currency_long", gofakeit.CurrencyLong)
|
||||||
@ -368,7 +368,6 @@ func setFakeFuncs(f *goja.Object) {
|
|||||||
// Hacker
|
// Hacker
|
||||||
f.Set("hacker_abbreviation", gofakeit.HackerAbbreviation)
|
f.Set("hacker_abbreviation", gofakeit.HackerAbbreviation)
|
||||||
f.Set("hacker_adjective", gofakeit.HackerAdjective)
|
f.Set("hacker_adjective", gofakeit.HackerAdjective)
|
||||||
f.Set("hacker_ingverb", gofakeit.HackerIngverb)
|
|
||||||
f.Set("hacker_noun", gofakeit.HackerNoun)
|
f.Set("hacker_noun", gofakeit.HackerNoun)
|
||||||
f.Set("hacker_phrase", gofakeit.HackerPhrase)
|
f.Set("hacker_phrase", gofakeit.HackerPhrase)
|
||||||
f.Set("hacker_verb", gofakeit.HackerVerb)
|
f.Set("hacker_verb", gofakeit.HackerVerb)
|
||||||
|
@ -19,7 +19,7 @@ func cmdServ(cmd *cobra.Command, args []string) {
|
|||||||
|
|
||||||
initWatcher()
|
initWatcher()
|
||||||
|
|
||||||
db, err = initDB(conf, true)
|
db, err = initDB(conf, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fatalInProd(err, "failed to connect to database")
|
fatalInProd(err, "failed to connect to database")
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,10 @@ func GetConfigName() string {
|
|||||||
return ge
|
return ge
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Config) telemetryEnabled() bool {
|
||||||
|
return c.Telemetry.Debug || c.Telemetry.Metrics.Exporter != "" || c.Telemetry.Tracing.Exporter != ""
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Config) relPath(p string) string {
|
func (c *Config) relPath(p string) string {
|
||||||
if filepath.IsAbs(p) {
|
if filepath.IsAbs(p) {
|
||||||
return p
|
return p
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package serv
|
|
||||||
|
|
||||||
// func (c *coreContext) handleReq(w io.Writer, req *http.Request) error {
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
|
|
||||||
// }
|
|
@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
var healthyResponse = []byte("All's Well")
|
var healthyResponse = []byte("All's Well")
|
||||||
|
|
||||||
func health(w http.ResponseWriter, _ *http.Request) {
|
func health(w http.ResponseWriter, r *http.Request) {
|
||||||
ct, cancel := context.WithTimeout(context.Background(), conf.DB.PingTimeout)
|
ct, cancel := context.WithTimeout(r.Context(), conf.DB.PingTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
if err := db.PingContext(ct); err != nil {
|
if err := db.PingContext(ct); err != nil {
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/dosco/super-graph/core"
|
"github.com/dosco/super-graph/core"
|
||||||
"github.com/dosco/super-graph/internal/serv/internal/auth"
|
"github.com/dosco/super-graph/internal/serv/internal/auth"
|
||||||
"github.com/rs/cors"
|
"github.com/rs/cors"
|
||||||
|
"go.opencensus.io/plugin/ochttp"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,7 +46,7 @@ func apiV1Handler() http.Handler {
|
|||||||
AllowCredentials: true,
|
AllowCredentials: true,
|
||||||
Debug: conf.DebugCORS,
|
Debug: conf.DebugCORS,
|
||||||
})
|
})
|
||||||
h = c.Handler(h)
|
return c.Handler(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
return h
|
return h
|
||||||
@ -78,6 +80,22 @@ func apiV1(w http.ResponseWriter, r *http.Request) {
|
|||||||
doLog := true
|
doLog := true
|
||||||
res, err := sg.GraphQL(ct, req.Query, req.Vars)
|
res, err := sg.GraphQL(ct, req.Query, req.Vars)
|
||||||
|
|
||||||
|
if conf.telemetryEnabled() {
|
||||||
|
span := trace.FromContext(ct)
|
||||||
|
|
||||||
|
span.AddAttributes(
|
||||||
|
trace.StringAttribute("operation", res.OperationName()),
|
||||||
|
trace.StringAttribute("query_name", res.QueryName()),
|
||||||
|
trace.StringAttribute("role", res.Role()),
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
span.AddAttributes(trace.StringAttribute("error", err.Error()))
|
||||||
|
}
|
||||||
|
|
||||||
|
ochttp.SetRoute(ct, apiRoute)
|
||||||
|
}
|
||||||
|
|
||||||
if !conf.Production && res.QueryName() == introspectionQuery {
|
if !conf.Production && res.QueryName() == introspectionQuery {
|
||||||
doLog = false
|
doLog = false
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"contrib.go.opencensus.io/integrations/ocsql"
|
||||||
"github.com/jackc/pgx/v4"
|
"github.com/jackc/pgx/v4"
|
||||||
"github.com/jackc/pgx/v4/stdlib"
|
"github.com/jackc/pgx/v4/stdlib"
|
||||||
//_ "github.com/jackc/pgx/v4/stdlib"
|
//_ "github.com/jackc/pgx/v4/stdlib"
|
||||||
@ -110,13 +111,10 @@ func initConf() (*Config, error) {
|
|||||||
c.UseAllowList = true
|
c.UseAllowList = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// In anon role block all tables that are not defined in the role
|
|
||||||
c.DefaultBlock = true
|
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDB(c *Config, useDB bool) (*sql.DB, error) {
|
func initDB(c *Config, useDB, useTelemetry bool) (*sql.DB, error) {
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@ -210,16 +208,56 @@ func initDB(c *Config, useDB bool) (*sql.DB, error) {
|
|||||||
// config.MaxConns = conf.DB.PoolSize
|
// config.MaxConns = conf.DB.PoolSize
|
||||||
// }
|
// }
|
||||||
|
|
||||||
for i := 1; i < 10; i++ {
|
connString := stdlib.RegisterConnConfig(config)
|
||||||
db = stdlib.OpenDB(*config)
|
driverName := "pgx"
|
||||||
if db == nil {
|
// if db = stdlib.OpenDB(*config); db == nil {
|
||||||
break
|
// return errors.New("failed to open db")
|
||||||
|
// }
|
||||||
|
|
||||||
|
if useTelemetry && conf.telemetryEnabled() {
|
||||||
|
opts := ocsql.TraceOptions{
|
||||||
|
AllowRoot: true,
|
||||||
|
Ping: true,
|
||||||
|
RowsNext: true,
|
||||||
|
RowsClose: true,
|
||||||
|
RowsAffected: true,
|
||||||
|
LastInsertID: true,
|
||||||
|
Query: conf.Telemetry.Tracing.IncludeQuery,
|
||||||
|
QueryParams: conf.Telemetry.Tracing.IncludeParams,
|
||||||
}
|
}
|
||||||
|
opt := ocsql.WithOptions(opts)
|
||||||
|
name := ocsql.WithInstanceName(conf.AppName)
|
||||||
|
|
||||||
|
driverName, err = ocsql.Register(driverName, opt, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to register ocsql driver: %v", err)
|
||||||
|
}
|
||||||
|
ocsql.RegisterAllViews()
|
||||||
|
|
||||||
|
var interval time.Duration
|
||||||
|
|
||||||
|
if conf.Telemetry.Interval != nil {
|
||||||
|
interval = *conf.Telemetry.Interval
|
||||||
|
} else {
|
||||||
|
interval = 5 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
defer ocsql.RecordStats(db, interval)()
|
||||||
|
|
||||||
|
log.Println("INF OpenCensus telemetry enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < 10; i++ {
|
||||||
|
db, err = sql.Open(driverName, connString)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
time.Sleep(time.Duration(i*100) * time.Millisecond)
|
time.Sleep(time.Duration(i*100) * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("unable to open db connection: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
|
File diff suppressed because one or more lines are too long
@ -13,6 +13,11 @@ import (
|
|||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
"github.com/dosco/super-graph/internal/serv/internal/auth"
|
"github.com/dosco/super-graph/internal/serv/internal/auth"
|
||||||
|
"go.opencensus.io/plugin/ochttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
apiRoute string = "/api/v1/graphql"
|
||||||
)
|
)
|
||||||
|
|
||||||
func initWatcher() {
|
func initWatcher() {
|
||||||
@ -37,7 +42,6 @@ func initWatcher() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func startHTTP() {
|
func startHTTP() {
|
||||||
var hostPort string
|
|
||||||
var appName string
|
var appName string
|
||||||
|
|
||||||
defaultHP := "0.0.0.0:8080"
|
defaultHP := "0.0.0.0:8080"
|
||||||
@ -56,12 +60,12 @@ func startHTTP() {
|
|||||||
hp[1] = conf.Port
|
hp[1] = conf.Port
|
||||||
}
|
}
|
||||||
|
|
||||||
hostPort = fmt.Sprintf("%s:%s", hp[0], hp[1])
|
conf.hostPort = fmt.Sprintf("%s:%s", hp[0], hp[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hostPort) == 0 {
|
if len(conf.hostPort) == 0 {
|
||||||
hostPort = defaultHP
|
conf.hostPort = defaultHP
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, err := routeHandler()
|
routes, err := routeHandler()
|
||||||
@ -70,13 +74,17 @@ func startHTTP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: hostPort,
|
Addr: conf.hostPort,
|
||||||
Handler: routes,
|
Handler: routes,
|
||||||
ReadTimeout: 5 * time.Second,
|
ReadTimeout: 5 * time.Second,
|
||||||
WriteTimeout: 10 * time.Second,
|
WriteTimeout: 10 * time.Second,
|
||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.telemetryEnabled() {
|
||||||
|
srv.Handler = &ochttp.Handler{Handler: routes}
|
||||||
|
}
|
||||||
|
|
||||||
idleConnsClosed := make(chan struct{})
|
idleConnsClosed := make(chan struct{})
|
||||||
go func() {
|
go func() {
|
||||||
sigint := make(chan os.Signal, 1)
|
sigint := make(chan os.Signal, 1)
|
||||||
@ -90,13 +98,15 @@ func startHTTP() {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
srv.RegisterOnShutdown(func() {
|
srv.RegisterOnShutdown(func() {
|
||||||
|
if conf.closeFn != nil {
|
||||||
|
conf.closeFn()
|
||||||
|
}
|
||||||
db.Close()
|
db.Close()
|
||||||
|
log.Fatalln("INF shutdown complete")
|
||||||
})
|
})
|
||||||
|
|
||||||
log.Printf("INF version: %s, git-branch: %s, host-port: %s, app-name: %s, env: %s\n",
|
log.Printf("INF Super Graph started, version: %s, git-branch: %s, host-port: %s, app-name: %s, env: %s\n",
|
||||||
version, gitBranch, hostPort, appName, env)
|
version, gitBranch, conf.hostPort, appName, env)
|
||||||
|
|
||||||
log.Printf("INF %s started\n", serverName)
|
|
||||||
|
|
||||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||||
log.Fatalln("INF server closed")
|
log.Fatalln("INF server closed")
|
||||||
@ -106,14 +116,13 @@ func startHTTP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func routeHandler() (http.Handler, error) {
|
func routeHandler() (http.Handler, error) {
|
||||||
|
var err error
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
if conf == nil {
|
if conf == nil {
|
||||||
return mux, nil
|
return mux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
apiRoute := "/api/v1/graphql"
|
|
||||||
|
|
||||||
if len(conf.APIPath) != 0 {
|
if len(conf.APIPath) != 0 {
|
||||||
apiRoute = path.Join("/", conf.APIPath, "/v1/graphql")
|
apiRoute = path.Join("/", conf.APIPath, "/v1/graphql")
|
||||||
}
|
}
|
||||||
@ -142,6 +151,13 @@ func routeHandler() (http.Handler, error) {
|
|||||||
mux.Handle(k, v)
|
mux.Handle(k, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.telemetryEnabled() {
|
||||||
|
conf.closeFn, err = enableObservability(mux)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Server", serverName)
|
w.Header().Set("Server", serverName)
|
||||||
mux.ServeHTTP(w, r)
|
mux.ServeHTTP(w, r)
|
||||||
@ -169,6 +185,10 @@ func setActionRoutes(routes map[string]http.Handler) error {
|
|||||||
routes[p] = fn
|
routes[p] = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.telemetryEnabled() {
|
||||||
|
routes[p] = ochttp.WithRouteTag(routes[p], p)
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
141
internal/serv/telemetry.go
Normal file
141
internal/serv/telemetry.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package serv
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"contrib.go.opencensus.io/exporter/aws"
|
||||||
|
"contrib.go.opencensus.io/exporter/prometheus"
|
||||||
|
"contrib.go.opencensus.io/exporter/stackdriver"
|
||||||
|
|
||||||
|
"contrib.go.opencensus.io/exporter/zipkin"
|
||||||
|
"contrib.go.opencensus.io/integrations/ocsql"
|
||||||
|
stdzipkin "github.com/openzipkin/zipkin-go"
|
||||||
|
httpreporter "github.com/openzipkin/zipkin-go/reporter/http"
|
||||||
|
"go.opencensus.io/stats/view"
|
||||||
|
"go.opencensus.io/trace"
|
||||||
|
"go.opencensus.io/zpages"
|
||||||
|
)
|
||||||
|
|
||||||
|
func enableObservability(mux *http.ServeMux) (func(), error) {
|
||||||
|
// Enable OpenCensus zPages
|
||||||
|
if conf.Telemetry.Debug {
|
||||||
|
zpages.Handle(mux, "/telemetry")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable ocsql metrics with OpenCensus
|
||||||
|
ocsql.RegisterAllViews()
|
||||||
|
|
||||||
|
var mex view.Exporter
|
||||||
|
var tex trace.Exporter
|
||||||
|
|
||||||
|
var mCloseFn, tCloseFn func()
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Set up the metrics exporter
|
||||||
|
switch conf.Telemetry.Metrics.Exporter {
|
||||||
|
case "prometheus":
|
||||||
|
ep := "/metrics"
|
||||||
|
|
||||||
|
if conf.Telemetry.Metrics.Endpoint != "" {
|
||||||
|
ep = conf.Telemetry.Metrics.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
ex, err1 := prometheus.NewExporter(prometheus.Options{Namespace: conf.Telemetry.Metrics.Namespace})
|
||||||
|
if err == nil {
|
||||||
|
mux.Handle(ep, ex)
|
||||||
|
log.Printf("INF Prometheus exporter listening on: %s", ep)
|
||||||
|
}
|
||||||
|
mex, err = view.Exporter(ex), err1
|
||||||
|
|
||||||
|
case "stackdriver":
|
||||||
|
mex, err = stackdriver.NewExporter(stackdriver.Options{ProjectID: conf.Telemetry.Metrics.Key})
|
||||||
|
if err == nil {
|
||||||
|
log.Println("INF Google Stackdriver exporter initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
case "":
|
||||||
|
log.Println("WRN OpenCensus: no metrics exporter defined")
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("invalid metrics exporter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ERR OpenCensus: %s: %v", conf.Telemetry.Metrics, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mex != nil {
|
||||||
|
// Register the exporter
|
||||||
|
view.RegisterExporter(mex)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the tracing exporter
|
||||||
|
switch conf.Telemetry.Tracing.Exporter {
|
||||||
|
case "xray", "aws":
|
||||||
|
ex, err1 := aws.NewExporter(aws.WithVersion("latest"))
|
||||||
|
if err == nil {
|
||||||
|
tCloseFn = func() { ex.Flush() }
|
||||||
|
log.Println("INF Amazon X-Ray exporter initialized")
|
||||||
|
}
|
||||||
|
tex, err = trace.Exporter(ex), err1
|
||||||
|
|
||||||
|
case "zipkin":
|
||||||
|
// The local endpoint stores the name and address of the local service
|
||||||
|
lep, err := stdzipkin.NewEndpoint(conf.AppName, conf.hostPort)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Zipkin reporter takes collected spans from the app and reports them to the backend
|
||||||
|
// http://localhost:9411/api/v2/spans is the default for the Zipkin Span v2
|
||||||
|
re := httpreporter.NewReporter(conf.Telemetry.Tracing.Endpoint)
|
||||||
|
tCloseFn = func() { re.Close() }
|
||||||
|
tex = zipkin.NewExporter(re, lep)
|
||||||
|
|
||||||
|
case "":
|
||||||
|
log.Println("WRN OpenCensus: no traceing exporter defined")
|
||||||
|
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("invalid tracing exporter")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("ERR OpenCensus: %s: %v",
|
||||||
|
conf.Telemetry.Tracing.Exporter,
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tex != nil {
|
||||||
|
trace.RegisterExporter(tex)
|
||||||
|
sample := conf.Telemetry.Tracing.Sample
|
||||||
|
|
||||||
|
if sample == "always" {
|
||||||
|
trace.ApplyConfig(trace.Config{DefaultSampler: trace.AlwaysSample()})
|
||||||
|
|
||||||
|
} else {
|
||||||
|
prob := 0.5
|
||||||
|
if v, err := strconv.ParseFloat(sample, 10); err == nil {
|
||||||
|
prob = v
|
||||||
|
}
|
||||||
|
trace.ApplyConfig(trace.Config{DefaultSampler: trace.ProbabilitySampler(prob)})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var closeOnce sync.Once
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
// Flush and shutdown the Zipkin HTTP reporter
|
||||||
|
closeOnce.Do(func() {
|
||||||
|
if mCloseFn != nil {
|
||||||
|
mCloseFn()
|
||||||
|
}
|
||||||
|
if tCloseFn != nil {
|
||||||
|
tCloseFn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, err
|
||||||
|
}
|
@ -5,7 +5,7 @@ steps:
|
|||||||
[
|
[
|
||||||
"build",
|
"build",
|
||||||
"--tag",
|
"--tag",
|
||||||
"gcr.io/$PROJECT_ID/{% app_name_slug %}:latest",
|
"gcr.io/$PROJECT_ID/{{- .AppNameSlug -}}:latest",
|
||||||
"--build-arg",
|
"--build-arg",
|
||||||
"GO_ENV=production",
|
"GO_ENV=production",
|
||||||
".",
|
".",
|
||||||
@ -13,7 +13,7 @@ steps:
|
|||||||
|
|
||||||
# Push new image to Google Container Registry
|
# Push new image to Google Container Registry
|
||||||
- name: "gcr.io/cloud-builders/docker"
|
- name: "gcr.io/cloud-builders/docker"
|
||||||
args: ["push", "gcr.io/$PROJECT_ID/{% app_name_slug %}:latest"]
|
args: ["push", "gcr.io/$PROJECT_ID/{{- .AppNameSlug -}}:latest"]
|
||||||
|
|
||||||
# Deploy image to Cloud Run
|
# Deploy image to Cloud Run
|
||||||
- name: "gcr.io/cloud-builders/gcloud"
|
- name: "gcr.io/cloud-builders/gcloud"
|
||||||
@ -23,15 +23,15 @@ steps:
|
|||||||
"deploy",
|
"deploy",
|
||||||
"data",
|
"data",
|
||||||
"--image",
|
"--image",
|
||||||
"gcr.io/$PROJECT_ID/{% app_name_slug %}:latest",
|
"gcr.io/$PROJECT_ID/{{- .AppNameSlug -}}:latest",
|
||||||
"--add-cloudsql-instances",
|
"--add-cloudsql-instances",
|
||||||
"$PROJECT_ID:$REGION:{% app_name_slug %}_production",
|
"$PROJECT_ID:$REGION:{{- .AppNameSlug -}}_production",
|
||||||
"--region",
|
"--region",
|
||||||
"$REGION",
|
"$REGION",
|
||||||
"--platform",
|
"--platform",
|
||||||
"managed",
|
"managed",
|
||||||
"--update-env-vars",
|
"--update-env-vars",
|
||||||
"GO_ENV=production,SG_DATABASE_HOST=/cloudsql/$PROJECT_ID:$REGION:{% app_name_slug %}_production,SECRETS_FILE=prod.secrets.yml",
|
"GO_ENV=production,SG_DATABASE_HOST=/cloudsql/$PROJECT_ID:$REGION:{{- .AppNameSlug -}}_production,SECRETS_FILE=prod.secrets.yml",
|
||||||
"--port",
|
"--port",
|
||||||
"8080",
|
"8080",
|
||||||
"--service-account",
|
"--service-account",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
app_name: "{% app_name %} Development"
|
app_name: "{{- .AppName }} Development"
|
||||||
host_port: 0.0.0.0:8080
|
host_port: 0.0.0.0:8080
|
||||||
web_ui: true
|
web_ui: true
|
||||||
|
|
||||||
@ -69,10 +69,20 @@ cors_debug: false
|
|||||||
# person: people
|
# person: people
|
||||||
# sheep: sheep
|
# sheep: sheep
|
||||||
|
|
||||||
|
# open opencensus tracing and metrics
|
||||||
|
# telemetry:
|
||||||
|
# debug: true
|
||||||
|
# metrics:
|
||||||
|
# exporter: "prometheus"
|
||||||
|
# tracing:
|
||||||
|
# exporter: "zipkin"
|
||||||
|
# endpoint: "http://zipkin:9411/api/v2/spans"
|
||||||
|
# sample: 0.6
|
||||||
|
|
||||||
auth:
|
auth:
|
||||||
# Can be 'rails', 'jwt' or 'header'
|
# Can be 'rails', 'jwt' or 'header'
|
||||||
type: rails
|
type: rails
|
||||||
cookie: _{% app_name_slug %}_session
|
cookie: _{{- .AppNameSlug -}}_session
|
||||||
|
|
||||||
# Comment this out if you want to disable setting
|
# Comment this out if you want to disable setting
|
||||||
# the user_id via a header for testing.
|
# the user_id via a header for testing.
|
||||||
@ -124,7 +134,7 @@ database:
|
|||||||
type: postgres
|
type: postgres
|
||||||
host: db
|
host: db
|
||||||
port: 5432
|
port: 5432
|
||||||
dbname: {% app_name_slug %}_development
|
dbname: {{- .AppNameSlug -}}_development
|
||||||
user: postgres
|
user: postgres
|
||||||
password: postgres
|
password: postgres
|
||||||
|
|
||||||
|
@ -9,48 +9,10 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "5432:5432"
|
- "5432:5432"
|
||||||
|
|
||||||
# Yugabyte DB
|
{{ .AppNameSlug -}}_api:
|
||||||
# yb-master:
|
|
||||||
# image: yugabytedb/yugabyte:latest
|
|
||||||
# container_name: yb-master-n1
|
|
||||||
# command: [ "/home/yugabyte/bin/yb-master",
|
|
||||||
# "--fs_data_dirs=/mnt/disk0,/mnt/disk1",
|
|
||||||
# "--master_addresses=yb-master-n1:7100",
|
|
||||||
# "--replication_factor=1",
|
|
||||||
# "--enable_ysql=true"]
|
|
||||||
# ports:
|
|
||||||
# - "7000:7000"
|
|
||||||
# environment:
|
|
||||||
# SERVICE_7000_NAME: yb-master
|
|
||||||
|
|
||||||
# db:
|
|
||||||
# image: yugabytedb/yugabyte:latest
|
|
||||||
# container_name: yb-tserver-n1
|
|
||||||
# command: [ "/home/yugabyte/bin/yb-tserver",
|
|
||||||
# "--fs_data_dirs=/mnt/disk0,/mnt/disk1",
|
|
||||||
# "--start_pgsql_proxy",
|
|
||||||
# "--tserver_master_addrs=yb-master-n1:7100"]
|
|
||||||
# ports:
|
|
||||||
# - "9042:9042"
|
|
||||||
# - "6379:6379"
|
|
||||||
# - "5433:5433"
|
|
||||||
# - "9000:9000"
|
|
||||||
# environment:
|
|
||||||
# SERVICE_5433_NAME: ysql
|
|
||||||
# SERVICE_9042_NAME: ycql
|
|
||||||
# SERVICE_6379_NAME: yedis
|
|
||||||
# SERVICE_9000_NAME: yb-tserver
|
|
||||||
# depends_on:
|
|
||||||
# - yb-master
|
|
||||||
|
|
||||||
{% app_name_slug %}_api:
|
|
||||||
image: dosco/super-graph:latest
|
image: dosco/super-graph:latest
|
||||||
environment:
|
environment:
|
||||||
GO_ENV: "development"
|
GO_ENV: "development"
|
||||||
# Uncomment below for Yugabyte DB
|
|
||||||
# SG_DATABASE_PORT: 5433
|
|
||||||
# SG_DATABASE_USER: yugabyte
|
|
||||||
# SG_DATABASE_PASSWORD: yugabyte
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./config:/config
|
- ./config:/config
|
||||||
ports:
|
ports:
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
# so I only need to overwrite some values
|
# so I only need to overwrite some values
|
||||||
inherits: dev
|
inherits: dev
|
||||||
|
|
||||||
app_name: "{% app_name %} Production"
|
app_name: "{{- .AppName }} Production"
|
||||||
host_port: 0.0.0.0:8080
|
host_port: 0.0.0.0:8080
|
||||||
web_ui: false
|
web_ui: false
|
||||||
|
|
||||||
@ -68,11 +68,21 @@ reload_on_config_change: false
|
|||||||
# SG_AUTH_RAILS_REDIS_PASSWORD
|
# SG_AUTH_RAILS_REDIS_PASSWORD
|
||||||
# SG_AUTH_JWT_PUBLIC_KEY_FILE
|
# SG_AUTH_JWT_PUBLIC_KEY_FILE
|
||||||
|
|
||||||
|
# open opencensus tracing and metrics
|
||||||
|
# telemetry:
|
||||||
|
# debug: false
|
||||||
|
# metrics:
|
||||||
|
# exporter: "prometheus"
|
||||||
|
# tracing:
|
||||||
|
# exporter: "zipkin"
|
||||||
|
# endpoint: "http://zipkin:9411/api/v2/spans"
|
||||||
|
# sample: 0.6
|
||||||
|
|
||||||
database:
|
database:
|
||||||
type: postgres
|
type: postgres
|
||||||
host: db
|
host: db
|
||||||
port: 5432
|
port: 5432
|
||||||
dbname: {% app_name_slug %}_production
|
dbname: {{- .AppNameSlug -}}_production
|
||||||
user: postgres
|
user: postgres
|
||||||
password: postgres
|
password: postgres
|
||||||
#pool_size: 10
|
#pool_size: 10
|
||||||
|
@ -3,6 +3,8 @@ package serv
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/brianvoe/gofakeit/v5"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGQLHash1(t *testing.T) {
|
func TestGQLHash1(t *testing.T) {
|
||||||
@ -229,3 +231,7 @@ func TestGQLHashWithVars2(t *testing.T) {
|
|||||||
t.Fatal("Hashes don't match they should")
|
t.Fatal("Hashes don't match they should")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGoFake(t *testing.T) {
|
||||||
|
gofakeit.Person()
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user