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

refactor: Rework definition validation #2720

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2953ce1
Do not update crdt of existing fields on patch
AndrewSisley Jun 13, 2024
4a3d257
Rename validator var
AndrewSisley Jun 12, 2024
c23c0eb
Bulkify createCollection
AndrewSisley Jun 12, 2024
f6499b1
Move validation to after field ids have been set
AndrewSisley Jun 13, 2024
30bdc7e
Rework create and update collection validation
AndrewSisley Jun 12, 2024
af07bad
Validate policy the same way as every other prop
AndrewSisley Jun 12, 2024
7811dc2
Extract validateSchemaFieldNotDeleted to new sys
AndrewSisley Jun 13, 2024
3873eea
Extract validateTypeAndKindCompatible to new sys
AndrewSisley Jun 13, 2024
0e48928
Extract validateTypeSupported to new sys
AndrewSisley Jun 13, 2024
90bb075
Extract validateFieldNotMoved to new sys
AndrewSisley Jun 13, 2024
78877e8
Extract validateFieldNotMutated to new sys
AndrewSisley Jun 13, 2024
48efc71
Extract validateFieldNotDuplicated to new sys
AndrewSisley Jun 13, 2024
ec7d3b9
Extract validateSecondaryNotOnSchema to new sys
AndrewSisley Jun 13, 2024
ea17786
Extract validateRelationalFieldIDType to new sys
AndrewSisley Jun 13, 2024
734d0f9
Extract schema field change detection to rule
AndrewSisley Jun 13, 2024
116136c
Remove impossible schema name rule
AndrewSisley Jun 13, 2024
48bdffb
Extract schema version change detection to rule
AndrewSisley Jun 13, 2024
89cba00
Extract schema root change detection to rule
AndrewSisley Jun 13, 2024
111bd6d
Extract validateSchemaNotAdded to new sys
AndrewSisley Jun 13, 2024
8161b2c
Extract validateSchemaNameNotEmpty to new sys
AndrewSisley Jun 13, 2024
fe8e384
Replace validateUpdateSchema with areSchemasEqual
AndrewSisley Jun 13, 2024
d5725bd
PR FIXUP - Cleanup schema vars
AndrewSisley Jun 14, 2024
0798bb7
PR FIXUP - Cleanup txn var
AndrewSisley Jun 14, 2024
697adb5
PR FIXUP - Remove CollectionAlreadyExists check from col_define.go
AndrewSisley Jun 14, 2024
a55f317
PR FIXUP - Validate all definitions outside of loop
AndrewSisley Jun 14, 2024
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
169 changes: 91 additions & 78 deletions internal/db/collection_define.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,113 +25,126 @@
"github.com/sourcenetwork/defradb/internal/db/description"
)

