Skip to content

Commit

Permalink
fix #1706. take 2 but with edit actions (#1711)
Browse files Browse the repository at this point in the history
  • Loading branch information
lolopinto authored Nov 7, 2023
1 parent ae86179 commit 94ed6a6
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 33 deletions.
28 changes: 27 additions & 1 deletion examples/simple/src/ent/contact/actions/edit_contact_action.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
import { ContactEmail } from "src/ent";
import {
EditContactActionBase,
ContactEditInput,
EditContactActionTriggers,
} from "../../generated/contact/actions/edit_contact_action_base";
import EditContactEmailAction from "src/ent/contact_email/actions/edit_contact_email_action";

export { ContactEditInput };

// we're only writing this once except with --force and packageName provided
export default class EditContactAction extends EditContactActionBase {}
export default class EditContactAction extends EditContactActionBase {
getTriggers(): EditContactActionTriggers {
return [
{
async changeset(builder, input) {
if (!input.emails) {
return;
}
return Promise.all(
input.emails.map(async (emailInput) => {
const email = await ContactEmail.loadX(
builder.viewer,
emailInput.id,
);
return EditContactEmailAction.create(builder.viewer, email, {
...emailInput,
}).changeset();
}),
);
},
},
];
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 23 additions & 1 deletion examples/simple/src/ent/tests/contact.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { User, Contact } from "../../ent";
import { User, Contact, ContactEmail } from "../../ent";
import { randomEmail, randomPhoneNumber } from "../../util/random";
import CreateUserAction from "../user/actions/create_user_action";
import CreateContactAction, {
Expand Down Expand Up @@ -238,6 +238,28 @@ test("multiple emails", async () => {
);
expect(r3.length).toBe(1);
expect(r3[0].id).toBe(contact.id);

const email1 = emails[0];
const newEmail = randomEmail();
const editedContact = await EditContactAction.create(
contact.viewer,
contact,
{
firstName: "Aegon",
lastName: "Targaryen",
emails: [
{
id: email1.id,
emailAddress: newEmail,
},
],
},
).saveX();
expect(editedContact.firstName).toBe("Aegon");
expect(editedContact.lastName).toBe("Targaryen");

const email1Reloaded = await ContactEmail.loadX(contact.viewer, email1.id);
expect(email1Reloaded.emailAddress).toBe(newEmail);
});

test("multiple phonenumbers", async () => {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions examples/simple/src/graphql/generated/schema.gql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions examples/simple/src/graphql/generated/schema.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions examples/simple/src/schema/contact_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ const ContactSchema = new EntSchema({
},
{
operation: ActionOperation.Edit,
actionOnlyFields: [
{
name: "emails",
list: true,
nullable: true,
type: "Object",
actionName: "EditContactEmailAction",
},
],
},
{
operation: ActionOperation.Delete,
Expand Down
42 changes: 30 additions & 12 deletions internal/action/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func parseActionsFromInput(cfg codegenapi.Config, nodeName string, action *input
// create/edit/delete
concreteAction, ok := typ.(concreteNodeActionType)
if ok {
fields, err := getFieldsForAction(nodeName, action, fieldInfo, concreteAction)
fields, primaryKeyField, err := getFieldsForAction(nodeName, action, fieldInfo, concreteAction)
if err != nil {
return nil, err
}
Expand All @@ -40,6 +40,8 @@ func parseActionsFromInput(cfg codegenapi.Config, nodeName string, action *input
return nil, err
}

opt.primaryKeyField = primaryKeyField

commonInfo := getCommonInfo(
cfg,
nodeName,
Expand Down Expand Up @@ -82,10 +84,11 @@ func getActionsForMutationsType(cfg codegenapi.Config, nodeName string, fieldInf
var actions []Action

createTyp := &createActionType{}
fields, err := getFieldsForAction(nodeName, action, fieldInfo, createTyp)
fields, primaryKeyField, err := getFieldsForAction(nodeName, action, fieldInfo, createTyp)
if err != nil {
return nil, err
}
opt.primaryKeyField = primaryKeyField
actions = append(actions, getCreateAction(
getCommonInfo(
cfg,
Expand All @@ -102,10 +105,11 @@ func getActionsForMutationsType(cfg codegenapi.Config, nodeName string, fieldInf
))

editTyp := &editActionType{}
fields, err = getFieldsForAction(nodeName, action, fieldInfo, editTyp)
fields, primaryKeyField, err = getFieldsForAction(nodeName, action, fieldInfo, editTyp)
if err != nil {
return nil, err
}
opt.primaryKeyField = primaryKeyField
actions = append(actions, getEditAction(
getCommonInfo(
cfg,
Expand All @@ -122,7 +126,8 @@ func getActionsForMutationsType(cfg codegenapi.Config, nodeName string, fieldInf
))

deleteTyp := &deleteActionType{}
fields, err = getFieldsForAction(nodeName, action, fieldInfo, deleteTyp)
fields, primaryKeyField, err = getFieldsForAction(nodeName, action, fieldInfo, deleteTyp)
opt.primaryKeyField = primaryKeyField
if err != nil {
return nil, err
}
Expand All @@ -146,10 +151,21 @@ func getActionsForMutationsType(cfg codegenapi.Config, nodeName string, fieldInf
// provides a way to say this action doesn't have any fields
const NO_FIELDS = "__NO_FIELDS__"

func getFieldsForAction(nodeName string, action *input.Action, fieldInfo *field.FieldInfo, typ concreteNodeActionType) ([]*field.Field, error) {
func getFieldsForAction(nodeName string, action *input.Action, fieldInfo *field.FieldInfo, typ concreteNodeActionType) ([]*field.Field, *field.Field, error) {
var primaryKeyField *field.Field

if fieldInfo != nil && typ.mutatingExistingObject() {
for _, f := range fieldInfo.EntFields() {
if f.SingleFieldPrimaryKey() {
primaryKeyField = f
break
}
}
}

var fields []*field.Field
if !typ.supportsFieldsFromEnt() {
return fields, nil
return fields, primaryKeyField, nil
}

fieldNames := action.Fields
Expand All @@ -170,11 +186,11 @@ func getFieldsForAction(nodeName string, action *input.Action, fieldInfo *field.
}

if len(fieldNames) != 0 && len(excludedFields) != 0 {
return nil, fmt.Errorf("cannot provide both fields and excluded fields")
return nil, nil, fmt.Errorf("cannot provide both fields and excluded fields")
}

if noFields {
return fields, nil
return fields, primaryKeyField, nil
}

getField := func(f *field.Field, fieldName string) (*field.Field, error) {
Expand Down Expand Up @@ -236,7 +252,7 @@ func getFieldsForAction(nodeName string, action *input.Action, fieldInfo *field.
if f.ExposeToActionsByDefault() && f.EditableField(typ.getEditableFieldContext()) && !excludedFields[f.FieldName] {
f2, err := getField(f, f.FieldName)
if err != nil {
return nil, err
return nil, nil, err
}
fields = append(fields, f2)
}
Expand All @@ -246,15 +262,16 @@ func getFieldsForAction(nodeName string, action *input.Action, fieldInfo *field.
for _, fieldName := range fieldNames {
f, err := getField(nil, fieldName)
if err != nil {
return nil, err
return nil, nil, err
}
if !f.EditableField(typ.getEditableFieldContext()) {
return nil, fmt.Errorf("field %s is not editable and cannot be added to action", fieldName)
return nil, nil, fmt.Errorf("field %s is not editable and cannot be added to action", fieldName)
}
fields = append(fields, f)
}
}
return fields, nil

return fields, primaryKeyField, nil
}

func getNonEntFieldsFromInput(cfg codegenapi.Config, nodeName string, action *input.Action, typ concreteNodeActionType) ([]*field.NonEntField, error) {
Expand Down Expand Up @@ -496,6 +513,7 @@ func getCommonInfo(
NodeInfo: nodeinfo.GetNodeInfo(nodeName),
Operation: typ.getOperation(),
tranformsDelete: opt.transformsDelete,
primaryKeyField: opt.primaryKeyField,
}
}

Expand Down
13 changes: 13 additions & 0 deletions internal/action/action_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type concreteNodeActionType interface {
getDefaultGraphQLInputName(cfg codegenapi.Config, nodeName string) string
getEditableFieldContext() field.EditableContext
supportsFieldsFromEnt() bool
mutatingExistingObject() bool
}

type concreteEdgeActionType interface {
Expand Down Expand Up @@ -81,6 +82,10 @@ func (action *createActionType) supportsFieldsFromEnt() bool {
return true
}

func (action *createActionType) mutatingExistingObject() bool {
return false
}

func (action *createActionType) getActionVerb() string {
return "create"
}
Expand Down Expand Up @@ -141,6 +146,10 @@ func (action *editActionType) getEditableFieldContext() field.EditableContext {
return field.EditEditableContext
}

func (action *editActionType) mutatingExistingObject() bool {
return true
}

var _ concreteNodeActionType = &editActionType{}

type deleteActionType struct {
Expand Down Expand Up @@ -186,6 +195,10 @@ func (action *deleteActionType) getEditableFieldContext() field.EditableContext
return field.DeleteEditableContext
}

func (action *deleteActionType) mutatingExistingObject() bool {
return true
}

var _ concreteNodeActionType = &deleteActionType{}

type mutationsActionType struct {
Expand Down
Loading

0 comments on commit 94ed6a6

Please sign in to comment.