Skip to content

Commit

Permalink
WIP - Prevent mutations from secondary side of relation
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewSisley committed Oct 10, 2024
1 parent bc68f57 commit c8e2ddd
Show file tree
Hide file tree
Showing 17 changed files with 244 additions and 646 deletions.
31 changes: 30 additions & 1 deletion client/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,11 +241,30 @@ func validateFieldSchema(val any, field FieldDefinition) (NormalValue, error) {
if err != nil {
return nil, err
}

_, err = NewDocIDFromString(v)
if err != nil {
return nil, err
}

return NewNormalString(v), nil
}

switch field.Kind {
case FieldKind_DocID, FieldKind_NILLABLE_STRING, FieldKind_NILLABLE_BLOB:
case FieldKind_DocID:
v, err := getString(val)
if err != nil {
return nil, err
}

_, err = NewDocIDFromString(v)
if err != nil {
return nil, err
}

return NewNormalString(v), nil

case FieldKind_NILLABLE_STRING, FieldKind_NILLABLE_BLOB:
v, err := getString(val)
if err != nil {
return nil, err
Expand Down Expand Up @@ -692,6 +711,16 @@ func (doc *Document) Set(field string, value any) error {
if !exists {
return NewErrFieldNotExist(field)
}

if fd.Kind == FieldKind_DocID && strings.HasSuffix(field, request.RelatedObjectID) {
objFieldName := strings.TrimSuffix(field, request.RelatedObjectID)
ofd, exists := doc.collectionDefinition.GetFieldByName(objFieldName)
if exists && !ofd.IsPrimaryRelation {
return NewErrCannotSetRelationFromSecondarySide(field)
}

}

Check failure on line 722 in client/document.go

View workflow job for this annotation

GitHub Actions / Lint GoLang job

unnecessary trailing newline (whitespace)

if fd.Kind.IsObject() && !fd.Kind.IsArray() {
if !strings.HasSuffix(field, request.RelatedObjectID) {
field = field + request.RelatedObjectID
Expand Down
5 changes: 5 additions & 0 deletions client/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
errCanNotTurnNormalValueIntoArray string = "can not turn normal value into array"
errCanNotMakeNormalNilFromFieldKind string = "can not make normal nil from field kind"
errFailedToParseKind string = "failed to parse kind"
errCannotSetRelationFromSecondarySide string = "cannot set relation from secondary side"
)

// Errors returnable from this package.
Expand Down Expand Up @@ -190,3 +191,7 @@ func ReviveError(message string) error {
return fmt.Errorf("%s", message)
}
}

func NewErrCannotSetRelationFromSecondarySide(name string) error {
return errors.New(errCannotSetRelationFromSecondarySide, errors.NewKV("Name", name))
}
8 changes: 8 additions & 0 deletions internal/request/graphql/schema/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,14 @@ func (g *Generator) buildMutationInputTypes(collections []client.CollectionDefin
continue
}

if field.Kind == client.FieldKind_DocID && strings.HasSuffix(field.Name, request.RelatedObjectID) {
objFieldName := strings.TrimSuffix(field.Name, request.RelatedObjectID)
ofd, exists := collection.GetFieldByName(objFieldName)
if exists && !ofd.IsPrimaryRelation {
continue
}
}

var ttype gql.Type
if field.Kind.IsObject() {
if field.Kind.IsArray() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,35 +94,6 @@ func TestMutationCreateOneToMany_AliasedRelationNameNonExistingRelationManySide_
}
executeTestCase(t, test)
}
func TestMutationCreateOneToMany_AliasedRelationNameInvalidIDManySide_CreatedDoc(t *testing.T) {
test := testUtils.TestCase{
Description: "One to many create mutation, invalid id, from the many side, with alias",
Actions: []any{
testUtils.CreateDoc{
CollectionID: 0,
Doc: `{
"name": "Painted House",
"author": "ValueDoesntMatter"
}`,
},
testUtils.Request{
Request: `query {
Book {
name
}
}`,
Results: map[string]any{
"Book": []map[string]any{
{
"name": "Painted House",
},
},
},
},
},
}
executeTestCase(t, test)
}

func TestMutationCreateOneToMany_AliasedRelationNameToLinkFromManySide(t *testing.T) {
test := testUtils.TestCase{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,6 @@ func TestMutationCreateOneToOneNoChild(t *testing.T) {
executeTestCase(t, test)
}

func TestMutationCreateOneToOne_NonExistingRelationSecondarySide_Error(t *testing.T) {
test := testUtils.TestCase{
Description: "One to one create mutation, from the secondary side",
Actions: []any{
testUtils.CreateDoc{
CollectionID: 0,
Doc: `{
"name": "Painted House",
"author_id": "bae-be6d8024-4953-5a92-84b4-f042d25230c6"
}`,
ExpectedError: "document not found or not authorized to access",
},
},
}
executeTestCase(t, test)
}

func TestMutationCreateOneToOne(t *testing.T) {
test := testUtils.TestCase{
Description: "One to one create mutation",
Expand Down Expand Up @@ -168,51 +151,10 @@ func TestMutationCreateOneToOneSecondarySide(t *testing.T) {
testUtils.CreateDoc{
CollectionID: 0,
DocMap: map[string]any{
"name": "Painted House",
"author_id": testUtils.NewDocIndex(1, 0),
},
},
testUtils.Request{
Request: `
query {
Author {
name
published {
name
}
}
}`,
Results: map[string]any{
"Author": []map[string]any{
{
"name": "John Grisham",
"published": map[string]any{
"name": "Painted House",
},
},
},
},
},
testUtils.Request{
Request: `
query {
Book {
name
author {
name
}
}
}`,
Results: map[string]any{
"Book": []map[string]any{
{
"name": "Painted House",
"author": map[string]any{
"name": "John Grisham",
},
},
},
"name": "Painted House",
"author": testUtils.NewDocIndex(1, 0),
},
ExpectedError: "cannot set relation from secondary side",
},
},
}
Expand Down Expand Up @@ -250,34 +192,3 @@ func TestMutationCreateOneToOne_ErrorsGivenRelationAlreadyEstablishedViaPrimary(

executeTestCase(t, test)
}

func TestMutationCreateOneToOne_ErrorsGivenRelationAlreadyEstablishedViaSecondary(t *testing.T) {
test := testUtils.TestCase{
Description: "One to one create mutation, errors due to link already existing, secondary side",
Actions: []any{
testUtils.CreateDoc{
CollectionID: 1,
Doc: `{
"name": "John Grisham"
}`,
},
testUtils.CreateDoc{
CollectionID: 0,
DocMap: map[string]any{
"name": "Painted House",
"author_id": testUtils.NewDocIndex(1, 0),
},
},
testUtils.CreateDoc{
CollectionID: 0,
DocMap: map[string]any{
"name": "Golestan",
"author_id": testUtils.NewDocIndex(1, 0),
},
ExpectedError: "target document is already linked to another document.",
},
},
}

executeTestCase(t, test)
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ func TestMutationUpdateOneToMany_RelationIDToLinkFromSingleSide_Error(t *testing
executeTestCase(t, test)
}

// Note: This test should probably not pass, as it contains a
// reference to a document that doesnt exist.
func TestMutationUpdateOneToMany_InvalidRelationIDToLinkFromManySide(t *testing.T) {
author1ID := "bae-a47f80ab-1c30-53b3-9dac-04a4a3fda77e"
invalidAuthorID := "bae-35953ca-518d-9e6b-9ce6cd00eff5"
Expand Down Expand Up @@ -106,42 +104,7 @@ func TestMutationUpdateOneToMany_InvalidRelationIDToLinkFromManySide(t *testing.
}`,
invalidAuthorID,
),
},
testUtils.Request{
Request: `query {
Author {
name
published {
name
}
}
}`,
Results: map[string]any{
"Author": []map[string]any{
{
"name": "John Grisham",
"published": []map[string]any{},
},
},
},
},
testUtils.Request{
Request: `query {
Book {
name
author {
name
}
}
}`,
Results: map[string]any{
"Book": []map[string]any{
{
"name": "Painted House",
"author": nil, // Linked to incorrect id
},
},
},
ExpectedError: "uuid: incorrect UUID length 30 in string",
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,51 +100,14 @@ func TestMutationUpdateOneToMany_InvalidAliasRelationNameToLinkFromManySide_GQL(
}`,
invalidAuthorID,
),
},
testUtils.Request{
Request: `query {
Author {
name
published {
name
}
}
}`,
Results: map[string]any{
"Author": []map[string]any{
{
"name": "John Grisham",
"published": []map[string]any{},
},
},
},
},
testUtils.Request{
Request: `query {
Book {
name
author {
name
}
}
}`,
Results: map[string]any{
"Book": []map[string]any{
{
"name": "Painted House",
"author": nil, // Linked to incorrect id
},
},
},
ExpectedError: "uuid: incorrect UUID length 30 in string",
},
},
}

executeTestCase(t, test)
}

// Note: This test should probably not pass, as it contains a
// reference to a document that doesnt exist.
func TestMutationUpdateOneToMany_InvalidAliasRelationNameToLinkFromManySide_Collection(t *testing.T) {
author1ID := "bae-a47f80ab-1c30-53b3-9dac-04a4a3fda77e"
invalidAuthorID := "bae-35953ca-518d-9e6b-9ce6cd00eff5"
Expand Down Expand Up @@ -177,24 +140,7 @@ func TestMutationUpdateOneToMany_InvalidAliasRelationNameToLinkFromManySide_Coll
}`,
invalidAuthorID,
),
},
testUtils.Request{
Request: `query {
Book {
name
author {
name
}
}
}`,
Results: map[string]any{
"Book": []map[string]any{
{
"name": "Painted House",
"author": nil,
},
},
},
ExpectedError: "uuid: incorrect UUID length 30 in string",
},
},
}
Expand Down
Loading

0 comments on commit c8e2ddd

Please sign in to comment.