func (db *db) createCollection(
func (db *db) createCollections(
ctx context.Context,
def client.CollectionDefinition,
newDefinitions []client.CollectionDefinition,
) (client.Collection, error) {
schema := def.Schema
desc := def.Description
txn := mustGetContextTxn(ctx)

if desc.Name.HasValue() {
exists, err := description.HasCollectionByName(ctx, txn, desc.Name.Value())
if err != nil {
return nil, err
}
if exists {
return nil, ErrCollectionAlreadyExists
}
}
) ([]client.CollectionDefinition, error) {
returnDescriptions := make([]client.CollectionDefinition, len(newDefinitions))

existingDefinitions, err := db.getAllActiveDefinitions(ctx)
if err != nil {
return nil, err
}

schemaByName := map[string]client.SchemaDescription{}
for _, existingDefinition := range existingDefinitions {
schemaByName[existingDefinition.Schema.Name] = existingDefinition.Schema
}
for _, newDefinition := range newDefinitions {
schemaByName[newDefinition.Schema.Name] = newDefinition.Schema
}
txn := mustGetContextTxn(ctx)

_, err = validateUpdateSchemaFields(schemaByName, client.SchemaDescription{}, schema)
if err != nil {
return nil, err
}
for i, def := range newDefinitions {
schemaByName := map[string]client.SchemaDescription{}
for _, existingDefinition := range existingDefinitions {
schemaByName[existingDefinition.Schema.Name] = existingDefinition.Schema
}
for _, newDefinition := range newDefinitions {
schemaByName[newDefinition.Schema.Name] = newDefinition.Schema
}

definitionsByName := map[string]client.CollectionDefinition{}
for _, existingDefinition := range existingDefinitions {
definitionsByName[existingDefinition.GetName()] = existingDefinition
}
for _, newDefinition := range newDefinitions {
definitionsByName[newDefinition.GetName()] = newDefinition
}
err = db.validateNewCollection(def, definitionsByName)
if err != nil {
return nil, err
schema, err := description.CreateSchemaVersion(ctx, txn, def.Schema)
if err != nil {
return nil, err

Check warning on line 52 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L52

Added line #L52 was not covered by tests
}
newDefinitions[i].Description.SchemaVersionID = schema.VersionID
newDefinitions[i].Schema = schema
}

colSeq, err := db.getSequence(ctx, core.CollectionIDSequenceKey{})
if err != nil {
return nil, err
}
colID, err := colSeq.next(ctx)
if err != nil {
return nil, err
}
for i, def := range newDefinitions {
if len(def.Description.Fields) == 0 {
// This is a schema-only definition, we should not create a collection for it
continue
}

fieldSeq, err := db.getSequence(ctx, core.NewFieldIDSequenceKey(uint32(colID)))
if err != nil {
return nil, err
}
colSeq, err := db.getSequence(ctx, core.CollectionIDSequenceKey{})
if err != nil {
return nil, err

Check warning on line 66 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L66

Added line #L66 was not covered by tests
}
colID, err := colSeq.next(ctx)
if err != nil {
return nil, err

Check warning on line 70 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L70

Added line #L70 was not covered by tests
}

desc.ID = uint32(colID)
desc.RootID = desc.ID
fieldSeq, err := db.getSequence(ctx, core.NewFieldIDSequenceKey(uint32(colID)))
if err != nil {
return nil, err

Check warning on line 75 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L75

Added line #L75 was not covered by tests
}

schema, err = description.CreateSchemaVersion(ctx, txn, schema)
if err != nil {
return nil, err
}
desc.SchemaVersionID = schema.VersionID
for _, localField := range desc.Fields {
var fieldID uint64
if localField.Name == request.DocIDFieldName {
// There is no hard technical requirement for this, we just think it looks nicer
// if the doc id is at the zero index. It makes it look a little nicer in commit
// queries too.
fieldID = 0
} else {
fieldID, err = fieldSeq.next(ctx)
if err != nil {
return nil, err
newDefinitions[i].Description.ID = uint32(colID)
newDefinitions[i].Description.RootID = newDefinitions[i].Description.ID

for _, localField := range def.Description.Fields {
var fieldID uint64
if localField.Name == request.DocIDFieldName {
// There is no hard technical requirement for this, we just think it looks nicer
// if the doc id is at the zero index. It makes it look a little nicer in commit
// queries too.
fieldID = 0
} else {
fieldID, err = fieldSeq.next(ctx)
if err != nil {
return nil, err

Check warning on line 91 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L91

Added line #L91 was not covered by tests
}
}
}

for i := range desc.Fields {
if desc.Fields[i].Name == localField.Name {
desc.Fields[i].ID = client.FieldID(fieldID)
break
for j := range def.Description.Fields {
if def.Description.Fields[j].Name == localField.Name {
newDefinitions[i].Description.Fields[j].ID = client.FieldID(fieldID)
break
}
}
}
}

desc, err = description.SaveCollection(ctx, txn, desc)
err = db.validateNewCollection(
ctx,
append(
append(
[]client.CollectionDefinition{},
newDefinitions...,
),
existingDefinitions...,
),
existingDefinitions,
)
if err != nil {
return nil, err
}

col := db.newCollection(desc, schema)
for _, def := range newDefinitions {
if len(def.Description.Fields) == 0 {
// This is a schema-only definition, we should not create a collection for it
returnDescriptions = append(returnDescriptions, def)
continue
}

desc, err := description.SaveCollection(ctx, txn, def.Description)
if err != nil {
return nil, err

Check warning on line 128 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L128

Added line #L128 was not covered by tests
}

col := db.newCollection(desc, def.Schema)

for _, index := range desc.Indexes {
if _, err := col.createIndex(ctx, index); err != nil {
return nil, err

Check warning on line 135 in internal/db/collection_define.go

View check run for this annotation

Codecov / codecov/patch

internal/db/collection_define.go#L135

Added line #L135 was not covered by tests
}
}

for _, index := range desc.Indexes {
if _, err := col.createIndex(ctx, index); err != nil {
result, err := db.getCollectionByID(ctx, desc.ID)
if err != nil {
return nil, err
}

returnDescriptions = append(returnDescriptions, result.Definition())
}

return db.getCollectionByID(ctx, desc.ID)
return returnDescriptions, nil
}

func (db *db) patchCollection(
Expand Down Expand Up @@ -171,7 +184,7 @@
return err
}

err = db.validateCollectionChanges(existingColsByID, newColsByID)
err = db.validateCollectionChanges(ctx, cols, newColsByID)
if err != nil {
return err
}
Expand Down
Loading
Loading