Compare commits

..

1 Commits

Author SHA1 Message Date
34b85e6a96 feat(storage): rpc based implementation
All checks were successful
arcad/edge/pipeline/pr-master This commit looks good
2023-09-28 11:02:30 -06:00
78 changed files with 324 additions and 284 deletions

View File

@ -25,7 +25,7 @@ watch: tools/modd/bin/modd
test: test-go
test-go:
go test -v -count=1 $(GOTEST_ARGS) ./...
go test -count=1 $(GOTEST_ARGS) ./...
lint:
golangci-lint run --enable-all $(LINT_ARGS)

View File

@ -27,9 +27,7 @@ import (
"forge.cadoles.com/arcad/edge/pkg/module/fetch"
netModule "forge.cadoles.com/arcad/edge/pkg/module/net"
shareModule "forge.cadoles.com/arcad/edge/pkg/module/share"
shareSqlite "forge.cadoles.com/arcad/edge/pkg/module/share/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/registry"
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/bundle"
@ -45,9 +43,11 @@ import (
_ "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/argon2id"
_ "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/plain"
// Register storage schemes
_ "forge.cadoles.com/arcad/edge/pkg/storage/rpc/registry"
_ "forge.cadoles.com/arcad/edge/pkg/storage/sqlite/registry"
// Register storage drivers
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
)
func RunCommand() *cli.Command {
@ -90,9 +90,10 @@ func RunCommand() *cli.Command {
Value: "sqlite://.edge/%APPID%/data.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
},
&cli.StringFlag{
Name: "shared-resources-file",
Usage: "use `FILE` for SQLite shared resources database",
Value: ".edge/shared-resources.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
Name: "sharestore-dsn",
Usage: "use `DSN` for share storage",
EnvVars: []string{"EDGE_SHARESTORE_DSN"},
Value: "sqlite://.edge/share.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
},
&cli.StringFlag{
Name: "accounts-file",
@ -108,8 +109,8 @@ func RunCommand() *cli.Command {
logLevel := ctx.Int("log-level")
blobstoreDSN := ctx.String("blobstore-dsn")
documentstoreDSN := ctx.String("documentstore-dsn")
shareStoreDSN := ctx.String("sharestore-dsn")
accountsFile := ctx.String("accounts-file")
sharedResourcesFile := ctx.String("shared-resources-file")
logger.SetFormat(logger.Format(logFormat))
logger.SetLevel(logger.Level(logLevel))
@ -155,7 +156,7 @@ func RunCommand() *cli.Command {
appCtx := logger.With(cmdCtx, logger.F("address", address))
if err := runApp(appCtx, path, address, documentstoreDSN, blobstoreDSN, accountsFile, appsRepository, sharedResourcesFile); err != nil {
if err := runApp(appCtx, path, address, documentstoreDSN, blobstoreDSN, shareStoreDSN, accountsFile, appsRepository); err != nil {
logger.Error(appCtx, "could not run app", logger.E(errors.WithStack(err)))
}
}(p, port, idx)
@ -168,7 +169,7 @@ func RunCommand() *cli.Command {
}
}
func runApp(ctx context.Context, path, address, documentStoreDSN, blobStoreDSN, accountsFile string, appRepository appModule.Repository, sharedResourcesFile string) error {
func runApp(ctx context.Context, path, address, documentStoreDSN, blobStoreDSN, shareStoreDSN, accountsFile string, appRepository appModule.Repository) error {
absPath, err := filepath.Abs(path)
if err != nil {
return errors.Wrapf(err, "could not resolve path '%s'", path)
@ -201,9 +202,8 @@ func runApp(ctx context.Context, path, address, documentStoreDSN, blobStoreDSN,
deps := &moduleDeps{}
funcs := []ModuleDepFunc{
initMemoryBus,
initDatastores(documentStoreDSN, blobStoreDSN, manifest.ID),
initDatastores(documentStoreDSN, blobStoreDSN, shareStoreDSN, manifest.ID),
initAccounts(accountsFile, manifest.ID),
initShareRepository(sharedResourcesFile),
initAppRepository(appRepository),
}
@ -254,13 +254,13 @@ func runApp(ctx context.Context, path, address, documentStoreDSN, blobStoreDSN,
}
type moduleDeps struct {
AppID app.ID
Bus bus.Bus
DocumentStore storage.DocumentStore
BlobStore storage.BlobStore
AppRepository appModule.Repository
ShareRepository shareModule.Repository
Accounts []authHTTP.LocalAccount
AppID app.ID
Bus bus.Bus
DocumentStore storage.DocumentStore
BlobStore storage.BlobStore
AppRepository appModule.Repository
ShareStore share.Store
Accounts []authHTTP.LocalAccount
}
type ModuleDepFunc func(*moduleDeps) error
@ -280,7 +280,7 @@ func getServerModules(deps *moduleDeps) []app.ServerModuleFactory {
),
appModule.ModuleFactory(deps.AppRepository),
fetch.ModuleFactory(deps.Bus),
shareModule.ModuleFactory(deps.AppID, deps.ShareRepository),
shareModule.ModuleFactory(deps.AppID, deps.ShareStore),
}
}
@ -448,11 +448,11 @@ func initMemoryBus(deps *moduleDeps) error {
return nil
}
func initDatastores(documentStoreDSN, blobStoreDSN string, appID app.ID) ModuleDepFunc {
func initDatastores(documentStoreDSN, blobStoreDSN, shareStoreDSN string, appID app.ID) ModuleDepFunc {
return func(deps *moduleDeps) error {
documentStoreDSN = injectAppID(documentStoreDSN, appID)
documentStore, err := registry.NewDocumentStore(documentStoreDSN)
documentStore, err := driver.NewDocumentStore(documentStoreDSN)
if err != nil {
return errors.WithStack(err)
}
@ -461,13 +461,20 @@ func initDatastores(documentStoreDSN, blobStoreDSN string, appID app.ID) ModuleD
blobStoreDSN = injectAppID(blobStoreDSN, appID)
blobStore, err := registry.NewBlobStore(blobStoreDSN)
blobStore, err := driver.NewBlobStore(blobStoreDSN)
if err != nil {
return errors.WithStack(err)
}
deps.BlobStore = blobStore
shareStore, err := driver.NewShareStore(shareStoreDSN)
if err != nil {
return errors.WithStack(err)
}
deps.ShareStore = shareStore
return nil
}
}
@ -486,17 +493,3 @@ func initAccounts(accountsFile string, appID app.ID) ModuleDepFunc {
return nil
}
}
func initShareRepository(shareRepositoryFile string) ModuleDepFunc {
return func(deps *moduleDeps) error {
if err := ensureDir(shareRepositoryFile); err != nil {
return errors.WithStack(err)
}
repo := shareSqlite.NewRepository(shareRepositoryFile)
deps.ShareRepository = repo
return nil
}
}

View File

@ -11,16 +11,16 @@ import (
"github.com/keegancsmith/rpc"
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/storage/registry"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server"
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
// Register storage schemes
_ "forge.cadoles.com/arcad/edge/pkg/storage/rpc/registry"
_ "forge.cadoles.com/arcad/edge/pkg/storage/sqlite/registry"
// Register storage drivers
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
)
func Run() *cli.Command {
@ -147,7 +147,7 @@ func getDocumentStoreServer(cacheSize int, cacheTTL time.Duration, tenant, appID
dsn := strings.ReplaceAll(dsnPattern, "%TENANT%", tenant)
dsn = strings.ReplaceAll(dsn, "%APPID%", appID)
documentStore, err := registry.NewDocumentStore(dsn)
documentStore, err := driver.NewDocumentStore(dsn)
if err != nil {
return nil, errors.WithStack(err)
}
@ -179,7 +179,7 @@ func getBlobStoreStoreServer(cacheSize int, cacheTTL time.Duration, tenant, appI
dsn := strings.ReplaceAll(dsnPattern, "%TENANT%", tenant)
dsn = strings.ReplaceAll(dsn, "%APPID%", appID)
blobStore, err := registry.NewBlobStore(dsn)
blobStore, err := driver.NewBlobStore(dsn)
if err != nil {
return nil, errors.WithStack(err)
}

View File

@ -1,14 +1,14 @@
package blob
import (
"io/ioutil"
"os"
"testing"
"cdr.dev/slog"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
"forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
@ -27,7 +27,7 @@ func TestBlobModule(t *testing.T) {
ModuleFactory(bus, store),
)
data, err := ioutil.ReadFile("testdata/blob.js")
data, err := os.ReadFile("testdata/blob.js")
if err != nil {
t.Fatal(err)
}

View File

@ -5,18 +5,19 @@ import (
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/module/util"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"github.com/dop251/goja"
"github.com/pkg/errors"
)
const (
AnyType ValueType = "*"
AnyName string = "*"
AnyType share.ValueType = "*"
AnyName string = "*"
)
type Module struct {
appID app.ID
repository Repository
appID app.ID
store share.Store
}
func (m *Module) Name() string {
@ -48,19 +49,19 @@ func (m *Module) Export(export *goja.Object) {
panic(errors.Wrap(err, "could not set 'ANY_NAME' property"))
}
if err := export.Set("TYPE_TEXT", TypeText); err != nil {
if err := export.Set("TYPE_TEXT", share.TypeText); err != nil {
panic(errors.Wrap(err, "could not set 'TYPE_TEXT' property"))
}
if err := export.Set("TYPE_NUMBER", TypeNumber); err != nil {
if err := export.Set("TYPE_NUMBER", share.TypeNumber); err != nil {
panic(errors.Wrap(err, "could not set 'TYPE_NUMBER' property"))
}
if err := export.Set("TYPE_BOOL", TypeBool); err != nil {
if err := export.Set("TYPE_BOOL", share.TypeBool); err != nil {
panic(errors.Wrap(err, "could not set 'TYPE_BOOL' property"))
}
if err := export.Set("TYPE_PATH", TypePath); err != nil {
if err := export.Set("TYPE_PATH", share.TypePath); err != nil {
panic(errors.Wrap(err, "could not set 'TYPE_PATH' property"))
}
}
@ -69,20 +70,20 @@ func (m *Module) upsertResource(call goja.FunctionCall, rt *goja.Runtime) goja.V
ctx := util.AssertContext(call.Argument(0), rt)
resourceID := assertResourceID(call.Argument(1), rt)
var attributes []Attribute
var attributes []share.Attribute
if len(call.Arguments) > 2 {
attributes = assertAttributes(call.Arguments[2:], rt)
} else {
attributes = make([]Attribute, 0)
attributes = make([]share.Attribute, 0)
}
for _, attr := range attributes {
if err := AssertType(attr.Value(), attr.Type()); err != nil {
if err := share.AssertType(attr.Value(), attr.Type()); err != nil {
panic(rt.ToValue(errors.WithStack(err)))
}
}
resource, err := m.repository.UpdateAttributes(ctx, m.appID, resourceID, attributes...)
resource, err := m.store.UpdateAttributes(ctx, m.appID, resourceID, attributes...)
if err != nil {
panic(rt.ToValue(errors.WithStack(err)))
}
@ -101,7 +102,7 @@ func (m *Module) deleteAttributes(call goja.FunctionCall, rt *goja.Runtime) goja
names = make([]string, 0)
}
err := m.repository.DeleteAttributes(ctx, m.appID, resourceID, names...)
err := m.store.DeleteAttributes(ctx, m.appID, resourceID, names...)
if err != nil {
panic(rt.ToValue(errors.WithStack(err)))
}
@ -112,23 +113,23 @@ func (m *Module) deleteAttributes(call goja.FunctionCall, rt *goja.Runtime) goja
func (m *Module) findResources(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
ctx := util.AssertContext(call.Argument(0), rt)
funcs := make([]FindResourcesOptionFunc, 0)
funcs := make([]share.FindResourcesOptionFunc, 0)
if len(call.Arguments) > 1 {
name := util.AssertString(call.Argument(1), rt)
if name != AnyName {
funcs = append(funcs, WithName(name))
funcs = append(funcs, share.WithName(name))
}
}
if len(call.Arguments) > 2 {
valueType := assertValueType(call.Argument(2), rt)
if valueType != AnyType {
funcs = append(funcs, WithType(valueType))
funcs = append(funcs, share.WithType(valueType))
}
}
resources, err := m.repository.FindResources(ctx, funcs...)
resources, err := m.store.FindResources(ctx, funcs...)
if err != nil {
panic(rt.ToValue(errors.WithStack(err)))
}
@ -140,7 +141,7 @@ func (m *Module) deleteResource(call goja.FunctionCall, rt *goja.Runtime) goja.V
ctx := util.AssertContext(call.Argument(0), rt)
resourceID := assertResourceID(call.Argument(1), rt)
err := m.repository.DeleteResource(ctx, m.appID, resourceID)
err := m.store.DeleteResource(ctx, m.appID, resourceID)
if err != nil {
panic(rt.ToValue(errors.WithStack(err)))
}
@ -148,29 +149,29 @@ func (m *Module) deleteResource(call goja.FunctionCall, rt *goja.Runtime) goja.V
return nil
}
func ModuleFactory(appID app.ID, repository Repository) app.ServerModuleFactory {
func ModuleFactory(appID app.ID, store share.Store) app.ServerModuleFactory {
return func(server *app.Server) app.ServerModule {
return &Module{
appID: appID,
repository: repository,
appID: appID,
store: store,
}
}
}
func assertResourceID(v goja.Value, r *goja.Runtime) ResourceID {
func assertResourceID(v goja.Value, r *goja.Runtime) share.ResourceID {
value := v.Export()
switch typ := value.(type) {
case string:
return ResourceID(typ)
case ResourceID:
return share.ResourceID(typ)
case share.ResourceID:
return typ
default:
panic(r.ToValue(errors.Errorf("expected value to be a string or ResourceID, got '%T'", value)))
}
}
func assertAttributes(values []goja.Value, r *goja.Runtime) []Attribute {
attributes := make([]Attribute, len(values))
func assertAttributes(values []goja.Value, r *goja.Runtime) []share.Attribute {
attributes := make([]share.Attribute, len(values))
for idx, val := range values {
export := val.Export()
@ -195,12 +196,12 @@ func assertAttributes(values []goja.Value, r *goja.Runtime) []Attribute {
panic(r.ToValue(errors.Errorf("could not find 'type' property on attribute '%v'", export)))
}
var valueType ValueType
var valueType share.ValueType
switch typ := rawType.(type) {
case ValueType:
case share.ValueType:
valueType = typ
case string:
valueType = ValueType(typ)
valueType = share.ValueType(typ)
default:
panic(r.ToValue(errors.Errorf("unexpected value for attribute property 'type': expected 'string' or 'ValueType', got '%T'", rawType)))
@ -211,7 +212,7 @@ func assertAttributes(values []goja.Value, r *goja.Runtime) []Attribute {
panic(r.ToValue(errors.Errorf("could not find 'value' property on attribute '%v'", export)))
}
attributes[idx] = NewBaseAttribute(
attributes[idx] = share.NewBaseAttribute(
name,
valueType,
value,
@ -232,12 +233,12 @@ func assertStrings(values []goja.Value, r *goja.Runtime) []string {
return strings
}
func assertValueType(v goja.Value, r *goja.Runtime) ValueType {
func assertValueType(v goja.Value, r *goja.Runtime) share.ValueType {
value := v.Export()
switch typ := value.(type) {
case string:
return ValueType(typ)
case ValueType:
return share.ValueType(typ)
case share.ValueType:
return typ
default:
panic(r.ToValue(errors.Errorf("expected value to be a string or ValueType, got '%T'", value)))
@ -245,7 +246,7 @@ func assertValueType(v goja.Value, r *goja.Runtime) ValueType {
}
type gojaResource struct {
ID ResourceID `goja:"id" json:"id"`
ID share.ResourceID `goja:"id" json:"id"`
Origin app.ID `goja:"origin" json:"origin"`
Attributes []*gojaAttribute `goja:"attributes" json:"attributes"`
}
@ -254,7 +255,7 @@ func (r *gojaResource) Has(call goja.FunctionCall, rt *goja.Runtime) goja.Value
name := util.AssertString(call.Argument(0), rt)
valueType := assertValueType(call.Argument(1), rt)
hasAttr := HasAttribute(toResource(r), name, valueType)
hasAttr := share.HasAttribute(toResource(r), name, valueType)
return rt.ToValue(hasAttr)
}
@ -268,7 +269,7 @@ func (r *gojaResource) Get(call goja.FunctionCall, rt *goja.Runtime) goja.Value
defaultValue = call.Argument(2).Export()
}
attr := GetAttribute(toResource(r), name, valueType)
attr := share.GetAttribute(toResource(r), name, valueType)
if attr == nil {
return rt.ToValue(defaultValue)
@ -278,14 +279,14 @@ func (r *gojaResource) Get(call goja.FunctionCall, rt *goja.Runtime) goja.Value
}
type gojaAttribute struct {
Name string `goja:"name" json:"name"`
Type ValueType `goja:"type" json:"type"`
Value any `goja:"value" json:"value"`
CreatedAt time.Time `goja:"createdAt" json:"createdAt"`
UpdatedAt time.Time `goja:"updatedAt" json:"updatedAt"`
Name string `goja:"name" json:"name"`
Type share.ValueType `goja:"type" json:"type"`
Value any `goja:"value" json:"value"`
CreatedAt time.Time `goja:"createdAt" json:"createdAt"`
UpdatedAt time.Time `goja:"updatedAt" json:"updatedAt"`
}
func toGojaResource(res Resource) *gojaResource {
func toGojaResource(res share.Resource) *gojaResource {
attributes := make([]*gojaAttribute, len(res.Attributes()))
for idx, attr := range res.Attributes() {
@ -305,7 +306,7 @@ func toGojaResource(res Resource) *gojaResource {
}
}
func toGojaResources(resources []Resource) []*gojaResource {
func toGojaResources(resources []share.Resource) []*gojaResource {
gojaResources := make([]*gojaResource, len(resources))
for idx, res := range resources {
gojaResources[idx] = toGojaResource(res)
@ -313,19 +314,19 @@ func toGojaResources(resources []Resource) []*gojaResource {
return gojaResources
}
func toResource(res *gojaResource) Resource {
return NewBaseResource(
func toResource(res *gojaResource) share.Resource {
return share.NewBaseResource(
res.Origin,
res.ID,
toAttributes(res.Attributes)...,
)
}
func toAttributes(gojaAttributes []*gojaAttribute) []Attribute {
attributes := make([]Attribute, len(gojaAttributes))
func toAttributes(gojaAttributes []*gojaAttribute) []share.Attribute {
attributes := make([]share.Attribute, len(gojaAttributes))
for idx, gojaAttr := range gojaAttributes {
attr := NewBaseAttribute(
attr := share.NewBaseAttribute(
gojaAttr.Name,
gojaAttr.Type,
gojaAttr.Value,

View File

@ -1,21 +1,23 @@
package testsuite
package share
import (
"context"
"io/fs"
"os"
"testing"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/module/share"
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
)
func TestModule(t *testing.T, newRepo NewTestRepoFunc) {
func TestModule(t *testing.T) {
logger.SetLevel(logger.LevelDebug)
repo, err := newRepo("module")
store, err := driver.NewShareStore("sqlite://testdata/test_share_module.sqlite")
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
@ -23,10 +25,10 @@ func TestModule(t *testing.T, newRepo NewTestRepoFunc) {
server := app.NewServer(
module.ContextModuleFactory(),
module.ConsoleModuleFactory(),
share.ModuleFactory("test.app.edge", repo),
ModuleFactory("test.app.edge", store),
)
data, err := fs.ReadFile(testData, "testdata/share.js")
data, err := os.ReadFile("testdata/share.js")
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}

View File

@ -1,13 +0,0 @@
package sqlite
import (
"testing"
"forge.cadoles.com/arcad/edge/pkg/module/share/testsuite"
"gitlab.com/wpetit/goweb/logger"
)
func TestModule(t *testing.T) {
logger.SetLevel(logger.LevelDebug)
testsuite.TestModule(t, newTestRepo)
}

View File

@ -1 +0,0 @@
*.sqlite*

View File

@ -1,16 +0,0 @@
package testsuite
import (
"testing"
"forge.cadoles.com/arcad/edge/pkg/module/share"
)
type NewTestRepoFunc func(testname string) (share.Repository, error)
func TestRepository(t *testing.T, newRepo NewTestRepoFunc) {
t.Run("Cases", func(t *testing.T) {
t.Parallel()
runRepositoryTests(t, newRepo)
})
}

View File

@ -2,12 +2,12 @@ package store
import (
"context"
"io/ioutil"
"os"
"testing"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
@ -22,7 +22,7 @@ func TestStoreModule(t *testing.T) {
ModuleFactory(store),
)
data, err := ioutil.ReadFile("testdata/store.js")
data, err := os.ReadFile("testdata/store.js")
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}

View File

@ -1,4 +1,4 @@
package registry
package driver
import (
"net/url"
@ -11,7 +11,7 @@ var blobStoreFactories = make(map[string]BlobStoreFactory, 0)
type BlobStoreFactory func(url *url.URL) (storage.BlobStore, error)
func AddBlobStoreFactory(scheme string, factory BlobStoreFactory) {
func RegisterBlobStoreFactory(scheme string, factory BlobStoreFactory) {
blobStoreFactories[scheme] = factory
}

View File

@ -1,4 +1,4 @@
package registry
package driver
import (
"net/url"
@ -11,7 +11,7 @@ var documentStoreFactories = make(map[string]DocumentStoreFactory, 0)
type DocumentStoreFactory func(url *url.URL) (storage.DocumentStore, error)
func AddDocumentStoreFactory(scheme string, factory DocumentStoreFactory) {
func RegisterDocumentStoreFactory(scheme string, factory DocumentStoreFactory) {
documentStoreFactories[scheme] = factory
}

View File

@ -1,4 +1,4 @@
package registry
package driver
import "errors"

View File

@ -5,7 +5,7 @@ import (
"io"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server/blob"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server/blob"
"github.com/pkg/errors"
)

View File

@ -8,7 +8,7 @@ import (
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server/blob"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server/blob"
"github.com/pkg/errors"
)

View File

@ -9,8 +9,8 @@ import (
"testing"
"time"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/testsuite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"

View File

@ -9,8 +9,8 @@ import (
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server/document"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server/document"
)
type DocumentStore struct {

View File

@ -9,8 +9,8 @@ import (
"testing"
"time"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/testsuite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"

View File

@ -3,7 +3,7 @@ package client
import (
"context"
_ "forge.cadoles.com/arcad/edge/pkg/storage/rpc/gob"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/gob"
)
type CallFunc func(ctx context.Context, serviceMethod string, args any, reply any) error

View File

@ -1,16 +1,16 @@
package registry
package rpc
import (
"net/url"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/registry"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/client"
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/client"
)
func init() {
registry.AddDocumentStoreFactory("rpc", documentStoreFactory)
registry.AddBlobStoreFactory("rpc", blobStoreFactory)
driver.RegisterDocumentStoreFactory("rpc", documentStoreFactory)
driver.RegisterBlobStoreFactory("rpc", blobStoreFactory)
}
func documentStoreFactory(url *url.URL) (storage.DocumentStore, error) {

View File

@ -4,7 +4,7 @@ import (
"context"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/gob"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/gob"
"github.com/pkg/errors"
)

View File

@ -0,0 +1,5 @@
package server
import (
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/gob"
)

View File

@ -4,8 +4,8 @@ import (
"github.com/keegancsmith/rpc"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server/blob"
"forge.cadoles.com/arcad/edge/pkg/storage/rpc/server/document"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server/blob"
"forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc/server/document"
)
func NewBlobStoreServer(store storage.BlobStore) *rpc.Server {

View File

@ -0,0 +1,35 @@
package driver
import (
"net/url"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"github.com/pkg/errors"
)
var shareStoreFactories = make(map[string]ShareStoreFactory, 0)
type ShareStoreFactory func(url *url.URL) (share.Store, error)
func RegisterShareStoreFactory(scheme string, factory ShareStoreFactory) {
shareStoreFactories[scheme] = factory
}
func NewShareStore(dsn string) (share.Store, error) {
url, err := url.Parse(dsn)
if err != nil {
return nil, errors.WithStack(err)
}
factory, exists := shareStoreFactories[url.Scheme]
if !exists {
return nil, errors.WithStack(ErrSchemeNotRegistered)
}
store, err := factory(url)
if err != nil {
return nil, errors.WithStack(err)
}
return store, nil
}

View File

@ -276,7 +276,7 @@ func (s *DocumentStore) withTx(ctx context.Context, fn func(tx *sql.Tx) error) e
return nil
}
func ensureTables(ctx context.Context, db *sql.DB) error {
func ensureDocumentTables(ctx context.Context, db *sql.DB) error {
err := WithTx(ctx, db, func(tx *sql.Tx) error {
query := `
CREATE TABLE IF NOT EXISTS documents (
@ -344,7 +344,7 @@ func withLimitOffsetClause(query string, args []any, limit int, offset int) (str
}
func NewDocumentStore(path string) *DocumentStore {
getDB := NewGetDBFunc(path, ensureTables)
getDB := NewGetDBFunc(path, ensureDocumentTables)
return &DocumentStore{
getDB: getDB,
@ -352,7 +352,7 @@ func NewDocumentStore(path string) *DocumentStore {
}
func NewDocumentStoreWithDB(db *sql.DB) *DocumentStore {
getDB := NewGetDBFuncFromDB(db, ensureTables)
getDB := NewGetDBFuncFromDB(db, ensureDocumentTables)
return &DocumentStore{
getDB: getDB,

View File

@ -0,0 +1,75 @@
package sqlite
import (
"net/url"
"os"
"path/filepath"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"github.com/pkg/errors"
)
func init() {
driver.RegisterDocumentStoreFactory("sqlite", documentStoreFactory)
driver.RegisterBlobStoreFactory("sqlite", blobStoreFactory)
driver.RegisterShareStoreFactory("sqlite", shareStoreFactory)
}
func documentStoreFactory(url *url.URL) (storage.DocumentStore, error) {
dir := filepath.Dir(url.Host + url.Path)
if dir != ":memory:" {
if err := os.MkdirAll(dir, os.FileMode(0750)); err != nil {
return nil, errors.WithStack(err)
}
}
path := url.Host + url.Path + "?" + url.RawQuery
db, err := Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
return NewDocumentStoreWithDB(db), nil
}
func blobStoreFactory(url *url.URL) (storage.BlobStore, error) {
dir := filepath.Dir(url.Host + url.Path)
if dir != ":memory:" {
if err := os.MkdirAll(dir, os.FileMode(0750)); err != nil {
return nil, errors.WithStack(err)
}
}
path := url.Host + url.Path + "?" + url.RawQuery
db, err := Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
return NewBlobStoreWithDB(db), nil
}
func shareStoreFactory(url *url.URL) (share.Store, error) {
dir := filepath.Dir(url.Host + url.Path)
if dir != ":memory:" {
if err := os.MkdirAll(dir, os.FileMode(0750)); err != nil {
return nil, errors.WithStack(err)
}
}
path := url.Host + url.Path + "?" + url.RawQuery
db, err := Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
return NewShareStoreWithDB(db), nil
}

View File

@ -7,19 +7,18 @@ import (
"time"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/module/share"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Repository struct {
getDB sqlite.GetDBFunc
type ShareStore struct {
getDB GetDBFunc
}
// DeleteAttributes implements share.Repository
func (r *Repository) DeleteAttributes(ctx context.Context, origin app.ID, resourceID share.ResourceID, names ...string) error {
err := r.withTx(ctx, func(tx *sql.Tx) error {
func (s *ShareStore) DeleteAttributes(ctx context.Context, origin app.ID, resourceID share.ResourceID, names ...string) error {
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
DELETE FROM resources
WHERE origin = $1 AND resource_id = $2
@ -76,8 +75,8 @@ func (r *Repository) DeleteAttributes(ctx context.Context, origin app.ID, resour
}
// DeleteResource implements share.Repository
func (r *Repository) DeleteResource(ctx context.Context, origin app.ID, resourceID share.ResourceID) error {
err := r.withTx(ctx, func(tx *sql.Tx) error {
func (s *ShareStore) DeleteResource(ctx context.Context, origin app.ID, resourceID share.ResourceID) error {
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
DELETE FROM resources
WHERE origin = $1 AND resource_id = $2
@ -115,12 +114,12 @@ func (r *Repository) DeleteResource(ctx context.Context, origin app.ID, resource
}
// FindResources implements share.Repository
func (r *Repository) FindResources(ctx context.Context, funcs ...share.FindResourcesOptionFunc) ([]share.Resource, error) {
func (s *ShareStore) FindResources(ctx context.Context, funcs ...share.FindResourcesOptionFunc) ([]share.Resource, error) {
opts := share.FillFindResourcesOptions(funcs...)
var resources []share.Resource
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
SELECT
main.origin, main.resource_id,
@ -222,14 +221,14 @@ func (r *Repository) FindResources(ctx context.Context, funcs ...share.FindResou
}
// GetResource implements share.Repository
func (r *Repository) GetResource(ctx context.Context, origin app.ID, resourceID share.ResourceID) (share.Resource, error) {
func (s *ShareStore) GetResource(ctx context.Context, origin app.ID, resourceID share.ResourceID) (share.Resource, error) {
var (
resource *share.BaseResource
err error
)
err = r.withTx(ctx, func(tx *sql.Tx) error {
resource, err = r.getResourceWithinTx(ctx, tx, origin, resourceID)
err = s.withTx(ctx, func(tx *sql.Tx) error {
resource, err = s.getResourceWithinTx(ctx, tx, origin, resourceID)
if err != nil {
return errors.WithStack(err)
}
@ -244,13 +243,13 @@ func (r *Repository) GetResource(ctx context.Context, origin app.ID, resourceID
}
// UpdateAttributes implements share.Repository
func (r *Repository) UpdateAttributes(ctx context.Context, origin app.ID, resourceID share.ResourceID, attributes ...share.Attribute) (share.Resource, error) {
func (s *ShareStore) UpdateAttributes(ctx context.Context, origin app.ID, resourceID share.ResourceID, attributes ...share.Attribute) (share.Resource, error) {
if len(attributes) == 0 {
return nil, errors.WithStack(share.ErrAttributeRequired)
}
var resource *share.BaseResource
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
INSERT INTO resources (origin, resource_id, name, type, value, created_at, updated_at)
VALUES($1, $2, $3, $4, $5, $6, $6)
@ -289,7 +288,7 @@ func (r *Repository) UpdateAttributes(ctx context.Context, origin app.ID, resour
}
}
resource, err = r.getResourceWithinTx(ctx, tx, origin, resourceID)
resource, err = s.getResourceWithinTx(ctx, tx, origin, resourceID)
if err != nil {
return errors.WithStack(err)
}
@ -303,7 +302,7 @@ func (r *Repository) UpdateAttributes(ctx context.Context, origin app.ID, resour
return resource, nil
}
func (r *Repository) getResourceWithinTx(ctx context.Context, tx *sql.Tx, origin app.ID, resourceID share.ResourceID) (*share.BaseResource, error) {
func (s *ShareStore) getResourceWithinTx(ctx context.Context, tx *sql.Tx, origin app.ID, resourceID share.ResourceID) (*share.BaseResource, error) {
query := `
SELECT name, type, value, created_at, updated_at
FROM resources
@ -361,23 +360,23 @@ func (r *Repository) getResourceWithinTx(ctx context.Context, tx *sql.Tx, origin
return resource, nil
}
func (r *Repository) withTx(ctx context.Context, fn func(tx *sql.Tx) error) error {
func (s *ShareStore) withTx(ctx context.Context, fn func(tx *sql.Tx) error) error {
var db *sql.DB
db, err := r.getDB(ctx)
db, err := s.getDB(ctx)
if err != nil {
return errors.WithStack(err)
}
if err := sqlite.WithTx(ctx, db, fn); err != nil {
if err := WithTx(ctx, db, fn); err != nil {
return errors.WithStack(err)
}
return nil
}
func ensureTables(ctx context.Context, db *sql.DB) error {
err := sqlite.WithTx(ctx, db, func(tx *sql.Tx) error {
func ensureShareTables(ctx context.Context, db *sql.DB) error {
err := WithTx(ctx, db, func(tx *sql.Tx) error {
query := `
CREATE TABLE IF NOT EXISTS resources (
resource_id TEXT NOT NULL,
@ -410,20 +409,20 @@ func ensureTables(ctx context.Context, db *sql.DB) error {
return nil
}
func NewRepository(path string) *Repository {
getDB := sqlite.NewGetDBFunc(path, ensureTables)
func NewShareStore(path string) *ShareStore {
getDB := NewGetDBFunc(path, ensureShareTables)
return &Repository{
return &ShareStore{
getDB: getDB,
}
}
func NewRepositoryWithDB(db *sql.DB) *Repository {
getDB := sqlite.NewGetDBFuncFromDB(db, ensureTables)
func NewShareStoreWithDB(db *sql.DB) *ShareStore {
getDB := NewGetDBFuncFromDB(db, ensureShareTables)
return &Repository{
return &ShareStore{
getDB: getDB,
}
}
var _ share.Repository = &Repository{}
var _ share.Store = &ShareStore{}

View File

@ -7,18 +7,18 @@ import (
"testing"
"time"
"forge.cadoles.com/arcad/edge/pkg/module/share"
"forge.cadoles.com/arcad/edge/pkg/module/share/testsuite"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"forge.cadoles.com/arcad/edge/pkg/storage/share/testsuite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func TestRepository(t *testing.T) {
logger.SetLevel(logger.LevelDebug)
testsuite.TestRepository(t, newTestRepo)
testsuite.TestStore(t, newTestStore)
}
func newTestRepo(testName string) (share.Repository, error) {
func newTestStore(testName string) (share.Store, error) {
filename := strings.ToLower(strings.ReplaceAll(testName, " ", "_"))
file := fmt.Sprintf("./testdata/%s.sqlite", filename)
@ -27,7 +27,7 @@ func newTestRepo(testName string) (share.Repository, error) {
}
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d", file, (60 * time.Second).Milliseconds())
repo := NewRepository(dsn)
store := NewShareStore(dsn)
return repo, nil
return store, nil
}

View File

@ -1,5 +0,0 @@
package server
import (
_ "forge.cadoles.com/arcad/edge/pkg/storage/rpc/gob"
)

View File

@ -23,7 +23,7 @@ type Attribute interface {
CreatedAt() time.Time
}
type Repository interface {
type Store interface {
DeleteResource(ctx context.Context, origin app.ID, resourceID ResourceID) error
FindResources(ctx context.Context, funcs ...FindResourcesOptionFunc) ([]Resource, error)
GetResource(ctx context.Context, origin app.ID, resourceID ResourceID) (Resource, error)

View File

@ -0,0 +1,16 @@
package testsuite
import (
"testing"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
)
type NewTestStoreFunc func(testname string) (share.Store, error)
func TestStore(t *testing.T, newStore NewTestStoreFunc) {
t.Run("Cases", func(t *testing.T) {
t.Parallel()
runRepositoryTests(t, newStore)
})
}

View File

@ -8,26 +8,26 @@ import (
"time"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/module/share"
"forge.cadoles.com/arcad/edge/pkg/storage/share"
"github.com/pkg/errors"
)
type repositoryTestCase struct {
Name string
Skip bool
Run func(ctx context.Context, t *testing.T, repo share.Repository) error
Run func(ctx context.Context, t *testing.T, store share.Store) error
}
var repositoryTestCases = []repositoryTestCase{
{
Name: "Update resource attributes",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
origin := app.ID("test")
resourceID := share.ResourceID("test")
// Try to create resource without attributes
_, err := repo.UpdateAttributes(ctx, origin, resourceID)
_, err := store.UpdateAttributes(ctx, origin, resourceID)
if err == nil {
return errors.New("err should not be nil")
}
@ -43,7 +43,7 @@ var repositoryTestCases = []repositoryTestCase{
share.NewBaseAttribute("my_bool_attr", share.TypeBool, true),
}
resource, err := repo.UpdateAttributes(ctx, origin, resourceID, attributes...)
resource, err := store.UpdateAttributes(ctx, origin, resourceID, attributes...)
if err != nil {
return errors.WithStack(err)
}
@ -71,12 +71,12 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Find resources by attribute name",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_name.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_name.json", store); err != nil {
return errors.WithStack(err)
}
resources, err := repo.FindResources(ctx, share.WithName("my_number"))
resources, err := store.FindResources(ctx, share.WithName("my_number"))
if err != nil {
return errors.WithStack(err)
}
@ -96,12 +96,12 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Find resources by attribute type",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_type.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_type.json", store); err != nil {
return errors.WithStack(err)
}
resources, err := repo.FindResources(ctx, share.WithType(share.TypePath))
resources, err := store.FindResources(ctx, share.WithType(share.TypePath))
if err != nil {
return errors.WithStack(err)
}
@ -121,12 +121,12 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Find resources by attribute type and name",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_type_and_name.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/find_resources_by_attribute_type_and_name.json", store); err != nil {
return errors.WithStack(err)
}
resources, err := repo.FindResources(ctx, share.WithType(share.TypeText), share.WithName("my_attr"))
resources, err := store.FindResources(ctx, share.WithType(share.TypeText), share.WithName("my_attr"))
if err != nil {
return errors.WithStack(err)
}
@ -146,15 +146,15 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Get resource",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/get_resource.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/get_resource.json", store); err != nil {
return errors.WithStack(err)
}
origin := app.ID("app1.edge.app")
resourceID := share.ResourceID("res-1")
resource, err := repo.GetResource(ctx, origin, resourceID)
resource, err := store.GetResource(ctx, origin, resourceID)
if err != nil {
return errors.WithStack(err)
}
@ -172,7 +172,7 @@ var repositoryTestCases = []repositoryTestCase{
return errors.Errorf("resource.ID(): expected '%v', got '%v'", e, g)
}
resource, err = repo.GetResource(ctx, origin, "unexistant-id")
resource, err = store.GetResource(ctx, origin, "unexistant-id")
if err == nil {
return errors.New("err should not be nil")
}
@ -187,8 +187,8 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Delete resource",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/delete_resource.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/delete_resource.json", store); err != nil {
return errors.WithStack(err)
}
@ -196,11 +196,11 @@ var repositoryTestCases = []repositoryTestCase{
resourceID := share.ResourceID("res-1")
// It should delete an existing resource
if err := repo.DeleteResource(ctx, origin, resourceID); err != nil {
if err := store.DeleteResource(ctx, origin, resourceID); err != nil {
return errors.WithStack(err)
}
_, err := repo.GetResource(ctx, origin, resourceID)
_, err := store.GetResource(ctx, origin, resourceID)
if err == nil {
return errors.New("err should not be nil")
}
@ -211,7 +211,7 @@ var repositoryTestCases = []repositoryTestCase{
}
// It should not delete an unexistant resource
err = repo.DeleteResource(ctx, origin, resourceID)
err = store.DeleteResource(ctx, origin, resourceID)
if err == nil {
return errors.New("err should not be nil")
}
@ -223,7 +223,7 @@ var repositoryTestCases = []repositoryTestCase{
otherOrigin := app.ID("app2.edge.app")
// It should not delete a resource with the same id and another origin
resource, err := repo.GetResource(ctx, otherOrigin, resourceID)
resource, err := store.GetResource(ctx, otherOrigin, resourceID)
if err != nil {
return errors.New("err should not be nil")
}
@ -238,8 +238,8 @@ var repositoryTestCases = []repositoryTestCase{
{
Name: "Delete attributes",
Skip: false,
Run: func(ctx context.Context, t *testing.T, repo share.Repository) error {
if err := loadTestData(ctx, "testdata/delete_attributes.json", repo); err != nil {
Run: func(ctx context.Context, t *testing.T, store share.Store) error {
if err := loadTestData(ctx, "testdata/delete_attributes.json", store); err != nil {
return errors.WithStack(err)
}
@ -247,11 +247,11 @@ var repositoryTestCases = []repositoryTestCase{
resourceID := share.ResourceID("res-1")
// It should delete specified attributes
if err := repo.DeleteAttributes(ctx, origin, resourceID, "my_text", "my_bool"); err != nil {
if err := store.DeleteAttributes(ctx, origin, resourceID, "my_text", "my_bool"); err != nil {
return errors.WithStack(err)
}
resource, err := repo.GetResource(ctx, origin, resourceID)
resource, err := store.GetResource(ctx, origin, resourceID)
if err != nil {
return errors.WithStack(err)
}
@ -270,7 +270,7 @@ var repositoryTestCases = []repositoryTestCase{
},
}
func runRepositoryTests(t *testing.T, newRepo NewTestRepoFunc) {
func runRepositoryTests(t *testing.T, newRepo NewTestStoreFunc) {
for _, tc := range repositoryTestCases {
func(tc repositoryTestCase) {
t.Run(tc.Name, func(t *testing.T) {
@ -311,7 +311,7 @@ type jsonAttribute struct {
UpdatedAt time.Time `json:"updatedAt"`
}
func loadTestData(ctx context.Context, jsonFile string, repo share.Repository) error {
func loadTestData(ctx context.Context, jsonFile string, store share.Store) error {
data, err := testData.ReadFile(jsonFile)
if err != nil {
return errors.WithStack(err)
@ -334,7 +334,7 @@ func loadTestData(ctx context.Context, jsonFile string, repo share.Repository) e
)
}
_, err := repo.UpdateAttributes(ctx, app.ID(res.Origin), share.ResourceID(res.ID), attributes...)
_, err := store.UpdateAttributes(ctx, app.ID(res.Origin), share.ResourceID(res.ID), attributes...)
if err != nil {
return errors.WithStack(err)
}

View File

@ -1,51 +0,0 @@
package registry
import (
"net/url"
"os"
"path/filepath"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/registry"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"github.com/pkg/errors"
)
func init() {
registry.AddDocumentStoreFactory("sqlite", documentStoreFactory)
registry.AddBlobStoreFactory("sqlite", blobStoreFactory)
}
func documentStoreFactory(url *url.URL) (storage.DocumentStore, error) {
dir := filepath.Dir(url.Host + url.Path)
if err := os.MkdirAll(dir, os.FileMode(0750)); err != nil {
return nil, errors.WithStack(err)
}
path := url.Host + url.Path + "?" + url.RawQuery
db, err := sqlite.Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
return sqlite.NewDocumentStoreWithDB(db), nil
}
func blobStoreFactory(url *url.URL) (storage.BlobStore, error) {
dir := filepath.Dir(url.Host + url.Path)
if err := os.MkdirAll(dir, os.FileMode(0750)); err != nil {
return nil, errors.WithStack(err)
}
path := url.Host + url.Path + "?" + url.RawQuery
db, err := sqlite.Open(path)
if err != nil {
return nil, errors.WithStack(err)
}
return sqlite.NewBlobStoreWithDB(db), nil
}