diff --git a/core/api.go b/core/api.go index 09aa61ce..c00c068a 100644 --- a/core/api.go +++ b/core/api.go @@ -81,6 +81,7 @@ type GraphJin struct { conf *Config db *sql.DB log *_log.Logger + dbtype string dbinfo *sdata.DBInfo schema *sdata.DBSchema allowList *allow.List diff --git a/core/core.go b/core/core.go index de2a08d9..b581a769 100644 --- a/core/core.go +++ b/core/core.go @@ -62,8 +62,14 @@ type qres struct { } func (gj *GraphJin) initDiscover() error { + if gj.conf.DBType == "" { + gj.dbtype = "postgres" + } else { + gj.dbtype = gj.conf.DBType + } + if err := gj._initDiscover(); err != nil { - return fmt.Errorf("%s: %w", gj.conf.DBType, err) + return fmt.Errorf("%s: %w", gj.dbtype, err) } return nil } @@ -71,16 +77,12 @@ func (gj *GraphJin) initDiscover() error { func (gj *GraphJin) _initDiscover() error { var err error - if gj.conf.DBType == "" { - gj.conf.DBType = "postgres" - } - // If gj.dbinfo is not null then it's probably set // for tests if gj.dbinfo == nil { gj.dbinfo, err = sdata.GetDBInfo( gj.db, - gj.conf.DBType, + gj.dbtype, gj.conf.Blocklist) } @@ -89,7 +91,7 @@ func (gj *GraphJin) _initDiscover() error { func (gj *GraphJin) initSchema() error { if err := gj._initSchema(); err != nil { - return fmt.Errorf("%s: %w", gj.conf.DBType, err) + return fmt.Errorf("%s: %w", gj.dbtype, err) } return nil } diff --git a/core/core_test.go b/core/core_test.go index af627717..2d90d6b2 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -80,6 +80,7 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } + db.SetMaxIdleConns(100) dbType = v.name if res := m.Run(); res != 0 { diff --git a/core/init.go b/core/init.go index c33b529c..c8e650ef 100644 --- a/core/init.go +++ b/core/init.go @@ -63,7 +63,6 @@ func (gj *GraphJin) initConfig() error { Name: "user", tm: make(map[string]*RoleTable), } - c.Roles = append(c.Roles, ur) gj.roles["user"] = &ur } @@ -73,7 +72,6 @@ func (gj *GraphJin) initConfig() error { Name: "anon", tm: make(map[string]*RoleTable), } - c.Roles = append(c.Roles, ur) gj.roles["anon"] = &ur } diff --git a/core/internal/psql/query.go b/core/internal/psql/query.go index b79cffae..33f8506a 100644 --- a/core/internal/psql/query.go +++ b/core/internal/psql/query.go @@ -70,6 +70,8 @@ func (co *Compiler) Compile(w *bytes.Buffer, qc *qcode.QCode) (Metadata, error) return md, fmt.Errorf("qcode is nil") } + w.WriteString(`/* action='` + qc.Name + `',controller='graphql',framework='graphjin' */ `) + switch qc.Type { case qcode.QTQuery: co.CompileQuery(w, qc, &md) diff --git a/core/internal/qcode/qcode.go b/core/internal/qcode/qcode.go index 1c7e161e..258a4b4c 100644 --- a/core/internal/qcode/qcode.go +++ b/core/internal/qcode/qcode.go @@ -55,6 +55,7 @@ type ColKey struct { type QCode struct { Type QType SType QType + Name string ActionVar string Selects []Select Vars Variables @@ -246,14 +247,14 @@ type Variables map[string]json.RawMessage func (co *Compiler) Compile(query []byte, vars Variables, role string) (*QCode, error) { var err error - qc := QCode{SType: QTQuery, Schema: co.s, Vars: vars} - qc.Roots = qc.rootsA[:0] - op, err := graph.Parse(query, co.c.FragmentFetcher) if err != nil { return nil, err } + qc := QCode{Name: op.Name, SType: QTQuery, Schema: co.s, Vars: vars} + qc.Roots = qc.rootsA[:0] + switch op.Type { case graph.OpQuery: qc.Type = QTQuery diff --git a/core/internal/sdata/schema.go b/core/internal/sdata/schema.go index 84e1714d..3b9a508c 100644 --- a/core/internal/sdata/schema.go +++ b/core/internal/sdata/schema.go @@ -97,14 +97,15 @@ func NewDBSchema( if err != nil { return nil, err } + } - // Add aliases to edge index by duplicating - // table nodes - for _, alias := range aliases[t.Name] { + // Add aliases to edge index by duplicating + for t, al := range aliases { + for _, alias := range al { if _, ok := schema.ei[alias]; ok { continue } - if e, ok := schema.ei[t.Name]; ok { + if e, ok := schema.ei[t]; ok { schema.ei[alias] = e } } diff --git a/core/introspec.go b/core/introspec.go index 02b20091..df242606 100644 --- a/core/introspec.go +++ b/core/introspec.go @@ -112,6 +112,10 @@ type intro struct { } func (gj *GraphJin) initGraphQLEgine() error { + if gj.prod { + return nil + } + engine := graphql.New() in := &intro{ Schema: engine.Schema, diff --git a/core/query2_test.go b/core/query2_test.go index e7f8e63e..785b1a70 100644 --- a/core/query2_test.go +++ b/core/query2_test.go @@ -11,6 +11,7 @@ import ( "github.com/dosco/graphjin/core" "github.com/stretchr/testify/assert" + "golang.org/x/sync/errgroup" ) func TestQuery(t *testing.T) { @@ -155,6 +156,59 @@ func TestConfigRoleManagement(t *testing.T) { assert.Empty(t, conf.Roles) } +func TestParallelRuns(t *testing.T) { + gql := `query { + me { + id + email + products { + id + } + } + }` + + // TODO: introspection engine has race condition in dev + // mode. + conf := &core.Config{Production: true, DisableAllowList: true, + Tables: []core.Table{ + {Name: "me", Table: "users"}, + }, + } + + err := conf.AddRoleTable("user", "me", core.Query{ + Filters: []string{"{ id: { eq: $user_id } }"}, + }) + if err != nil { + panic(err) + } + + g := errgroup.Group{} + + for i := 0; i < 10; i++ { + x := i + g.Go(func() error { + for n := 0; n < 10; n++ { + gj, err := core.NewGraphJin(conf, db) + if err != nil { + return fmt.Errorf("%d: %w", x, err) + } + + ctx := context.WithValue(context.Background(), core.UserIDKey, x) + _, err = gj.GraphQL(ctx, gql, nil, nil) + if err != nil { + return fmt.Errorf("%d: %w", x, err) + } + // fmt.Println(x, ">", string(res.Data)) + } + return nil + }) + } + + if err := g.Wait(); err != nil { + t.Error(err) + } +} + var benchGQL = `query { products( # returns only 30 items diff --git a/core/subs_test.go b/core/subs_test.go index c79ee982..d49badff 100644 --- a/core/subs_test.go +++ b/core/subs_test.go @@ -174,7 +174,7 @@ func TestSubscription(t *testing.T) { w := sync.WaitGroup{} - for i := 101; i < 8128; i++ { + for i := 101; i < 5000; i++ { w.Add(1) go func(n int) { id := (rand.Intn(100-1) + 1) diff --git a/internal/serv/init.go b/internal/serv/init.go index 286c4c6a..b4c94318 100644 --- a/internal/serv/init.go +++ b/internal/serv/init.go @@ -144,11 +144,9 @@ func initDB(servConfig *ServConfig, useDB, useTelemetry bool) (*sql.DB, error) { } for i := 1; i < 10; i++ { - db, err = sql.Open(dc.driverName, dc.connString) - if err != nil { - continue + if db, err = sql.Open(dc.driverName, dc.connString); err == nil { + break } - time.Sleep(time.Duration(i*100) * time.Millisecond) } @@ -156,6 +154,7 @@ func initDB(servConfig *ServConfig, useDB, useTelemetry bool) (*sql.DB, error) { return nil, fmt.Errorf("unable to open db connection: %v", err) } + db.SetMaxIdleConns(100) return db, nil }