Skip to content

Commit

Permalink
Add support for adding relational fields to schema
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewSisley committed Aug 8, 2023
1 parent 229e02a commit 0372c5a
Show file tree
Hide file tree
Showing 5 changed files with 1,378 additions and 111 deletions.
132 changes: 129 additions & 3 deletions db/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,10 @@ func (db *db) updateCollection(
ctx context.Context,
txn datastore.Txn,
existingDescriptionsByName map[string]client.CollectionDescription,
proposedDescriptionsByName map[string]client.CollectionDescription,
desc client.CollectionDescription,
) (client.Collection, error) {
hasChanged, err := db.validateUpdateCollection(ctx, txn, existingDescriptionsByName, desc)
hasChanged, err := db.validateUpdateCollection(ctx, txn, existingDescriptionsByName, proposedDescriptionsByName, desc)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -313,6 +314,7 @@ func (db *db) validateUpdateCollection(
ctx context.Context,
txn datastore.Txn,
existingDescriptionsByName map[string]client.CollectionDescription,
proposedDescriptionsByName map[string]client.CollectionDescription,
proposedDesc client.CollectionDescription,
) (bool, error) {
if proposedDesc.Name == "" {
Expand Down Expand Up @@ -347,7 +349,7 @@ func (db *db) validateUpdateCollection(
return false, ErrCannotSetVersionID
}

hasChangedFields, err := validateUpdateCollectionFields(existingDesc, proposedDesc)
hasChangedFields, err := validateUpdateCollectionFields(proposedDescriptionsByName, existingDesc, proposedDesc)
if err != nil {
return hasChangedFields, err
}
Expand All @@ -357,6 +359,7 @@ func (db *db) validateUpdateCollection(
}

func validateUpdateCollectionFields(
descriptionsByName map[string]client.CollectionDescription,
existingDesc client.CollectionDescription,
proposedDesc client.CollectionDescription,
) (bool, error) {
Expand Down Expand Up @@ -387,7 +390,130 @@ func validateUpdateCollectionFields(

if !fieldAlreadyExists && (proposedField.Kind == client.FieldKind_FOREIGN_OBJECT ||
proposedField.Kind == client.FieldKind_FOREIGN_OBJECT_ARRAY) {
return false, NewErrCannotAddRelationalField(proposedField.Name, proposedField.Kind)
if proposedField.Schema == "" {
return false, NewErrRelationalFieldMissingSchema(proposedField.Name, proposedField.Kind)
}

relatedDesc, relatedDescFound := descriptionsByName[proposedField.Schema]

if !relatedDescFound {
return false, NewErrSchemaNotFound(proposedField.Name, proposedField.Schema)
}

if proposedField.Kind == client.FieldKind_FOREIGN_OBJECT {
if !proposedField.RelationType.IsSet(client.Relation_Type_ONE) ||
!(proposedField.RelationType.IsSet(client.Relation_Type_ONEONE) ||
proposedField.RelationType.IsSet(client.Relation_Type_ONEMANY)) {
return false, NewErrRelationalFieldInvalidRelationType(
proposedField.Name,
fmt.Sprintf(
"%v and %v or %v, with optionally %v",
client.Relation_Type_ONE,
client.Relation_Type_ONEONE,
client.Relation_Type_ONEMANY,
client.Relation_Type_Primary,
),
proposedField.RelationType,
)
}
}

if proposedField.Kind == client.FieldKind_FOREIGN_OBJECT_ARRAY {
if !proposedField.RelationType.IsSet(client.Relation_Type_MANY) ||
!proposedField.RelationType.IsSet(client.Relation_Type_ONEMANY) {
return false, NewErrRelationalFieldInvalidRelationType(
proposedField.Name,
client.Relation_Type_MANY|client.Relation_Type_ONEMANY,
proposedField.RelationType,
)
}
}

if proposedField.RelationName == "" {
return false, NewErrRelationalFieldMissingRelationName(proposedField.Name)
}

if proposedField.RelationType.IsSet(client.Relation_Type_Primary) {
if proposedField.Kind == client.FieldKind_FOREIGN_OBJECT_ARRAY {
return false, NewErrPrimarySideOnMany(proposedField.Name)
}

idFieldName := proposedField.Name + "_id"
idField, idFieldFound := proposedDesc.Schema.GetField(idFieldName)
if !idFieldFound {
return false, NewErrRelationalFieldMissingIDField(proposedField.Name, idFieldName)
}

if idField.Kind != client.FieldKind_DocKey {
return false, NewErrRelationalFieldIDInvalidType(idField.Name, client.FieldKind_DocKey, idField.Kind)
}

if idField.RelationType != client.Relation_Type_INTERNAL_ID {
return false, NewErrRelationalFieldInvalidRelationType(
idField.Name,
client.Relation_Type_INTERNAL_ID,
idField.RelationType,
)
}

if idField.RelationName == "" {
return false, NewErrRelationalFieldMissingRelationName(idField.Name)
}
}

var relatedFieldFound bool
var relatedField client.FieldDescription
for _, field := range relatedDesc.Schema.Fields {
if field.RelationName == proposedField.RelationName &&
!field.RelationType.IsSet(client.Relation_Type_INTERNAL_ID) &&
!(relatedDesc.Name == proposedDesc.Name && field.Name == proposedField.Name) {
relatedFieldFound = true
relatedField = field
break
}
}

if !relatedFieldFound {
return false, client.NewErrRelationOneSided(proposedField.Name, proposedField.Schema)
}

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

if proposedField.RelationType.IsSet(client.Relation_Type_Primary) &&
relatedField.RelationType.IsSet(client.Relation_Type_Primary) {
return false, NewErrBothSidesPrimary(proposedField.RelationName)
}

if proposedField.RelationType.IsSet(client.Relation_Type_ONEONE) &&
relatedField.Kind != client.FieldKind_FOREIGN_OBJECT {
return false, NewErrRelatedFieldKindMismatch(
proposedField.RelationName,
client.FieldKind_FOREIGN_OBJECT,
relatedField.Kind,
)
}

if proposedField.RelationType.IsSet(client.Relation_Type_ONEMANY) &&
proposedField.Kind == client.FieldKind_FOREIGN_OBJECT &&
relatedField.Kind != client.FieldKind_FOREIGN_OBJECT_ARRAY {
return false, NewErrRelatedFieldKindMismatch(
proposedField.RelationName,
client.FieldKind_FOREIGN_OBJECT_ARRAY,
relatedField.Kind,
)
}

if proposedField.RelationType.IsSet(client.Relation_Type_ONEONE) &&
!relatedField.RelationType.IsSet(client.Relation_Type_ONEONE) {
return false, NewErrRelatedFieldRelationTypeMismatch(
proposedField.RelationName,
client.Relation_Type_ONEONE,
relatedField.RelationType,
)
}
}

if _, isDuplicate := newFieldNames[proposedField.Name]; isDuplicate {
Expand Down
Loading

0 comments on commit 0372c5a

Please sign in to comment.