Skip to content

Commit

Permalink
feat: Force explicit primary decl. in SDL for one-ones (#2462)
Browse files Browse the repository at this point in the history
## Relevant issue(s)

Resolves #2461

## Description

Forces the explicit declaration of the primary side of one-one relation
fields in SDL.

PatchSchema already forces this and needed no change.
  • Loading branch information
AndrewSisley authored Mar 28, 2024
1 parent a2c3863 commit 34ff648
Show file tree
Hide file tree
Showing 16 changed files with 93 additions and 37 deletions.
9 changes: 9 additions & 0 deletions client/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
errCanNotNormalizeValue string = "can not normalize value"
errCanNotTurnNormalValueIntoArray string = "can not turn normal value into array"
errCanNotMakeNormalNilFromFieldKind string = "can not make normal nil from field kind"
errPrimarySideNotDefined string = "primary side of relation not defined"
)

// Errors returnable from this package.
Expand All @@ -57,6 +58,7 @@ var (
ErrCanNotNormalizeValue = errors.New(errCanNotNormalizeValue)
ErrCanNotTurnNormalValueIntoArray = errors.New(errCanNotTurnNormalValueIntoArray)
ErrCanNotMakeNormalNilFromFieldKind = errors.New(errCanNotMakeNormalNilFromFieldKind)
ErrPrimarySideNotDefined = errors.New(errPrimarySideNotDefined)
)

