package memory import ( "context" "slices" "sync" "time" "forge.cadoles.com/Cadoles/emissary/internal/datastore" "github.com/pkg/errors" ) type specDefRecord struct { Schema []byte CreatedAt time.Time UpdatedAt time.Time } type SpecDefinitionRepository struct { definitions map[string]map[string]specDefRecord mutex sync.RWMutex } // Delete implements datastore.SpecDefinitionRepository. func (r *SpecDefinitionRepository) Delete(ctx context.Context, name string, version string) error { r.mutex.Lock() defer r.mutex.Unlock() versions, exists := r.definitions[name] if !exists { return nil } delete(versions, version) r.definitions[name] = versions return nil } // Get implements datastore.SpecDefinitionRepository. func (r *SpecDefinitionRepository) Get(ctx context.Context, name string, version string) (*datastore.SpecDefinition, error) { r.mutex.RLock() defer r.mutex.RUnlock() versions, exists := r.definitions[name] if !exists { return nil, errors.WithStack(datastore.ErrNotFound) } rec, exists := versions[version] if !exists { return nil, errors.WithStack(datastore.ErrNotFound) } specDef := datastore.SpecDefinition{ SpecDefinitionHeader: datastore.SpecDefinitionHeader{ Name: name, Version: version, CreatedAt: rec.CreatedAt, UpdatedAt: rec.UpdatedAt, }, Schema: rec.Schema[:], } return &specDef, nil } // Query implements datastore.SpecDefinitionRepository. func (r *SpecDefinitionRepository) Query(ctx context.Context, opts ...datastore.SpecDefinitionQueryOptionFunc) ([]datastore.SpecDefinitionHeader, int, error) { options := &datastore.SpecDefinitionQueryOptions{} for _, fn := range opts { fn(options) } r.mutex.RLock() defer r.mutex.RUnlock() specDefs := make([]datastore.SpecDefinitionHeader, 0) count := 0 for name, versions := range r.definitions { for version, rec := range versions { count++ matches := true if options.Names != nil && !slices.Contains(options.Names, name) { matches = false } if options.Versions != nil && !slices.Contains(options.Versions, version) { matches = false } if options.Offset != nil && count < *options.Offset { matches = false } if options.Limit != nil && len(specDefs) >= *options.Limit { matches = false } if !matches { continue } specDefs = append(specDefs, datastore.SpecDefinitionHeader{ Name: name, Version: version, CreatedAt: rec.CreatedAt, UpdatedAt: rec.UpdatedAt, }) } } return specDefs, count, nil } // Upsert implements datastore.SpecDefinitionRepository. func (r *SpecDefinitionRepository) Upsert(ctx context.Context, name string, version string, schema []byte) (*datastore.SpecDefinition, error) { r.mutex.Lock() defer r.mutex.Unlock() versions, exists := r.definitions[name] if !exists { versions = make(map[string]specDefRecord) } now := time.Now().UTC() rec, exists := versions[version] if !exists { rec = specDefRecord{ CreatedAt: now, UpdatedAt: now, Schema: schema[:], } } else { rec.UpdatedAt = now rec.Schema = schema } versions[version] = rec r.definitions[name] = versions specDef := datastore.SpecDefinition{ SpecDefinitionHeader: datastore.SpecDefinitionHeader{ Name: name, Version: version, CreatedAt: rec.CreatedAt, UpdatedAt: rec.UpdatedAt, }, Schema: rec.Schema[:], } return &specDef, nil } func NewSpecDefinitionRepository() *SpecDefinitionRepository { return &SpecDefinitionRepository{ definitions: make(map[string]map[string]specDefRecord), } } var _ datastore.SpecDefinitionRepository = &SpecDefinitionRepository{}