emissary/internal/datastore/memory/spec_definition_repository.go

167 lines
3.6 KiB
Go

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{}