feat: add spec definition api with versioning
This commit is contained in:
166
internal/datastore/memory/spec_definition_repository.go
Normal file
166
internal/datastore/memory/spec_definition_repository.go
Normal file
@ -0,0 +1,166 @@
|
||||
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{}
|
14
internal/datastore/memory/spec_definition_repository_test.go
Normal file
14
internal/datastore/memory/spec_definition_repository_test.go
Normal file
@ -0,0 +1,14 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore/testsuite"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
func TestMemorySpecDefinitionRepository(t *testing.T) {
|
||||
logger.SetLevel(logger.LevelDebug)
|
||||
repo := NewSpecDefinitionRepository()
|
||||
testsuite.TestSpecDefinitionRepository(t, repo)
|
||||
}
|
Reference in New Issue
Block a user