// NewErrFieldNotExist returns an error indicating that the given field does not exist.
Expand Down Expand Up @@ -178,3 +180,10 @@ func NewErrCRDTKindMismatch(cType, kind string) error {
func NewErrInvalidJSONPaylaod(payload string) error {
return errors.New(errInvalidJSONPayload, errors.NewKV("Payload", payload))
}

func NewErrPrimarySideNotDefined(relationName string) error {
return errors.New(
errPrimarySideNotDefined,
errors.NewKV("RelationName", relationName),
)
}
2 changes: 1 addition & 1 deletion db/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ func validateUpdateSchemaFields(
}

if !(proposedField.IsPrimaryRelation || relatedField.IsPrimaryRelation) {
return false, NewErrPrimarySideNotDefined(proposedField.RelationName)
return false, client.NewErrPrimarySideNotDefined(proposedField.RelationName)
}

if proposedField.IsPrimaryRelation && relatedField.IsPrimaryRelation {
Expand Down
8 changes: 0 additions & 8 deletions db/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const (
errRelationalFieldInvalidRelationType string = "invalid RelationType"
errRelationalFieldMissingIDField string = "missing id field for relation object field"
errRelationalFieldMissingRelationName string = "missing relation name"
errPrimarySideNotDefined string = "primary side of relation not defined"
errPrimarySideOnMany string = "cannot set the many side of a relation as primary"
errBothSidesPrimary string = "both sides of a relation cannot be primary"
errRelatedFieldKindMismatch string = "invalid Kind of the related field"
Expand Down Expand Up @@ -273,13 +272,6 @@ func NewErrRelationalFieldMissingRelationName(name string) error {
)
}

func NewErrPrimarySideNotDefined(relationName string) error {
return errors.New(
errPrimarySideNotDefined,
errors.NewKV("RelationName", relationName),
)
}

func NewErrPrimarySideOnMany(name string) error {
return errors.New(
errPrimarySideOnMany,
Expand Down
4 changes: 2 additions & 2 deletions request/graphql/schema/descriptions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestSingleSimpleType(t *testing.T) {
type Author {
name: String
age: Int
published: Book
published: Book @primary
}
`,
targetDescs: []client.CollectionDefinition{
Expand Down Expand Up @@ -330,7 +330,7 @@ func TestSingleSimpleType(t *testing.T) {
type Author {
name: String
age: Int
published: Book @relation(name:"book_authors")
published: Book @relation(name:"book_authors") @primary
}
`,
targetDescs: []client.CollectionDefinition{
Expand Down
8 changes: 1 addition & 7 deletions request/graphql/schema/relations.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,7 @@ func (r *Relation) finalize() error {
if aBit.isSet(relation_Type_Primary) {
return ErrMultipleRelationPrimaries
} else if !xBit.isSet(relation_Type_Primary) {
// neither type has primary set, auto add to
// lexicographically first one by schema type name
if strings.Compare(r.schemaTypes[0], r.schemaTypes[1]) < 1 {
r.types[1] = r.types[1] | relation_Type_Primary
} else {
r.types[0] = r.types[0] | relation_Type_Primary
}
return client.NewErrPrimarySideNotDefined(r.name)
}
}

Expand Down
8 changes: 4 additions & 4 deletions tests/gen/gen_auto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func TestAutoGenerateFromSchema_RelationOneToOne(t *testing.T) {
}
type Device {
owner: User
owner: User @primary
model: String
}`

Expand Down Expand Up @@ -792,7 +792,7 @@ func TestAutoGenerateFromSchema_ConfigThatCanNotBySupplied(t *testing.T) {
type Device {
model: String
owner: User
owner: User @primary
}`,
options: []Option{WithTypeDemand("User", 10), WithTypeDemand("Device", 30)},
},
Expand All @@ -801,12 +801,12 @@ func TestAutoGenerateFromSchema_ConfigThatCanNotBySupplied(t *testing.T) {
type User {
name: String
device: Device
orders: Order
orders: Order @primary
}
type Device {
model: String
owner: User
owner: User @primary
}
type Order {
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/backup/one_to_one/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ func TestBackupExport_DoubleReletionship_NoError(t *testing.T) {
}
type Book {
name: String
author: User @relation(name: "written_books")
favourite: User @relation(name: "favourite_books")
author: User @relation(name: "written_books") @primary
favourite: User @relation(name: "favourite_books") @primary
}
`,
},
Expand Down Expand Up @@ -122,8 +122,8 @@ func TestBackupExport_DoubleReletionshipWithUpdate_NoError(t *testing.T) {
}
type Book {
name: String
author: User @relation(name: "written_books")
favourite: User @relation(name: "favourite_books")
author: User @relation(name: "written_books") @primary
favourite: User @relation(name: "favourite_books") @primary
}
`,
},
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/backup/one_to_one/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,8 @@ func TestBackupImport_DoubleRelationshipWithUpdate_NoError(t *testing.T) {
}
type Book {
name: String
author: User @relation(name: "written_books")
favourite: User @relation(name: "favourite_books")
author: User @relation(name: "written_books") @primary
favourite: User @relation(name: "favourite_books") @primary
}
`,
},
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/explain/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ var SchemaForExplainTests = testUtils.SchemaUpdate{
verified: Boolean
books: [Book]
articles: [Article]
contact: AuthorContact
contact: AuthorContact @primary
}
type AuthorContact {
cell: String
email: String
author: Author
address: ContactAddress
address: ContactAddress @primary
}
type ContactAddress {
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/index/query_with_relation_filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func TestQueryWithIndexOnOneToOnesSecondaryRelation_IfFilterOnIndexedRelation_Sh
}
type Address {
user: User
user: User @primary
city: String @index
}`,
},
Expand Down Expand Up @@ -348,7 +348,7 @@ func TestQueryWithIndexOnOneToTwoRelation_IfFilterOnIndexedRelation_ShouldFilter
}
type Address {
user: User
user: User @primary
city: String @index
}`,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func execute(t *testing.T, test testUtils.TestCase) {
name: String
rating: Float
author: Author
publisher: Publisher
publisher: Publisher @primary
}
type Author {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func execute(t *testing.T, test testUtils.TestCase) {
name: String
rating: Float
author: Author
publisher: Publisher
publisher: Publisher @primary
}
type Author {
Expand Down
61 changes: 61 additions & 0 deletions tests/integration/schema/one_one_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2024 Democratized Data Foundation
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package schema

import (
"testing"

testUtils "github.com/sourcenetwork/defradb/tests/integration"
)

func TestSchemaOneOne_NoPrimary_Errors(t *testing.T) {
test := testUtils.TestCase{
Actions: []any{
testUtils.SchemaUpdate{
Schema: `
type User {
name: String
dog: Dog
}
type Dog {
name: String
owner: User
}
`,
ExpectedError: "primary side of relation not defined. RelationName: dog_user",
},
},
}

testUtils.ExecuteTestCase(t, test)
}

func TestSchemaOneOne_TwoPrimaries_Errors(t *testing.T) {
test := testUtils.TestCase{
Actions: []any{
testUtils.SchemaUpdate{
Schema: `
type User {
name: String
dog: Dog @primary
}
type Dog {
name: String
owner: User @primary
}
`,
ExpectedError: "relation can only have a single field set as primary",
},
},
}

testUtils.ExecuteTestCase(t, test)
}
2 changes: 1 addition & 1 deletion tests/integration/schema/relations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestSchemaRelationOneToOne(t *testing.T) {
Schema: `
type Dog {
name: String
user: User
user: User @primary
}
type User {
dog: Dog
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/view/one_to_one/with_transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestView_OneToOneWithTransformOnOuter(t *testing.T) {
}
type Book {
name: String
author: Author
author: Author @primary
}
`,
},
Expand Down
2 changes: 1 addition & 1 deletion tests/predefined/gen_predefined_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func TestGeneratePredefinedFromSchema_OneToOne(t *testing.T) {
}
type Device {
model: String
owner: User
owner: User @primary
}`

docs, err := CreateFromSDL(schema, DocsList{
Expand Down

0 comments on commit 34ff648

Please sign in to comment.