diff --git a/.golangci.yml b/.golangci.yml index 504677d..274f169 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -35,6 +35,7 @@ linters: enable: - asciicheck - bodyclose + - copyloopvar - cyclop - dogsled - dupl @@ -43,7 +44,6 @@ linters: - errorlint - err113 - exhaustive - - exportloopref - forbidigo - forcetypeassert - funlen diff --git a/backends/ent/annotations.go b/backends/ent/annotations.go index 9ca0b1d..4c91244 100644 --- a/backends/ent/annotations.go +++ b/backends/ent/annotations.go @@ -13,6 +13,7 @@ import ( "github.com/protobom/storage/internal/backends/ent" "github.com/protobom/storage/internal/backends/ent/annotation" "github.com/protobom/storage/internal/backends/ent/document" + "github.com/protobom/storage/internal/backends/ent/predicate" ) func (backend *Backend) createAnnotations(data ...*ent.Annotation) error { @@ -27,7 +28,8 @@ func (backend *Backend) createAnnotations(data ...*ent.Annotation) error { builder := tx.Annotation.Create(). SetDocumentID(data[idx].DocumentID). SetName(data[idx].Name). - SetValue(data[idx].Value) + SetValue(data[idx].Value). + SetIsUnique(data[idx].IsUnique) builders = append(builders, builder) } @@ -77,14 +79,16 @@ func (backend *Backend) AddAnnotationToDocuments(name, value string, documentIDs // ClearAnnotations removes all annotations from the specified documents. func (backend *Backend) ClearAnnotations(documentIDs ...string) error { + if len(documentIDs) == 0 { + return nil + } + tx, err := backend.txClient() if err != nil { return err } - _, err = tx.Annotation.Delete(). - Where(annotation.DocumentIDIn(documentIDs...)). - Exec(backend.ctx) + _, err = tx.Annotation.Delete().Where(annotation.DocumentIDIn(documentIDs...)).Exec(backend.ctx) if err != nil { return rollback(tx, fmt.Errorf("clearing annotations: %w", err)) } @@ -96,32 +100,6 @@ func (backend *Backend) ClearAnnotations(documentIDs ...string) error { return nil } -// GetDocumentAlias gets the value for the annotation named "alias". -func (backend *Backend) GetDocumentAlias(documentID string) (string, error) { - if backend.client == nil { - return "", errUninitializedClient - } - - query := backend.client.Annotation.Query(). - Where( - annotation.And( - annotation.HasDocumentWith(document.IDEQ(documentID)), - annotation.NameEQ("alias"), - ), - ) - - result, err := query.Only(backend.ctx) - if err != nil { - if ent.IsNotFound(err) { - return "", nil - } - - return "", fmt.Errorf("retrieving document alias: %w", err) - } - - return result.Value, nil -} - // GetDocumentAnnotations gets all annotations for the specified // document, limited to a set of annotation names if specified. func (backend *Backend) GetDocumentAnnotations(documentID string, names ...string) (ent.Annotations, error) { @@ -129,14 +107,15 @@ func (backend *Backend) GetDocumentAnnotations(documentID string, names ...strin return nil, errUninitializedClient } - query := backend.client.Annotation.Query(). - Where(annotation.HasDocumentWith(document.IDEQ(documentID))) + predicates := []predicate.Annotation{ + annotation.HasDocumentWith(document.IDEQ(documentID)), + } if len(names) > 0 { - query.Where(annotation.NameIn(names...)) + predicates = append(predicates, annotation.NameIn(names...)) } - annotations, err := query.All(backend.ctx) + annotations, err := backend.client.Annotation.Query().Where(predicates...).All(backend.ctx) if err != nil { return nil, fmt.Errorf("querying annotations: %w", err) } @@ -151,16 +130,15 @@ func (backend *Backend) GetDocumentsByAnnotation(name string, values ...string) return nil, errUninitializedClient } - ids, err := backend.client.Document.Query(). - Where( - document.HasAnnotationsWith( - annotation.And( - annotation.NameEQ(name), - annotation.ValueIn(values...), - ), - ), - ). - IDs(backend.ctx) + predicates := []predicate.Document{ + document.HasAnnotationsWith(annotation.NameEQ(name)), + } + + if len(values) > 0 { + predicates = append(predicates, document.HasAnnotationsWith(annotation.ValueIn(values...))) + } + + ids, err := backend.client.Document.Query().Where(predicates...).IDs(backend.ctx) if err != nil { return nil, fmt.Errorf("querying documents table: %w", err) } @@ -168,6 +146,30 @@ func (backend *Backend) GetDocumentsByAnnotation(name string, values ...string) return backend.GetDocumentsByID(ids...) } +// GetDocumentUniqueAnnotation gets the value for a unique annotation. +func (backend *Backend) GetDocumentUniqueAnnotation(documentID, name string) (string, error) { + if backend.client == nil { + return "", errUninitializedClient + } + + result, err := backend.client.Annotation.Query(). + Where( + annotation.HasDocumentWith(document.IDEQ(documentID)), + annotation.NameEQ(name), + annotation.IsUniqueEQ(true), + ). + Only(backend.ctx) + if err != nil { + if ent.IsNotFound(err) { + return "", nil + } + + return "", fmt.Errorf("retrieving unique annotation for document: %w", err) + } + + return result.Value, nil +} + // RemoveAnnotations removes all annotations with the specified name from // the document, limited to a set of annotation values if specified. func (backend *Backend) RemoveAnnotations(documentID, name string, values ...string) error { @@ -176,16 +178,16 @@ func (backend *Backend) RemoveAnnotations(documentID, name string, values ...str return err } - _, err = tx.Annotation.Delete(). - Where( - annotation.And( - annotation.DocumentIDEQ(documentID), - annotation.NameEQ(name), - annotation.ValueIn(values...), - ), - ). - Exec(backend.ctx) - if err != nil { + predicates := []predicate.Annotation{ + annotation.DocumentIDEQ(documentID), + annotation.NameEQ(name), + } + + if len(values) > 0 { + predicates = append(predicates, annotation.ValueIn(values...)) + } + + if _, err := tx.Annotation.Delete().Where(predicates...).Exec(backend.ctx); err != nil { return rollback(tx, fmt.Errorf("removing annotations: %w", err)) } @@ -196,15 +198,6 @@ func (backend *Backend) RemoveAnnotations(documentID, name string, values ...str return nil } -// SetDocumentAlias set the value for the annotation named "alias". -func (backend *Backend) SetDocumentAlias(documentID, value string) error { - if err := backend.RemoveAnnotations(documentID, "alias"); err != nil { - return err - } - - return backend.AddAnnotations(documentID, "alias", value) -} - // SetAnnotations explicitly sets the named annotations for the specified document. func (backend *Backend) SetAnnotations(documentID, name string, values ...string) error { if err := backend.ClearAnnotations(documentID); err != nil { @@ -213,3 +206,13 @@ func (backend *Backend) SetAnnotations(documentID, name string, values ...string return backend.AddAnnotations(documentID, name, values...) } + +// SetUniqueAnnotation sets a named annotation value that is unique to the specified document. +func (backend *Backend) SetUniqueAnnotation(documentID, name, value string) error { + return backend.createAnnotations(&ent.Annotation{ + DocumentID: documentID, + Name: name, + Value: value, + IsUnique: true, + }) +} diff --git a/internal/backends/ent/annotation.go b/internal/backends/ent/annotation.go index 149466b..22e1be5 100644 --- a/internal/backends/ent/annotation.go +++ b/internal/backends/ent/annotation.go @@ -27,6 +27,8 @@ type Annotation struct { Name string `json:"name,omitempty"` // Value holds the value of the "value" field. Value string `json:"value,omitempty"` + // IsUnique holds the value of the "is_unique" field. + IsUnique bool `json:"is_unique,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the AnnotationQuery when eager-loading is set. Edges AnnotationEdges `json:"edges"` @@ -58,6 +60,8 @@ func (*Annotation) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { + case annotation.FieldIsUnique: + values[i] = new(sql.NullBool) case annotation.FieldID: values[i] = new(sql.NullInt64) case annotation.FieldDocumentID, annotation.FieldName, annotation.FieldValue: @@ -101,6 +105,12 @@ func (a *Annotation) assignValues(columns []string, values []any) error { } else if value.Valid { a.Value = value.String } + case annotation.FieldIsUnique: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field is_unique", values[i]) + } else if value.Valid { + a.IsUnique = value.Bool + } default: a.selectValues.Set(columns[i], values[i]) } @@ -150,6 +160,9 @@ func (a *Annotation) String() string { builder.WriteString(", ") builder.WriteString("value=") builder.WriteString(a.Value) + builder.WriteString(", ") + builder.WriteString("is_unique=") + builder.WriteString(fmt.Sprintf("%v", a.IsUnique)) builder.WriteByte(')') return builder.String() } diff --git a/internal/backends/ent/annotation/annotation.go b/internal/backends/ent/annotation/annotation.go index 94e607b..4667805 100644 --- a/internal/backends/ent/annotation/annotation.go +++ b/internal/backends/ent/annotation/annotation.go @@ -23,6 +23,8 @@ const ( FieldName = "name" // FieldValue holds the string denoting the value field in the database. FieldValue = "value" + // FieldIsUnique holds the string denoting the is_unique field in the database. + FieldIsUnique = "is_unique" // EdgeDocument holds the string denoting the document edge name in mutations. EdgeDocument = "document" // Table holds the table name of the annotation in the database. @@ -42,6 +44,7 @@ var Columns = []string{ FieldDocumentID, FieldName, FieldValue, + FieldIsUnique, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -54,6 +57,11 @@ func ValidColumn(column string) bool { return false } +var ( + // DefaultIsUnique holds the default value on creation for the "is_unique" field. + DefaultIsUnique bool +) + // OrderOption defines the ordering options for the Annotation queries. type OrderOption func(*sql.Selector) @@ -77,6 +85,11 @@ func ByValue(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldValue, opts...).ToFunc() } +// ByIsUnique orders the results by the is_unique field. +func ByIsUnique(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldIsUnique, opts...).ToFunc() +} + // ByDocumentField orders the results by document field. func ByDocumentField(field string, opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { diff --git a/internal/backends/ent/annotation/where.go b/internal/backends/ent/annotation/where.go index d073aa7..df8eadf 100644 --- a/internal/backends/ent/annotation/where.go +++ b/internal/backends/ent/annotation/where.go @@ -73,6 +73,11 @@ func Value(v string) predicate.Annotation { return predicate.Annotation(sql.FieldEQ(FieldValue, v)) } +// IsUnique applies equality check predicate on the "is_unique" field. It's identical to IsUniqueEQ. +func IsUnique(v bool) predicate.Annotation { + return predicate.Annotation(sql.FieldEQ(FieldIsUnique, v)) +} + // DocumentIDEQ applies the EQ predicate on the "document_id" field. func DocumentIDEQ(v string) predicate.Annotation { return predicate.Annotation(sql.FieldEQ(FieldDocumentID, v)) @@ -268,6 +273,16 @@ func ValueContainsFold(v string) predicate.Annotation { return predicate.Annotation(sql.FieldContainsFold(FieldValue, v)) } +// IsUniqueEQ applies the EQ predicate on the "is_unique" field. +func IsUniqueEQ(v bool) predicate.Annotation { + return predicate.Annotation(sql.FieldEQ(FieldIsUnique, v)) +} + +// IsUniqueNEQ applies the NEQ predicate on the "is_unique" field. +func IsUniqueNEQ(v bool) predicate.Annotation { + return predicate.Annotation(sql.FieldNEQ(FieldIsUnique, v)) +} + // HasDocument applies the HasEdge predicate on the "document" edge. func HasDocument() predicate.Annotation { return predicate.Annotation(func(s *sql.Selector) { diff --git a/internal/backends/ent/annotation_create.go b/internal/backends/ent/annotation_create.go index f76330e..45fa4b7 100644 --- a/internal/backends/ent/annotation_create.go +++ b/internal/backends/ent/annotation_create.go @@ -44,6 +44,20 @@ func (ac *AnnotationCreate) SetValue(s string) *AnnotationCreate { return ac } +// SetIsUnique sets the "is_unique" field. +func (ac *AnnotationCreate) SetIsUnique(b bool) *AnnotationCreate { + ac.mutation.SetIsUnique(b) + return ac +} + +// SetNillableIsUnique sets the "is_unique" field if the given value is not nil. +func (ac *AnnotationCreate) SetNillableIsUnique(b *bool) *AnnotationCreate { + if b != nil { + ac.SetIsUnique(*b) + } + return ac +} + // SetDocument sets the "document" edge to the Document entity. func (ac *AnnotationCreate) SetDocument(d *Document) *AnnotationCreate { return ac.SetDocumentID(d.ID) @@ -56,6 +70,7 @@ func (ac *AnnotationCreate) Mutation() *AnnotationMutation { // Save creates the Annotation in the database. func (ac *AnnotationCreate) Save(ctx context.Context) (*Annotation, error) { + ac.defaults() return withHooks(ctx, ac.sqlSave, ac.mutation, ac.hooks) } @@ -81,6 +96,14 @@ func (ac *AnnotationCreate) ExecX(ctx context.Context) { } } +// defaults sets the default values of the builder before save. +func (ac *AnnotationCreate) defaults() { + if _, ok := ac.mutation.IsUnique(); !ok { + v := annotation.DefaultIsUnique + ac.mutation.SetIsUnique(v) + } +} + // check runs all checks and user-defined validators on the builder. func (ac *AnnotationCreate) check() error { if _, ok := ac.mutation.DocumentID(); !ok { @@ -92,6 +115,9 @@ func (ac *AnnotationCreate) check() error { if _, ok := ac.mutation.Value(); !ok { return &ValidationError{Name: "value", err: errors.New(`ent: missing required field "Annotation.value"`)} } + if _, ok := ac.mutation.IsUnique(); !ok { + return &ValidationError{Name: "is_unique", err: errors.New(`ent: missing required field "Annotation.is_unique"`)} + } if len(ac.mutation.DocumentIDs()) == 0 { return &ValidationError{Name: "document", err: errors.New(`ent: missing required edge "Annotation.document"`)} } @@ -130,6 +156,10 @@ func (ac *AnnotationCreate) createSpec() (*Annotation, *sqlgraph.CreateSpec) { _spec.SetField(annotation.FieldValue, field.TypeString, value) _node.Value = value } + if value, ok := ac.mutation.IsUnique(); ok { + _spec.SetField(annotation.FieldIsUnique, field.TypeBool, value) + _node.IsUnique = value + } if nodes := ac.mutation.DocumentIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -235,6 +265,18 @@ func (u *AnnotationUpsert) UpdateValue() *AnnotationUpsert { return u } +// SetIsUnique sets the "is_unique" field. +func (u *AnnotationUpsert) SetIsUnique(v bool) *AnnotationUpsert { + u.Set(annotation.FieldIsUnique, v) + return u +} + +// UpdateIsUnique sets the "is_unique" field to the value that was provided on create. +func (u *AnnotationUpsert) UpdateIsUnique() *AnnotationUpsert { + u.SetExcluded(annotation.FieldIsUnique) + return u +} + // UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // @@ -317,6 +359,20 @@ func (u *AnnotationUpsertOne) UpdateValue() *AnnotationUpsertOne { }) } +// SetIsUnique sets the "is_unique" field. +func (u *AnnotationUpsertOne) SetIsUnique(v bool) *AnnotationUpsertOne { + return u.Update(func(s *AnnotationUpsert) { + s.SetIsUnique(v) + }) +} + +// UpdateIsUnique sets the "is_unique" field to the value that was provided on create. +func (u *AnnotationUpsertOne) UpdateIsUnique() *AnnotationUpsertOne { + return u.Update(func(s *AnnotationUpsert) { + s.UpdateIsUnique() + }) +} + // Exec executes the query. func (u *AnnotationUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -369,6 +425,7 @@ func (acb *AnnotationCreateBulk) Save(ctx context.Context) ([]*Annotation, error for i := range acb.builders { func(i int, root context.Context) { builder := acb.builders[i] + builder.defaults() var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { mutation, ok := m.(*AnnotationMutation) if !ok { @@ -562,6 +619,20 @@ func (u *AnnotationUpsertBulk) UpdateValue() *AnnotationUpsertBulk { }) } +// SetIsUnique sets the "is_unique" field. +func (u *AnnotationUpsertBulk) SetIsUnique(v bool) *AnnotationUpsertBulk { + return u.Update(func(s *AnnotationUpsert) { + s.SetIsUnique(v) + }) +} + +// UpdateIsUnique sets the "is_unique" field to the value that was provided on create. +func (u *AnnotationUpsertBulk) UpdateIsUnique() *AnnotationUpsertBulk { + return u.Update(func(s *AnnotationUpsert) { + s.UpdateIsUnique() + }) +} + // Exec executes the query. func (u *AnnotationUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/internal/backends/ent/annotation_update.go b/internal/backends/ent/annotation_update.go index 41a1168..868336b 100644 --- a/internal/backends/ent/annotation_update.go +++ b/internal/backends/ent/annotation_update.go @@ -74,6 +74,20 @@ func (au *AnnotationUpdate) SetNillableValue(s *string) *AnnotationUpdate { return au } +// SetIsUnique sets the "is_unique" field. +func (au *AnnotationUpdate) SetIsUnique(b bool) *AnnotationUpdate { + au.mutation.SetIsUnique(b) + return au +} + +// SetNillableIsUnique sets the "is_unique" field if the given value is not nil. +func (au *AnnotationUpdate) SetNillableIsUnique(b *bool) *AnnotationUpdate { + if b != nil { + au.SetIsUnique(*b) + } + return au +} + // SetDocument sets the "document" edge to the Document entity. func (au *AnnotationUpdate) SetDocument(d *Document) *AnnotationUpdate { return au.SetDocumentID(d.ID) @@ -143,6 +157,9 @@ func (au *AnnotationUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := au.mutation.Value(); ok { _spec.SetField(annotation.FieldValue, field.TypeString, value) } + if value, ok := au.mutation.IsUnique(); ok { + _spec.SetField(annotation.FieldIsUnique, field.TypeBool, value) + } if au.mutation.DocumentCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, @@ -234,6 +251,20 @@ func (auo *AnnotationUpdateOne) SetNillableValue(s *string) *AnnotationUpdateOne return auo } +// SetIsUnique sets the "is_unique" field. +func (auo *AnnotationUpdateOne) SetIsUnique(b bool) *AnnotationUpdateOne { + auo.mutation.SetIsUnique(b) + return auo +} + +// SetNillableIsUnique sets the "is_unique" field if the given value is not nil. +func (auo *AnnotationUpdateOne) SetNillableIsUnique(b *bool) *AnnotationUpdateOne { + if b != nil { + auo.SetIsUnique(*b) + } + return auo +} + // SetDocument sets the "document" edge to the Document entity. func (auo *AnnotationUpdateOne) SetDocument(d *Document) *AnnotationUpdateOne { return auo.SetDocumentID(d.ID) @@ -333,6 +364,9 @@ func (auo *AnnotationUpdateOne) sqlSave(ctx context.Context) (_node *Annotation, if value, ok := auo.mutation.Value(); ok { _spec.SetField(annotation.FieldValue, field.TypeString, value) } + if value, ok := auo.mutation.IsUnique(); ok { + _spec.SetField(annotation.FieldIsUnique, field.TypeBool, value) + } if auo.mutation.DocumentCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.M2O, diff --git a/internal/backends/ent/migrate/schema.go b/internal/backends/ent/migrate/schema.go index 743cf4e..5a1c2f7 100644 --- a/internal/backends/ent/migrate/schema.go +++ b/internal/backends/ent/migrate/schema.go @@ -19,6 +19,7 @@ var ( {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "name", Type: field.TypeString}, {Name: "value", Type: field.TypeString}, + {Name: "is_unique", Type: field.TypeBool, Default: false}, {Name: "document_id", Type: field.TypeString}, } // AnnotationsTable holds the schema information for the "annotations" table. @@ -29,23 +30,23 @@ var ( ForeignKeys: []*schema.ForeignKey{ { Symbol: "annotations_documents_annotations", - Columns: []*schema.Column{AnnotationsColumns[3]}, + Columns: []*schema.Column{AnnotationsColumns[4]}, RefColumns: []*schema.Column{DocumentsColumns[0]}, OnDelete: schema.NoAction, }, }, Indexes: []*schema.Index{ { - Name: "idx_annotation", + Name: "idx_annotations", Unique: true, - Columns: []*schema.Column{AnnotationsColumns[3], AnnotationsColumns[1], AnnotationsColumns[2]}, + Columns: []*schema.Column{AnnotationsColumns[4], AnnotationsColumns[1], AnnotationsColumns[2]}, }, { - Name: "idx_document_alias", + Name: "idx_document_unique_annotations", Unique: true, - Columns: []*schema.Column{AnnotationsColumns[3], AnnotationsColumns[1]}, + Columns: []*schema.Column{AnnotationsColumns[4], AnnotationsColumns[1]}, Annotation: &entsql.IndexAnnotation{ - Where: "name = 'alias'", + Where: "is_unique = true", }, }, }, diff --git a/internal/backends/ent/mutation.go b/internal/backends/ent/mutation.go index ebbe8e7..c7dce8e 100644 --- a/internal/backends/ent/mutation.go +++ b/internal/backends/ent/mutation.go @@ -63,6 +63,7 @@ type AnnotationMutation struct { id *int name *string value *string + is_unique *bool clearedFields map[string]struct{} document *string cleareddocument bool @@ -277,6 +278,42 @@ func (m *AnnotationMutation) ResetValue() { m.value = nil } +// SetIsUnique sets the "is_unique" field. +func (m *AnnotationMutation) SetIsUnique(b bool) { + m.is_unique = &b +} + +// IsUnique returns the value of the "is_unique" field in the mutation. +func (m *AnnotationMutation) IsUnique() (r bool, exists bool) { + v := m.is_unique + if v == nil { + return + } + return *v, true +} + +// OldIsUnique returns the old "is_unique" field's value of the Annotation entity. +// If the Annotation object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AnnotationMutation) OldIsUnique(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldIsUnique is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldIsUnique requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldIsUnique: %w", err) + } + return oldValue.IsUnique, nil +} + +// ResetIsUnique resets all changes to the "is_unique" field. +func (m *AnnotationMutation) ResetIsUnique() { + m.is_unique = nil +} + // ClearDocument clears the "document" edge to the Document entity. func (m *AnnotationMutation) ClearDocument() { m.cleareddocument = true @@ -338,7 +375,7 @@ func (m *AnnotationMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *AnnotationMutation) Fields() []string { - fields := make([]string, 0, 3) + fields := make([]string, 0, 4) if m.document != nil { fields = append(fields, annotation.FieldDocumentID) } @@ -348,6 +385,9 @@ func (m *AnnotationMutation) Fields() []string { if m.value != nil { fields = append(fields, annotation.FieldValue) } + if m.is_unique != nil { + fields = append(fields, annotation.FieldIsUnique) + } return fields } @@ -362,6 +402,8 @@ func (m *AnnotationMutation) Field(name string) (ent.Value, bool) { return m.Name() case annotation.FieldValue: return m.Value() + case annotation.FieldIsUnique: + return m.IsUnique() } return nil, false } @@ -377,6 +419,8 @@ func (m *AnnotationMutation) OldField(ctx context.Context, name string) (ent.Val return m.OldName(ctx) case annotation.FieldValue: return m.OldValue(ctx) + case annotation.FieldIsUnique: + return m.OldIsUnique(ctx) } return nil, fmt.Errorf("unknown Annotation field %s", name) } @@ -407,6 +451,13 @@ func (m *AnnotationMutation) SetField(name string, value ent.Value) error { } m.SetValue(v) return nil + case annotation.FieldIsUnique: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetIsUnique(v) + return nil } return fmt.Errorf("unknown Annotation field %s", name) } @@ -465,6 +516,9 @@ func (m *AnnotationMutation) ResetField(name string) error { case annotation.FieldValue: m.ResetValue() return nil + case annotation.FieldIsUnique: + m.ResetIsUnique() + return nil } return fmt.Errorf("unknown Annotation field %s", name) } diff --git a/internal/backends/ent/runtime.go b/internal/backends/ent/runtime.go index a494341..eb1d9d0 100644 --- a/internal/backends/ent/runtime.go +++ b/internal/backends/ent/runtime.go @@ -7,6 +7,7 @@ package ent import ( + "github.com/protobom/storage/internal/backends/ent/annotation" "github.com/protobom/storage/internal/backends/ent/metadata" "github.com/protobom/storage/internal/backends/ent/node" "github.com/protobom/storage/internal/backends/ent/schema" @@ -16,6 +17,12 @@ import ( // (default values, validators, hooks and policies) and stitches it // to their package variables. func init() { + annotationFields := schema.Annotation{}.Fields() + _ = annotationFields + // annotationDescIsUnique is the schema descriptor for is_unique field. + annotationDescIsUnique := annotationFields[3].Descriptor() + // annotation.DefaultIsUnique holds the default value on creation for the is_unique field. + annotation.DefaultIsUnique = annotationDescIsUnique.Default.(bool) metadataFields := schema.Metadata{}.Fields() _ = metadataFields // metadataDescID is the schema descriptor for id field. diff --git a/internal/backends/ent/runtime/runtime.go b/internal/backends/ent/runtime/runtime.go index d05d445..3022427 100644 --- a/internal/backends/ent/runtime/runtime.go +++ b/internal/backends/ent/runtime/runtime.go @@ -10,6 +10,6 @@ package runtime // The schema-stitching logic is generated in github.com/protobom/storage/internal/backends/ent/runtime.go const ( - Version = "v0.14.0" // Version of ent codegen. - Sum = "h1:EO3Z9aZ5bXJatJeGqu/EVdnNr6K4mRq3rWe5owt0MC4=" // Sum of ent codegen. + Version = "v0.14.1" // Version of ent codegen. + Sum = "h1:fUERL506Pqr92EPHJqr8EYxbPioflJo6PudkrEA8a/s=" // Sum of ent codegen. ) diff --git a/internal/backends/ent/schema/annotation.go b/internal/backends/ent/schema/annotation.go index 4bab838..d60d461 100644 --- a/internal/backends/ent/schema/annotation.go +++ b/internal/backends/ent/schema/annotation.go @@ -22,6 +22,8 @@ func (Annotation) Fields() []ent.Field { field.String("document_id"), field.String("name"), field.String("value"), + field.Bool("is_unique"). + Default(false), } } @@ -39,10 +41,10 @@ func (Annotation) Indexes() []ent.Index { return []ent.Index{ index.Fields("document_id", "name", "value"). Unique(). - StorageKey("idx_annotation"), + StorageKey("idx_annotations"), index.Fields("document_id", "name"). Unique(). - Annotations(entsql.IndexWhere("name = 'alias'")). - StorageKey("idx_document_alias"), + Annotations(entsql.IndexWhere("is_unique = true")). + StorageKey("idx_document_unique_annotations"), } }