mirror of
https://github.com/zhigang1992/graphql-engine.git
synced 2026-06-15 01:59:08 +08:00
1280 lines
36 KiB
Go
1280 lines
36 KiB
Go
package hasuradb
|
|
|
|
import (
|
|
"container/list"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
|
|
"github.com/hasura/graphql-engine/cli/migrate/database"
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/ahmetb/go-linq"
|
|
|
|
yaml "github.com/ghodss/yaml"
|
|
"github.com/qor/transition"
|
|
)
|
|
|
|
type CustomQuery linq.Query
|
|
|
|
func (q CustomQuery) MergeEventTriggers(squashList *database.CustomList) error {
|
|
eventTriggerTransition := transition.New(&eventTriggerConfig{})
|
|
eventTriggerTransition.Initial("new")
|
|
eventTriggerTransition.State("created")
|
|
eventTriggerTransition.State("deleted")
|
|
|
|
eventTriggerTransition.Event("create_event_trigger").To("created").From("new", "deleted")
|
|
eventTriggerTransition.Event("delete_event_trigger").To("deleted").From("new", "created")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == "" {
|
|
continue
|
|
}
|
|
evKey := g.Key.(string)
|
|
evCfg := eventTriggerConfig{
|
|
name: evKey,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch obj := element.Value.(type) {
|
|
case *createEventTriggerInput:
|
|
if obj.Replace {
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
err := eventTriggerTransition.Trigger("delete_event_trigger", &evCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
err := eventTriggerTransition.Trigger("create_event_trigger", &evCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *deleteEventTriggerInput:
|
|
err := eventTriggerTransition.Trigger("delete_event_trigger", &evCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeRelationships(squashList *database.CustomList) error {
|
|
relationshipTransition := transition.New(&relationshipConfig{})
|
|
relationshipTransition.Initial("new")
|
|
relationshipTransition.State("created")
|
|
relationshipTransition.State("dropped")
|
|
|
|
relationshipTransition.Event("create_relationship").To("created").From("new", "dropped")
|
|
relationshipTransition.Event("drop_relationship").To("dropped").From("new", "created")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
relKey := g.Key.(relationshipMap)
|
|
relCfg := relationshipConfig{
|
|
tableName: relKey.tableName,
|
|
schemaName: relKey.schemaName,
|
|
name: relKey.name,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch obj := element.Value.(type) {
|
|
case *createObjectRelationshipInput:
|
|
err := relationshipTransition.Trigger("create_relationship", &relCfg, nil)
|
|
if err != nil {
|
|
return errors.Wrap(err, fmt.Sprintf("relationship %s %s", obj.Name, relKey.name))
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createArrayRelationshipInput:
|
|
err := relationshipTransition.Trigger("create_relationship", &relCfg, nil)
|
|
if err != nil {
|
|
return errors.Wrap(err, fmt.Sprintf("relationship %s %s", obj.Name, relKey.name))
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setRelationshipCommentInput:
|
|
if len(prevElems) != 0 {
|
|
if rel, ok := prevElems[0].Value.(*createObjectRelationshipInput); ok {
|
|
rel.Comment = obj.Comment
|
|
continue
|
|
}
|
|
|
|
if rel, ok := prevElems[0].Value.(*createArrayRelationshipInput); ok {
|
|
rel.Comment = obj.Comment
|
|
continue
|
|
}
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropRelationshipInput:
|
|
if relCfg.GetState() == "created" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := relationshipTransition.Trigger("drop_relationship", &relCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergePermissions(squashList *database.CustomList) error {
|
|
permissionTransition := transition.New(&permissionConfig{})
|
|
permissionTransition.Initial("new")
|
|
permissionTransition.State("created")
|
|
permissionTransition.State("dropped")
|
|
|
|
permissionTransition.Event("create_permission").To("created").From("new", "dropped")
|
|
permissionTransition.Event("drop_permission").To("dropped").From("new", "created")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
permKey := g.Key.(permissionMap)
|
|
permCfg := permissionConfig{
|
|
tableName: permKey.tableName,
|
|
schemaName: permKey.schemaName,
|
|
permType: permKey.permType,
|
|
role: permKey.Role,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch obj := element.Value.(type) {
|
|
case *createInsertPermissionInput, *createSelectPermissionInput, *createUpdatePermissionInput, *createDeletePermissionInput:
|
|
err := permissionTransition.Trigger("create_permission", &permCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setPermissionCommentInput:
|
|
if len(prevElems) != 0 {
|
|
if perm, ok := prevElems[0].Value.(*createInsertPermissionInput); ok {
|
|
perm.Comment = obj.Comment
|
|
continue
|
|
}
|
|
|
|
if perm, ok := prevElems[0].Value.(*createSelectPermissionInput); ok {
|
|
perm.Comment = obj.Comment
|
|
continue
|
|
}
|
|
|
|
if perm, ok := prevElems[0].Value.(*createUpdatePermissionInput); ok {
|
|
perm.Comment = obj.Comment
|
|
continue
|
|
}
|
|
|
|
if perm, ok := prevElems[0].Value.(*createDeletePermissionInput); ok {
|
|
perm.Comment = obj.Comment
|
|
continue
|
|
}
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropInsertPermissionInput, *dropSelectPermissionInput, *dropUpdatePermissionInput, *dropDeletePermissionInput:
|
|
if permCfg.GetState() == "created" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := permissionTransition.Trigger("drop_permission", &permCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeComputedFields(squashList *database.CustomList) error {
|
|
computedFieldTransition := transition.New(&computedFieldConfig{})
|
|
computedFieldTransition.Initial("new")
|
|
computedFieldTransition.State("added")
|
|
computedFieldTransition.State("dropped")
|
|
|
|
computedFieldTransition.Event("add_computed_field").To("added").From("new", "dropped")
|
|
computedFieldTransition.Event("drop_computed_field").To("dropped").From("new", "added")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
cfKey := g.Key.(computedFieldMap)
|
|
cfCfg := computedFieldConfig{
|
|
tableName: cfKey.tableName,
|
|
schemaName: cfKey.schemaName,
|
|
name: cfKey.name,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch obj := element.Value.(type) {
|
|
case *addComputedFieldInput:
|
|
err := computedFieldTransition.Trigger("add_computed_field", &cfCfg, nil)
|
|
if err != nil {
|
|
return errors.Wrap(err, fmt.Sprintf("computed field %s", obj.Name))
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropComputedFieldInput:
|
|
if cfCfg.GetState() == "added" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := computedFieldTransition.Trigger("drop_computed_field", &cfCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeTableCustomFields(squashList *database.CustomList) error {
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
var prevElem *list.Element
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch element.Value.(type) {
|
|
case *setTableCustomFieldsV2Input:
|
|
if prevElem != nil {
|
|
squashList.Remove(prevElem)
|
|
}
|
|
prevElem = element
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeTables(squashList *database.CustomList) error {
|
|
tableTransition := transition.New(&tableConfig{})
|
|
tableTransition.Initial("new")
|
|
tableTransition.State("tracked")
|
|
tableTransition.State("untracked")
|
|
|
|
tableTransition.Event("track_table").To("tracked").From("new", "untracked")
|
|
tableTransition.Event("untrack_table").To("untracked").From("new", "tracked")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
tblKey := g.Key.(tableMap)
|
|
tblCfg := tableConfig{
|
|
name: tblKey.name,
|
|
schema: tblKey.schema,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch args := element.Value.(type) {
|
|
case *trackTableInput, *trackTableV2Input:
|
|
err := tableTransition.Trigger("track_table", &tblCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *unTrackTableInput:
|
|
if tblCfg.GetState() == "tracked" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := tableTransition.Trigger("untrack_table", &tblCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
case *createEventTriggerInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create event trigger %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *deleteEventTriggerInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot delete event trigger %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createObjectRelationshipInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create object relationship %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createArrayRelationshipInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create array relationship %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setRelationshipCommentInput:
|
|
prevElems = append(prevElems, element)
|
|
case *dropRelationshipInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop relationship %s when table %s on schema %s is untracked", args.RelationShip, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createInsertPermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create insert permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createSelectPermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create select permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createUpdatePermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create update permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *createDeletePermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot create delete permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setPermissionCommentInput:
|
|
prevElems = append(prevElems, element)
|
|
case *dropInsertPermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop insert permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropSelectPermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop select permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropUpdatePermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop update permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropDeletePermissionInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop delete permission for %s role when table %s on schema %s is untracked", args.Role, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *addComputedFieldInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot add computed field %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropComputedFieldInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot drop computed field %s when table %s on schema %s is untracked", args.Name, tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setTableCustomFieldsV2Input:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot set custom fields when table %s on schema %s is untracked", tblCfg.name, tblCfg.schema)
|
|
}
|
|
if len(prevElems) != 0 {
|
|
if track, ok := prevElems[0].Value.(*trackTableV2Input); ok {
|
|
track.Configuration = args.tableConfiguration
|
|
squashList.Remove(element)
|
|
continue
|
|
}
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *setTableIsEnumInput:
|
|
if tblCfg.GetState() == "untracked" {
|
|
return fmt.Errorf("cannot set table %s on schema %s has a enum when it is untracked", tblCfg.name, tblCfg.schema)
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeFunctions(squashList *database.CustomList) error {
|
|
functionTransition := transition.New(&functionConfig{})
|
|
functionTransition.Initial("new")
|
|
functionTransition.State("tracked")
|
|
functionTransition.State("untracked")
|
|
|
|
functionTransition.Event("track_function").To("tracked").From("new", "untracked")
|
|
functionTransition.Event("untrack_function").To("untracked").From("new", "tracked")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
funcKey := g.Key.(tableMap)
|
|
funcCfg := functionConfig{
|
|
name: funcKey.name,
|
|
schema: funcKey.schema,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch element.Value.(type) {
|
|
case *trackFunctionInput:
|
|
err := functionTransition.Trigger("track_function", &funcCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *unTrackFunctionInput:
|
|
if funcCfg.GetState() == "tracked" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := functionTransition.Trigger("untrack_function", &funcCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeRemoteSchemas(squashList *database.CustomList) error {
|
|
remoteSchemaTransition := transition.New(&remoteSchemaConfig{})
|
|
remoteSchemaTransition.Initial("new")
|
|
remoteSchemaTransition.State("added")
|
|
remoteSchemaTransition.State("removed")
|
|
|
|
remoteSchemaTransition.Event("add_remote_schema").To("added").From("new", "removed")
|
|
remoteSchemaTransition.Event("remove_remote_schema").To("removed").From("new", "added")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
remoteSchemaKey := g.Key.(string)
|
|
rsCfg := remoteSchemaConfig{
|
|
name: remoteSchemaKey,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch element.Value.(type) {
|
|
case *addRemoteSchemaInput:
|
|
err := remoteSchemaTransition.Trigger("add_remote_schema", &rsCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *removeRemoteSchemaInput:
|
|
if rsCfg.GetState() == "added" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := remoteSchemaTransition.Trigger("remove_remote_schema", &rsCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeQueryInCollections(squashList *database.CustomList) error {
|
|
queryInCollectionTransition := transition.New(&queryInCollectionConfig{})
|
|
queryInCollectionTransition.Initial("new")
|
|
queryInCollectionTransition.State("added")
|
|
queryInCollectionTransition.State("dropped")
|
|
|
|
queryInCollectionTransition.Event("add_query_to_collection").To("added").From("new", "dropped")
|
|
queryInCollectionTransition.Event("drop_query_from_collection").To("dropped").From("new", "added")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
queryInCollectionKey := g.Key.(*queryInCollectionMap)
|
|
qicCfg := queryInCollectionConfig{
|
|
collectionName: queryInCollectionKey.collectionName,
|
|
queryName: queryInCollectionKey.queryName,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch element.Value.(type) {
|
|
case *addQueryToCollectionInput:
|
|
err := queryInCollectionTransition.Trigger("add_query_to_collection", &qicCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropQueryFromCollectionInput:
|
|
if qicCfg.GetState() == "added" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := queryInCollectionTransition.Trigger("drop_query_from_collection", &qicCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeAllowLists(squashList *database.CustomList) error {
|
|
allowListTransition := transition.New(&allowListConfig{})
|
|
allowListTransition.Initial("new")
|
|
allowListTransition.State("added")
|
|
allowListTransition.State("removed")
|
|
|
|
allowListTransition.Event("add_collection_to_allowlist").To("added").From("new", "removed")
|
|
allowListTransition.Event("drop_collection_from_allowlist").To("removed").From("new", "added")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
allowListKey := g.Key.(string)
|
|
alCfg := allowListConfig{
|
|
collection: allowListKey,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch element.Value.(type) {
|
|
case *addRemoteSchemaInput:
|
|
err := allowListTransition.Trigger("add_collection_to_allowlist", &alCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *removeRemoteSchemaInput:
|
|
if alCfg.GetState() == "added" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := allowListTransition.Trigger("drop_collection_from_allowlist", &alCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (q CustomQuery) MergeQueryCollections(squashList *database.CustomList) error {
|
|
queryCollectionTransition := transition.New(&queryCollectionConfig{})
|
|
queryCollectionTransition.Initial("new")
|
|
queryCollectionTransition.State("created")
|
|
queryCollectionTransition.State("dropped")
|
|
|
|
queryCollectionTransition.Event("create_query_collection").To("created").From("new", "dropped")
|
|
queryCollectionTransition.Event("drop_query_collection").To("dropped").From("new", "created")
|
|
|
|
next := q.Iterate()
|
|
|
|
for item, ok := next(); ok; item, ok = next() {
|
|
g := item.(linq.Group)
|
|
if g.Key == nil {
|
|
continue
|
|
}
|
|
queryCollectionKey := g.Key.(string)
|
|
qcCfg := queryCollectionConfig{
|
|
name: queryCollectionKey,
|
|
}
|
|
prevElems := make([]*list.Element, 0)
|
|
for _, val := range g.Group {
|
|
element := val.(*list.Element)
|
|
switch args := element.Value.(type) {
|
|
case *createQueryCollectionInput:
|
|
err := queryCollectionTransition.Trigger("create_query_collection", &qcCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *addQueryToCollectionInput:
|
|
if qcCfg.GetState() == "dropped" {
|
|
return fmt.Errorf("cannot add query %s to a collection %s when it is dropped", args.QueryName, qcCfg.name)
|
|
}
|
|
|
|
if len(prevElems) != 0 {
|
|
if query, ok := prevElems[0].Value.(*createQueryCollectionInput); ok {
|
|
query.Definition.Queries = append(query.Definition.Queries, collectionQuery{
|
|
Name: args.QueryName,
|
|
Query: args.Query,
|
|
})
|
|
squashList.Remove(element)
|
|
continue
|
|
}
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
case *dropQueryFromCollectionInput:
|
|
prevElems = append(prevElems, element)
|
|
case *addCollectionToAllowListInput:
|
|
if qcCfg.GetState() == "dropped" {
|
|
return fmt.Errorf("cannot add collection %s to allowlist when it is dropped", qcCfg.name)
|
|
}
|
|
qcCfg.allowList = true
|
|
prevElems = append(prevElems, element)
|
|
case *dropCollectionFromAllowListInput:
|
|
qcCfg.allowList = false
|
|
prevElems = append(prevElems, element)
|
|
case *dropQueryCollectionInput:
|
|
if !args.Cascade && qcCfg.allowList {
|
|
// return error stating that without cascade set allow list wont be dropped
|
|
return fmt.Errorf("cannot drop collection %s from allowlist when cascade is not set to true", qcCfg.name)
|
|
}
|
|
if qcCfg.GetState() == "created" {
|
|
prevElems = append(prevElems, element)
|
|
}
|
|
err := queryCollectionTransition.Trigger("drop_query_collection", &qcCfg, nil)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
prevElems = append(prevElems, element)
|
|
// drop previous elements
|
|
for _, e := range prevElems {
|
|
squashList.Remove(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type customList struct {
|
|
*list.List
|
|
}
|
|
|
|
func (c *customList) Iterate() linq.Iterator {
|
|
length := c.Len()
|
|
var prevElem *list.Element
|
|
i := 0
|
|
return func() (item interface{}, ok bool) {
|
|
if length == 0 {
|
|
return
|
|
}
|
|
|
|
if i == 0 {
|
|
prevElem = c.Front()
|
|
i++
|
|
} else {
|
|
prevElem = prevElem.Next()
|
|
if prevElem == nil {
|
|
return
|
|
}
|
|
}
|
|
return prevElem, true
|
|
}
|
|
}
|
|
|
|
func (h *HasuraDB) PushToList(migration io.Reader, fileType string, l *database.CustomList) error {
|
|
migr, err := ioutil.ReadAll(migration)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
body := string(migr[:])
|
|
switch fileType {
|
|
case "sql":
|
|
if body == "" {
|
|
break
|
|
}
|
|
tt := &RunSQLInput{
|
|
SQL: body,
|
|
}
|
|
l.PushBack(tt)
|
|
case "meta":
|
|
var t []newHasuraIntefaceQuery
|
|
err := yaml.Unmarshal(migr, &t)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, v := range t {
|
|
switch actionType := v.Args.(type) {
|
|
case *replaceMetadataInput:
|
|
// Remove previous metadata actions
|
|
var next *list.Element
|
|
for e := l.Front(); e != nil; e = next {
|
|
next = e.Next()
|
|
switch e.Value.(type) {
|
|
case *RunSQLInput:
|
|
// do nothing
|
|
default:
|
|
l.Remove(e)
|
|
}
|
|
}
|
|
// add clear Metadata
|
|
cm := &clearMetadataInput{}
|
|
l.PushBack(cm)
|
|
// convert replace metadata to actions
|
|
actionType.convertToMetadataActions(l)
|
|
case *clearMetadataInput:
|
|
// Remove previous metadata actions
|
|
var next *list.Element
|
|
for e := l.Front(); e != nil; e = next {
|
|
next = e.Next()
|
|
switch e.Value.(type) {
|
|
case *RunSQLInput:
|
|
// do nothing
|
|
default:
|
|
l.Remove(e)
|
|
}
|
|
}
|
|
l.PushBack(actionType)
|
|
default:
|
|
l.PushBack(actionType)
|
|
}
|
|
}
|
|
default:
|
|
return fmt.Errorf("Invalid migration file type")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *HasuraDB) Squash(l *database.CustomList, ret chan<- interface{}) {
|
|
eventTriggersGroup := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) string {
|
|
switch args := element.Value.(type) {
|
|
case *createEventTriggerInput:
|
|
return args.Name
|
|
case *deleteEventTriggerInput:
|
|
return args.Name
|
|
}
|
|
return ""
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err := eventTriggersGroup.MergeEventTriggers(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
relationshipsGroup := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *createObjectRelationshipInput:
|
|
return relationshipMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Name,
|
|
}
|
|
case *createArrayRelationshipInput:
|
|
return relationshipMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Name,
|
|
}
|
|
case *setRelationshipCommentInput:
|
|
return relationshipMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Name,
|
|
}
|
|
case *dropRelationshipInput:
|
|
return relationshipMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.RelationShip,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = relationshipsGroup.MergeRelationships(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
permissionsGroup := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *createInsertPermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"insert",
|
|
args.Role,
|
|
}
|
|
case *createSelectPermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"select",
|
|
args.Role,
|
|
}
|
|
case *createUpdatePermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"update",
|
|
args.Role,
|
|
}
|
|
case *createDeletePermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"delete",
|
|
args.Role,
|
|
}
|
|
case *dropInsertPermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"insert",
|
|
args.Role,
|
|
}
|
|
case *dropSelectPermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"select",
|
|
args.Role,
|
|
}
|
|
case *dropUpdatePermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"update",
|
|
args.Role,
|
|
}
|
|
case *dropDeletePermissionInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
"delete",
|
|
args.Role,
|
|
}
|
|
case *setPermissionCommentInput:
|
|
return permissionMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Type,
|
|
args.Role,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = permissionsGroup.MergePermissions(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
computedFieldGroup := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *addComputedFieldInput:
|
|
return computedFieldMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Name,
|
|
}
|
|
case *dropComputedFieldInput:
|
|
return computedFieldMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
args.Name,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = computedFieldGroup.MergeComputedFields(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
tableCustomFieldGroup := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *setTableCustomFieldsV2Input:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = tableCustomFieldGroup.MergeTableCustomFields(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
tableGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *trackTableInput:
|
|
return tableMap{
|
|
args.tableSchema.Name,
|
|
args.tableSchema.Schema,
|
|
}
|
|
case *trackTableV2Input:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *unTrackTableInput:
|
|
return tableMap{
|
|
args.tableSchema.Name,
|
|
args.tableSchema.Schema,
|
|
}
|
|
case *setTableCustomFieldsV2Input:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *setTableIsEnumInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createEventTriggerInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createObjectRelationshipInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createArrayRelationshipInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropRelationshipInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createInsertPermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createSelectPermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createUpdatePermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *createDeletePermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropInsertPermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropSelectPermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropUpdatePermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropDeletePermissionInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *addComputedFieldInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
case *dropComputedFieldInput:
|
|
return tableMap{
|
|
args.Table.Name,
|
|
args.Table.Schema,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = tableGroups.MergeTables(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
functionGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case *trackFunctionInput:
|
|
return tableMap{
|
|
args.Name,
|
|
args.Schema,
|
|
}
|
|
case *unTrackFunctionInput:
|
|
return tableMap{
|
|
args.Name,
|
|
args.Schema,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = functionGroups.MergeFunctions(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
remoteSchemaGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) string {
|
|
switch args := element.Value.(type) {
|
|
case *addRemoteSchemaInput:
|
|
return args.Name
|
|
case *removeRemoteSchemaInput:
|
|
return args.Name
|
|
}
|
|
return ""
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = remoteSchemaGroups.MergeRemoteSchemas(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
allowListGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) string {
|
|
switch args := element.Value.(type) {
|
|
case *addCollectionToAllowListInput:
|
|
return args.Collection
|
|
case *dropCollectionFromAllowListInput:
|
|
return args.Collection
|
|
}
|
|
return ""
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = allowListGroups.MergeAllowLists(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
queryInCollectionGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) interface{} {
|
|
switch args := element.Value.(type) {
|
|
case addQueryToCollectionInput:
|
|
return queryInCollectionMap{
|
|
collectionName: args.CollectionName,
|
|
queryName: args.QueryName,
|
|
}
|
|
case dropQueryFromCollectionInput:
|
|
return queryInCollectionMap{
|
|
collectionName: args.CollectionName,
|
|
queryName: args.QueryName,
|
|
}
|
|
}
|
|
return nil
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = queryInCollectionGroups.MergeQueryInCollections(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
queryCollectionGroups := CustomQuery(linq.FromIterable(l).GroupByT(
|
|
func(element *list.Element) string {
|
|
switch args := element.Value.(type) {
|
|
case *createQueryCollectionInput:
|
|
return args.Name
|
|
case *addQueryToCollectionInput:
|
|
return args.CollectionName
|
|
case *dropQueryFromCollectionInput:
|
|
return args.CollectionName
|
|
case *addCollectionToAllowListInput:
|
|
return args.Collection
|
|
case *dropCollectionFromAllowListInput:
|
|
return args.Collection
|
|
case *dropQueryCollectionInput:
|
|
return args.Collection
|
|
}
|
|
return ""
|
|
}, func(element *list.Element) *list.Element {
|
|
return element
|
|
},
|
|
))
|
|
err = queryCollectionGroups.MergeQueryCollections(l)
|
|
if err != nil {
|
|
ret <- err
|
|
}
|
|
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
|
q := HasuraInterfaceQuery{
|
|
Args: e.Value,
|
|
}
|
|
switch args := e.Value.(type) {
|
|
case *trackTableInput:
|
|
q.Type = trackTable
|
|
case *trackTableV2Input:
|
|
q.Version = v2
|
|
q.Type = trackTable
|
|
case *setTableIsEnumInput:
|
|
q.Type = setTableIsEnum
|
|
case *unTrackTableInput:
|
|
q.Type = untrackTable
|
|
case *setTableCustomFieldsV2Input:
|
|
q.Version = v2
|
|
q.Type = setTableCustomFields
|
|
case *createObjectRelationshipInput:
|
|
q.Type = createObjectRelationship
|
|
case *createArrayRelationshipInput:
|
|
q.Type = createArrayRelationship
|
|
case *setRelationshipCommentInput:
|
|
q.Type = setRelationshipComment
|
|
case *dropRelationshipInput:
|
|
q.Type = dropRelationship
|
|
case *createInsertPermissionInput:
|
|
q.Type = createInsertPermission
|
|
case *dropInsertPermissionInput:
|
|
q.Type = dropInsertPermission
|
|
case *createSelectPermissionInput:
|
|
q.Type = createSelectPermission
|
|
case *dropSelectPermissionInput:
|
|
q.Type = dropSelectPermission
|
|
case *createUpdatePermissionInput:
|
|
q.Type = createUpdatePermission
|
|
case *dropUpdatePermissionInput:
|
|
q.Type = dropUpdatePermission
|
|
case *createDeletePermissionInput:
|
|
q.Type = createDeletePermission
|
|
case *dropDeletePermissionInput:
|
|
q.Type = dropDeletePermission
|
|
case *setPermissionCommentInput:
|
|
q.Type = setPermissionComment
|
|
case *trackFunctionInput:
|
|
q.Type = trackFunction
|
|
case *unTrackFunctionInput:
|
|
q.Type = unTrackFunction
|
|
case *createEventTriggerInput:
|
|
q.Type = createEventTrigger
|
|
case *deleteEventTriggerInput:
|
|
q.Type = deleteEventTrigger
|
|
case *addRemoteSchemaInput:
|
|
q.Type = addRemoteSchema
|
|
case *removeRemoteSchemaInput:
|
|
q.Type = removeRemoteSchema
|
|
case *createQueryCollectionInput:
|
|
q.Type = createQueryCollection
|
|
case *dropQueryCollectionInput:
|
|
q.Type = dropQueryCollection
|
|
case *addQueryToCollectionInput:
|
|
q.Type = addQueryToCollection
|
|
case *dropQueryFromCollectionInput:
|
|
q.Type = dropQueryFromCollection
|
|
case *addCollectionToAllowListInput:
|
|
q.Type = addCollectionToAllowList
|
|
case *dropCollectionFromAllowListInput:
|
|
q.Type = dropCollectionFromAllowList
|
|
case *clearMetadataInput:
|
|
q.Type = clearMetadata
|
|
case *addComputedFieldInput:
|
|
q.Type = addComputedField
|
|
case *dropComputedFieldInput:
|
|
q.Type = dropComputedField
|
|
case *RunSQLInput:
|
|
ret <- []byte(args.SQL)
|
|
continue
|
|
default:
|
|
ret <- fmt.Errorf("invalid metadata action")
|
|
return
|
|
}
|
|
ret <- q
|
|
}
|
|
}
|