mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 08:02:15 +03:00
cli: support squashing actions in config v1 (#5249)
This commit is contained in:
parent
2e5e59bd00
commit
96f6bdd531
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user