cli: support squashing actions in config v1 (#5249)

This commit is contained in:
Aravind 2020-07-27 07:15:43 +05:30 committed by GitHub
parent 2e5e59bd00
commit 96f6bdd531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 403 additions and 8 deletions

View File

@ -17,6 +17,212 @@ import (
type CustomQuery linq.Query
func (q CustomQuery) MergeCustomTypes(squashList *database.CustomList) error {
actionPermissionsTransition := transition.New(&cronTriggerConfig{})
actionPermissionsTransition.Initial("new")
actionPermissionsTransition.State("created")
actionPermissionsTransition.Event(setCustomTypes).To("created").From("new", "created")
next := q.Iterate()
for item, ok := next(); ok; item, ok = next() {
g := item.(linq.Group)
if g.Key == "" {
continue
}
var first *list.Element
for ind, val := range g.Group {
element := val.(*list.Element)
switch obj := element.Value.(type) {
case *setCustomTypesInput:
if ind == 0 {
first = element
continue
}
first.Value = obj
squashList.Remove(element)
}
}
}
return nil
}
func (q CustomQuery) MergeActionPermissions(squashList *database.CustomList) error {
actionPermissionsTransition := transition.New(&actionPermissionConfig{})
actionPermissionsTransition.Initial("new")
actionPermissionsTransition.State("created")
actionPermissionsTransition.State("deleted")
actionPermissionsTransition.Event(createActionPermission).To("created").From("new", "deleted")
actionPermissionsTransition.Event(dropActionPermission).To("deleted").From("new", "created")
next := q.Iterate()
for item, ok := next(); ok; item, ok = next() {
g := item.(linq.Group)
if g.Key == "" {
continue
}
key := g.Key.(string)
cfg := actionPermissionConfig{
action: key,
}
prevElems := make([]*list.Element, 0)
for _, val := range g.Group {
element := val.(*list.Element)
switch element.Value.(type) {
case *createActionPermissionInput:
err := actionPermissionsTransition.Trigger(createActionPermission, &cfg, nil)
if err != nil {
return err
}
prevElems = append(prevElems, element)
case *dropActionPermissionInput:
if cfg.GetState() == "created" {
prevElems = append(prevElems, element)
}
err := actionPermissionsTransition.Trigger(dropActionPermission, &cfg, nil)
if err != nil {
return err
}
for _, e := range prevElems {
squashList.Remove(e)
}
}
}
}
return nil
}
func (q CustomQuery) MergeActions(squashList *database.CustomList) error {
actionTransition := transition.New(&actionConfig{})
actionTransition.Initial("new")
actionTransition.State("created")
actionTransition.State("updated")
actionTransition.State("deleted")
actionTransition.Event(createAction).To("created").From("new", "deleted")
actionTransition.Event(updateAction).To("updated").From("new", "created", "updated", "deleted")
actionTransition.Event(dropAction).To("deleted").From("new", "created", "updated")
next := q.Iterate()
for item, ok := next(); ok; item, ok = next() {
g := item.(linq.Group)
if g.Key == "" {
continue
}
key, ok := g.Key.(string)
if !ok {
continue
}
cfg := actionConfig{
name: key,
}
prevElems := make([]*list.Element, 0)
for _, val := range g.Group {
element := val.(*list.Element)
switch obj := element.Value.(type) {
case *createActionInput:
err := actionTransition.Trigger(createAction, &cfg, nil)
if err != nil {
return errors.Wrapf(err, "error squashin Action: %v", obj.Name)
}
prevElems = append(prevElems, element)
case *updateActionInput:
if len(prevElems) != 0 {
if _, ok := prevElems[0].Value.(*createActionInput); ok {
prevElems[0].Value = &createActionInput{
actionDefinition: obj.actionDefinition,
}
prevElems = prevElems[:1]
err := actionTransition.Trigger(dropAction, &cfg, nil)
if err != nil {
return errors.Wrapf(err, "error squashing action: %v", obj.Name)
}
squashList.Remove(element)
err = actionTransition.Trigger(createAction, &cfg, nil)
if err != nil {
return errors.Wrapf(err, "error squashing action: %v", obj.Name)
}
continue
}
for _, e := range prevElems {
squashList.Remove(e)
}
prevElems = prevElems[:0]
err := actionTransition.Trigger(dropAction, &cfg, nil)
if err != nil {
return errors.Wrapf(err, "error squashing action: %v", obj.Name)
}
}
prevElems = append(prevElems, element)
err := actionTransition.Trigger(updateAction, &cfg, nil)
if err != nil {
return errors.Wrapf(err, "error squashing: %v", obj.Name)
}
case *dropActionInput:
if cfg.GetState() == "created" {
prevElems = append(prevElems, element)
// drop action permissions as well
actionPermissionGroup := CustomQuery(linq.FromIterable(squashList).GroupByT(
func(element *list.Element) string {
switch args := element.Value.(type) {
case *createActionPermissionInput:
if v, ok := args.Action.(string); ok {
return v
}
case *dropActionPermissionInput:
if v, ok := args.Action.(string); ok {
return v
}
}
return ""
}, func(element *list.Element) *list.Element {
return element
},
))
next := actionPermissionGroup.Iterate()
for item, ok := next(); ok; item, ok = next() {
g := item.(linq.Group)
if g.Key == "" {
continue
}
key, ok := g.Key.(string)
if !ok {
continue
}
if key == obj.Name {
for _, val := range g.Group {
element := val.(*list.Element)
squashList.Remove(element)
}
}
}
}
err := actionTransition.Trigger(dropAction, &cfg, nil)
if err != nil {
return err
}
for _, e := range prevElems {
squashList.Remove(e)
}
prevElems = prevElems[:0]
}
}
}
return nil
}
func (q CustomQuery) MergeCronTriggers(squashList *database.CustomList) error {
cronTriggersTransition := transition.New(&cronTriggerConfig{})
cronTriggersTransition.Initial("new")
@ -975,6 +1181,21 @@ func (h *HasuraDB) PushToList(migration io.Reader, fileType string, l *database.
}
l.PushBack(o)
}
case *createActionInput, *updateActionInput:
if v.Type == updateAction {
o, ok := v.Args.(*updateActionInput)
if !ok {
break
}
l.PushBack(o)
}
if v.Type == createAction {
o, ok := v.Args.(*createActionInput)
if !ok {
break
}
l.PushBack(o)
}
default:
l.PushBack(actionType)
}
@ -1437,6 +1658,70 @@ func (h *HasuraDB) Squash(l *database.CustomList, ret chan<- interface{}) {
ret <- err
}
customTypesGroup := CustomQuery(linq.FromIterable(l).GroupByT(
func(element *list.Element) string {
switch element.Value.(type) {
case *setCustomTypesInput:
return setCustomTypes
}
return ""
}, func(element *list.Element) *list.Element {
return element
},
))
err = customTypesGroup.MergeCustomTypes(l)
if err != nil {
ret <- err
}
actionGroup := CustomQuery(linq.FromIterable(l).GroupByT(
func(element *list.Element) string {
switch args := element.Value.(type) {
case *createActionInput:
if v, ok := args.Name.(string); ok {
return v
}
case *updateActionInput:
if v, ok := args.Name.(string); ok {
return v
}
case *dropActionInput:
if v, ok := args.Name.(string); ok {
return v
}
}
return ""
}, func(element *list.Element) *list.Element {
return element
},
))
err = actionGroup.MergeActions(l)
if err != nil {
ret <- err
}
actionPermissionGroup := CustomQuery(linq.FromIterable(l).GroupByT(
func(element *list.Element) string {
switch args := element.Value.(type) {
case *createActionPermissionInput:
if v, ok := args.Action.(string); ok {
return v
}
case *dropActionPermissionInput:
if v, ok := args.Action.(string); ok {
return v
}
}
return ""
}, func(element *list.Element) *list.Element {
return element
},
))
err = actionPermissionGroup.MergeActionPermissions(l)
if err != nil {
ret <- err
}
for e := l.Front(); e != nil; e = e.Next() {
q := HasuraInterfaceQuery{
Args: e.Value,
@ -1520,10 +1805,23 @@ func (h *HasuraDB) Squash(l *database.CustomList, ret chan<- interface{}) {
q.Type = createCronTrigger
case *deleteCronTriggerInput:
q.Type = deleteCronTrigger
case *createActionInput:
q.Type = createAction
case *updateActionInput:
q.Type = updateAction
case *dropActionInput:
q.Type = dropAction
case *createActionPermissionInput:
q.Type = createActionPermission
case *dropActionPermissionInput:
q.Type = dropActionPermission
case *setCustomTypesInput:
q.Type = setCustomTypes
case *RunSQLInput:
ret <- []byte(args.SQL)
continue
default:
h.logger.Debug("cannot find metadata type for:", args)
ret <- fmt.Errorf("invalid metadata action")
return
}

View File

@ -80,6 +80,51 @@ type deleteCronTriggerInput struct {
Name string `json:"name" yaml:"name"`
}
type actionDefinition struct {
Name interface{} `json:"name,omitempty" yaml:"name,omitempty"`
Definition interface{} `json:"definition,omitempty" yaml:"definition,omitempty"`
}
type createActionInput struct {
actionDefinition
Comment string `json:"comment,omitempty" yaml:"comment,omitempty"`
}
type actionAndPermission struct {
actionDefinition
Permissions []PermissionDefinition `json:"permissions" yaml:"permissions"`
}
type dropActionInput struct {
Name interface{} `json:"name,omitempty" yaml:"name,omitempty"`
ClearData bool `json:"clear_data,omitempty" yaml:"clear_data,omitempty"`
}
type updateActionInput struct {
actionDefinition
}
type PermissionDefinition struct {
Role interface{} `json:"role,omitempty" yaml:"role,omitempty"`
Comment string `json:"comment,omitempty" yaml:"comment,omitempty"`
}
type createActionPermissionInput struct {
Action interface{} `json:"action,omitempty" yaml:"action,omitempty"`
PermissionDefinition
}
type dropActionPermissionInput struct {
Action interface{} `json:"action,omitempty" yaml:"action,omitempty"`
PermissionDefinition
}
type setCustomTypesInput struct {
InputObjects interface{} `json:"input_objects,omitempty" yaml:"input_objects,omitempty"`
Objects interface{} `json:"objects,omitempty" yaml:"objects,omitempty"`
Scalars interface{} `json:"scalars,omitempty" yaml:"scalars,omitempty"`
Enums interface{} `json:"enums,omitempty" yaml:"enums,omitempty"`
}
func (h *newHasuraIntefaceQuery) UnmarshalJSON(b []byte) error {
type t newHasuraIntefaceQuery
var q t
@ -175,6 +220,18 @@ func (h *newHasuraIntefaceQuery) UnmarshalJSON(b []byte) error {
q.Args = &createCronTriggerInput{}
case deleteCronTrigger:
q.Args = &deleteCronTriggerInput{}
case createAction:
q.Args = &createActionInput{}
case dropAction:
q.Args = &dropActionInput{}
case updateAction:
q.Args = &updateActionInput{}
case createActionPermission:
q.Args = &createActionPermissionInput{}
case dropActionPermission:
q.Args = &dropActionPermissionInput{}
case setCustomTypes:
q.Args = &setCustomTypesInput{}
default:
return fmt.Errorf("cannot squash type %s", q.Type)
}
@ -357,6 +414,12 @@ const (
deleteRemoteRelationship = "delete_remote_relationship"
createCronTrigger = "create_cron_trigger"
deleteCronTrigger = "delete_cron_trigger"
createAction = "create_action"
dropAction = "drop_action"
updateAction = "update_action"
createActionPermission = "create_action_permission"
dropActionPermission = "drop_action_permission"
setCustomTypes = "set_custom_types"
)
type tableMap struct {
@ -700,6 +763,8 @@ type replaceMetadataInput struct {
AllowList []*addCollectionToAllowListInput `json:"allowlist" yaml:"allowlist"`
RemoteSchemas []*addRemoteSchemaInput `json:"remote_schemas" yaml:"remote_schemas"`
CronTriggers []*createCronTriggerInput `json:"cron_triggers" yaml:"cron_triggers"`
Actions []*actionAndPermission `json:"actions" yaml:"actions"`
CustomTypes *setCustomTypesInput `json:"custom_types" yaml:"custom_types"`
}
func (rmi *replaceMetadataInput) convertToMetadataActions(l *database.CustomList) {
@ -806,15 +871,17 @@ func (rmi *replaceMetadataInput) convertToMetadataActions(l *database.CustomList
}
for _, table := range rmi.Tables {
for _, remoteRelationship := range *table.RemoteRelationships {
r := createRemoteRelationshipInput{
remoteRelationshipDefinition: remoteRelationship.Definiton,
Table: tableSchema{
Name: table.Table.Name,
Schema: table.Table.Schema,
},
if table.RemoteRelationships != nil {
for _, remoteRelationship := range *table.RemoteRelationships {
r := createRemoteRelationshipInput{
remoteRelationshipDefinition: remoteRelationship.Definiton,
Table: tableSchema{
Name: table.Table.Name,
Schema: table.Table.Schema,
},
}
l.PushBack(r)
}
l.PushBack(r)
}
}
@ -842,6 +909,26 @@ func (rmi *replaceMetadataInput) convertToMetadataActions(l *database.CustomList
for _, ct := range rmi.CronTriggers {
l.PushBack(ct)
}
// track actions
for _, action := range rmi.Actions {
// action definition
a := &createActionInput{
actionDefinition: action.actionDefinition,
}
l.PushBack(a)
// permission
for _, permission := range action.Permissions {
p := &createActionPermissionInput{
Action: action.Name,
PermissionDefinition: permission,
}
l.PushBack(p)
}
}
if rmi.CustomTypes != nil {
l.PushBack(rmi.CustomTypes)
}
}
type InconsistentMetadata struct {
@ -1022,7 +1109,17 @@ type remoteRelationshipConfig struct {
tableName, schemaName, name string
transition.Transition
}
type cronTriggerConfig struct {
name string
transition.Transition
}
type actionConfig struct {
name string
transition.Transition
}
type actionPermissionConfig struct {
action string
transition.Transition
}