Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Mutation typed input #2167

Merged
merged 24 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ func getFloat64(v any) (float64, error) {
return val.Float64()
case int:
return float64(val), nil
case int32:
return float64(val), nil
case int64:
return float64(val), nil
case float64:
Expand All @@ -266,6 +268,8 @@ func getInt64(v any) (int64, error) {
return val.Int64()
case int:
return int64(val), nil
case int32:
return int64(val), nil
case int64:
return val, nil
case float64:
Expand Down
1 change: 1 addition & 0 deletions client/request/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (

Cid = "cid"
Data = "data"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Please delete this Data variable now, it is now not used anywhere.

Input = "input"
FieldName = "field"
FieldIDName = "fieldId"
ShowDeleted = "showDeleted"
Expand Down
2 changes: 1 addition & 1 deletion client/request/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type ObjectMutation struct {

IDs immutable.Option[[]string]
Filter immutable.Option[Filter]
Data string
Input map[string]any

Fields []Selection
}
Expand Down
28 changes: 8 additions & 20 deletions planner/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
package planner

import (
"encoding/json"

"github.com/sourcenetwork/defradb/client"
"github.com/sourcenetwork/defradb/client/request"
"github.com/sourcenetwork/defradb/core"
Expand All @@ -37,9 +35,9 @@ type createNode struct {
// collection name, meta-data, etc.
collection client.Collection

// newDoc is the JSON string of the new document, unparsed
newDocStr string
doc *client.Document
// input map of fields and values
input map[string]any
doc *client.Document

err error

Expand All @@ -59,7 +57,7 @@ func (n *createNode) Kind() string { return "createNode" }
func (n *createNode) Init() error { return nil }

func (n *createNode) Start() error {
doc, err := client.NewDocFromJSON([]byte(n.newDocStr), n.collection.Schema())
doc, err := client.NewDocFromMap(n.input, n.collection.Schema())
if err != nil {
n.err = err
return err
Expand Down Expand Up @@ -135,24 +133,14 @@ func (n *createNode) Close() error {

func (n *createNode) Source() planNode { return n.results }

func (n *createNode) simpleExplain() (map[string]any, error) {
data := map[string]any{}
err := json.Unmarshal([]byte(n.newDocStr), &data)
if err != nil {
return nil, err
}

return map[string]any{
dataLabel: data,
}, nil
}

// Explain method returns a map containing all attributes of this node that
// are to be explained, subscribes / opts-in this node to be an explainablePlanNode.
func (n *createNode) Explain(explainType request.ExplainType) (map[string]any, error) {
switch explainType {
case request.SimpleExplain:
return n.simpleExplain()
return map[string]any{
dataLabel: n.input,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: the name dataLabeldoesn't make sense anymore. Please change to inputLabel

}, nil

case request.ExecuteExplain:
return map[string]any{
Expand All @@ -173,7 +161,7 @@ func (p *Planner) CreateDoc(parsed *mapper.Mutation) (planNode, error) {
// create a mutation createNode.
create := &createNode{
p: p,
newDocStr: parsed.Data,
input: parsed.Input,
results: results,
docMapper: docMapper{parsed.DocumentMapping},
}
Expand Down
2 changes: 1 addition & 1 deletion planner/mapper/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@ func ToMutation(ctx context.Context, store client.Store, mutationRequest *reques
return &Mutation{
Select: *underlyingSelect,
Type: MutationType(mutationRequest.Type),
Data: mutationRequest.Data,
Input: mutationRequest.Input,
}, nil
}

Expand Down
7 changes: 3 additions & 4 deletions planner/mapper/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@
// The type of mutation. For example a create request.
Type MutationType

// The data to be used for the mutation. For example, during a create this
// will be the json representation of the object to be inserted.
Data string
// Input is the map of fields and values used for the mutation.
Input map[string]any
}

func (m *Mutation) CloneTo(index int) Requestable {
Expand All @@ -40,6 +39,6 @@
return &Mutation{
Select: *m.Select.cloneTo(index),
Type: m.Type,
Data: m.Data,
Input: m.Input,

Check warning on line 42 in planner/mapper/mutation.go

View check run for this annotation

Codecov / codecov/patch

planner/mapper/mutation.go#L42

Added line #L42 was not covered by tests
}
}
18 changes: 9 additions & 9 deletions planner/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@

docIDs []string

patch string
// input map of fields and values
input map[string]any

isUpdating bool

Expand Down Expand Up @@ -67,7 +68,11 @@
if err != nil {
return false, err
}
_, err = n.collection.UpdateWithDocID(n.p.ctx, docID, n.patch)
patch, err := json.Marshal(n.input)
if err != nil {
return false, err
}

Check warning on line 74 in planner/update.go

View check run for this annotation

Codecov / codecov/patch

planner/update.go#L73-L74

Added lines #L73 - L74 were not covered by tests
_, err = n.collection.UpdateWithDocID(n.p.ctx, docID, string(patch))
if err != nil {
return false, err
}
Expand Down Expand Up @@ -126,12 +131,7 @@
}

// Add the attribute that represents the patch to update with.
data := map[string]any{}
err := json.Unmarshal([]byte(n.patch), &data)
if err != nil {
return nil, err
}
simpleExplainMap[dataLabel] = data
simpleExplainMap[dataLabel] = n.input
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: Similar to other suggestions please change the variable name to be more relevant.

Suggested change
simpleExplainMap[dataLabel] = n.input
simpleExplainMap[inputLabel] = n.input


return simpleExplainMap, nil
}
Expand Down Expand Up @@ -160,7 +160,7 @@
filter: parsed.Filter,
docIDs: parsed.DocIDs.Value(),
isUpdating: true,
patch: parsed.Data,
input: parsed.Input,
docMapper: docMapper{parsed.DocumentMapping},
}

Expand Down
50 changes: 44 additions & 6 deletions request/graphql/parser/mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,9 @@
for _, argument := range field.Arguments {
prop := argument.Name.Value
// parse each individual arg type seperately
if prop == request.Data { // parse data
raw := argument.Value.(*ast.StringValue)
if raw.Value == "" {
return nil, ErrEmptyDataPayload
}
mut.Data = raw.Value
if prop == request.Input { // parse input
raw := argument.Value.(*ast.ObjectValue)
mut.Input = parseMutationInputObject(raw)
} else if prop == request.FilterClause { // parse filter
obj := argument.Value.(*ast.ObjectValue)
filterType, ok := getArgumentType(fieldDef, request.FilterClause)
Expand Down Expand Up @@ -147,3 +144,44 @@
mut.Fields, err = parseSelectFields(schema, request.ObjectSelection, fieldObject, field.SelectionSet)
return mut, err
}

// parseMutationInput parses the correct underlying
// value type of the given ast.Value
func parseMutationInput(val ast.Value) any {
switch t := val.(type) {
case *ast.IntValue:
return gql.Int.ParseLiteral(val)
case *ast.FloatValue:
return gql.Float.ParseLiteral(val)
case *ast.BooleanValue:
return t.Value
case *ast.StringValue:
return t.Value
case *ast.ObjectValue:
return parseMutationInputObject(t)

Check warning on line 161 in request/graphql/parser/mutation.go

View check run for this annotation

Codecov / codecov/patch

request/graphql/parser/mutation.go#L160-L161

Added lines #L160 - L161 were not covered by tests
case *ast.ListValue:
return parseMutationInputList(t)
default:
return val.GetValue()
}
}

// parseMutationInputList parses the correct underlying
// value type for all of the values in the ast.ListValue
func parseMutationInputList(val *ast.ListValue) []any {
list := make([]any, 0)
for _, val := range val.Values {
list = append(list, parseMutationInput(val))
}
return list
}

// parseMutationInputObject parses the correct underlying
// value type for all of the fields in the ast.ObjectValue
func parseMutationInputObject(val *ast.ObjectValue) map[string]any {
obj := make(map[string]any)
for _, field := range val.Fields {
obj[field.Name.Value] = parseMutationInput(field.Value)
}
return obj
}
7 changes: 0 additions & 7 deletions request/graphql/schema/descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,6 @@ An optional value that specifies as to whether deleted documents may be
`
createDocumentDescription string = `
Creates a single document of this type using the data provided.
`
createDataArgDescription string = `
The json representation of the document you wish to create. Required.
`
updateDocumentsDescription string = `
Updates documents in this collection using the data provided. Only documents
Expand All @@ -148,10 +145,6 @@ An optional set of docID values that will limit the update to documents
An optional filter for this update that will limit the update to the documents
matching the given criteria. If no matching documents are found, the operation
will succeed, but no documents will be updated.
`
updateDataArgDescription string = `
The json representation of the fields to update and their new values. Required.
Fields not explicitly mentioned here will not be updated.
`
deleteDocumentsDescription string = `
Deletes documents in this collection matching any provided criteria. If no
Expand Down
61 changes: 35 additions & 26 deletions request/graphql/schema/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,37 @@
import "github.com/sourcenetwork/defradb/errors"

const (
errDuplicateField string = "duplicate field"
errFieldMissingRelation string = "field missing associated relation"
errRelationMissingField string = "relation missing field"
errAggregateTargetNotFound string = "aggregate target not found"
errSchemaTypeAlreadyExist string = "schema type already exists"
errObjectNotFoundDuringThunk string = "object not found whilst executing fields thunk"
errTypeNotFound string = "no type found for given name"
errRelationNotFound string = "no relation found"
errNonNullForTypeNotSupported string = "NonNull variants for type are not supported"
errIndexMissingFields string = "index missing fields"
errIndexUnknownArgument string = "index with unknown argument"
errIndexInvalidArgument string = "index with invalid argument"
errIndexInvalidName string = "index with invalid name"
errDuplicateField string = "duplicate field"
errFieldMissingRelation string = "field missing associated relation"
errRelationMissingField string = "relation missing field"
errAggregateTargetNotFound string = "aggregate target not found"
errSchemaTypeAlreadyExist string = "schema type already exists"
errMutationInputTypeAlreadyExist string = "mutation input type already exists"
errObjectNotFoundDuringThunk string = "object not found whilst executing fields thunk"
errTypeNotFound string = "no type found for given name"
errRelationNotFound string = "no relation found"
errNonNullForTypeNotSupported string = "NonNull variants for type are not supported"
errIndexMissingFields string = "index missing fields"
errIndexUnknownArgument string = "index with unknown argument"
errIndexInvalidArgument string = "index with invalid argument"
errIndexInvalidName string = "index with invalid name"
)

var (
ErrDuplicateField = errors.New(errDuplicateField)
ErrFieldMissingRelation = errors.New(errFieldMissingRelation)
ErrRelationMissingField = errors.New(errRelationMissingField)
ErrAggregateTargetNotFound = errors.New(errAggregateTargetNotFound)
ErrSchemaTypeAlreadyExist = errors.New(errSchemaTypeAlreadyExist)
ErrObjectNotFoundDuringThunk = errors.New(errObjectNotFoundDuringThunk)
ErrTypeNotFound = errors.New(errTypeNotFound)
ErrRelationNotFound = errors.New(errRelationNotFound)
ErrNonNullForTypeNotSupported = errors.New(errNonNullForTypeNotSupported)
ErrRelationMutlipleTypes = errors.New("relation type can only be either One or Many, not both")
ErrRelationMissingTypes = errors.New("relation is missing its defined types and fields")
ErrRelationInvalidType = errors.New("relation has an invalid type to be finalize")
ErrMultipleRelationPrimaries = errors.New("relation can only have a single field set as primary")
ErrDuplicateField = errors.New(errDuplicateField)
ErrFieldMissingRelation = errors.New(errFieldMissingRelation)
ErrRelationMissingField = errors.New(errRelationMissingField)
ErrAggregateTargetNotFound = errors.New(errAggregateTargetNotFound)
ErrSchemaTypeAlreadyExist = errors.New(errSchemaTypeAlreadyExist)
ErrMutationInputTypeAlreadyExist = errors.New(errMutationInputTypeAlreadyExist)
ErrObjectNotFoundDuringThunk = errors.New(errObjectNotFoundDuringThunk)
ErrTypeNotFound = errors.New(errTypeNotFound)
ErrRelationNotFound = errors.New(errRelationNotFound)
ErrNonNullForTypeNotSupported = errors.New(errNonNullForTypeNotSupported)
ErrRelationMutlipleTypes = errors.New("relation type can only be either One or Many, not both")
ErrRelationMissingTypes = errors.New("relation is missing its defined types and fields")
ErrRelationInvalidType = errors.New("relation has an invalid type to be finalize")
ErrMultipleRelationPrimaries = errors.New("relation can only have a single field set as primary")
// NonNull is the literal name of the GQL type, so we have to disable the linter
//nolint:revive
ErrNonNullNotSupported = errors.New("NonNull fields are not currently supported")
Expand Down Expand Up @@ -94,6 +96,13 @@
)
}

func NewErrMutationInputTypeAlreadyExist(name string) error {
return errors.New(
errMutationInputTypeAlreadyExist,
errors.NewKV("Name", name),
)

Check warning on line 103 in request/graphql/schema/errors.go

View check run for this annotation

Codecov / codecov/patch

request/graphql/schema/errors.go#L99-L103

Added lines #L99 - L103 were not covered by tests
}

func NewErrObjectNotFoundDuringThunk(object string) error {
return errors.New(
errObjectNotFoundDuringThunk,
Expand Down
Loading
Loading