Compare commits
No commits in common. "776dbba5b09c04170bbac5a030546f36c1390f7a" and "a268759d330fba4ea0bbe45bb8e759c92d875b09" have entirely different histories.
776dbba5b0
...
a268759d33
@ -9,16 +9,12 @@ import (
|
|||||||
"github.com/oklog/ulid/v2"
|
"github.com/oklog/ulid/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var ErrDocumentNotFound = errors.New("document not found")
|
||||||
ErrDocumentNotFound = errors.New("document not found")
|
|
||||||
ErrDocumentRevisionConflict = errors.New("document revision conflict")
|
|
||||||
)
|
|
||||||
|
|
||||||
type DocumentID string
|
type DocumentID string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DocumentAttrID = "_id"
|
DocumentAttrID = "_id"
|
||||||
DocumentAttrRevision = "_revision"
|
|
||||||
DocumentAttrCreatedAt = "_createdAt"
|
DocumentAttrCreatedAt = "_createdAt"
|
||||||
DocumentAttrUpdatedAt = "_updatedAt"
|
DocumentAttrUpdatedAt = "_updatedAt"
|
||||||
)
|
)
|
||||||
@ -48,20 +44,6 @@ func (d Document) ID() (DocumentID, bool) {
|
|||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d Document) Revision() (int, bool) {
|
|
||||||
rawRevision, exists := d[DocumentAttrRevision]
|
|
||||||
if !exists {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
revision, ok := rawRevision.(int)
|
|
||||||
if ok {
|
|
||||||
return revision, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d Document) CreatedAt() (time.Time, bool) {
|
func (d Document) CreatedAt() (time.Time, bool) {
|
||||||
return d.timeAttr(DocumentAttrCreatedAt)
|
return d.timeAttr(DocumentAttrCreatedAt)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func TestBlobStore(t *testing.T) {
|
|||||||
t.Fatalf("%+v", errors.WithStack(err))
|
t.Fatalf("%+v", errors.WithStack(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d&_pragma=journal_mode=wal", file, (60 * time.Second).Milliseconds())
|
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d", file, (60 * time.Second).Milliseconds())
|
||||||
store := NewBlobStore(dsn)
|
store := NewBlobStore(dsn)
|
||||||
|
|
||||||
testsuite.TestBlobStore(context.Background(), t, store)
|
testsuite.TestBlobStore(context.Background(), t, store)
|
||||||
|
@ -13,14 +13,9 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
|
||||||
_ "embed"
|
|
||||||
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed document_store.sql
|
|
||||||
var documentStoreSchema string
|
|
||||||
|
|
||||||
type DocumentStore struct {
|
type DocumentStore struct {
|
||||||
getDB GetDBFunc
|
getDB GetDBFunc
|
||||||
}
|
}
|
||||||
@ -53,7 +48,7 @@ func (s *DocumentStore) Get(ctx context.Context, collection string, id storage.D
|
|||||||
|
|
||||||
err := s.withTx(ctx, func(tx *sql.Tx) error {
|
err := s.withTx(ctx, func(tx *sql.Tx) error {
|
||||||
query := `
|
query := `
|
||||||
SELECT id, revision, data, created_at, updated_at
|
SELECT id, data, created_at, updated_at
|
||||||
FROM documents
|
FROM documents
|
||||||
WHERE collection = $1 AND id = $2
|
WHERE collection = $1 AND id = $2
|
||||||
`
|
`
|
||||||
@ -64,10 +59,9 @@ func (s *DocumentStore) Get(ctx context.Context, collection string, id storage.D
|
|||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
updatedAt time.Time
|
updatedAt time.Time
|
||||||
data JSONMap
|
data JSONMap
|
||||||
revision int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
err := row.Scan(&id, &revision, &data, &createdAt, &updatedAt)
|
err := row.Scan(&id, &data, &createdAt, &updatedAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return errors.WithStack(storage.ErrDocumentNotFound)
|
return errors.WithStack(storage.ErrDocumentNotFound)
|
||||||
@ -83,7 +77,6 @@ func (s *DocumentStore) Get(ctx context.Context, collection string, id storage.D
|
|||||||
document = storage.Document(data)
|
document = storage.Document(data)
|
||||||
|
|
||||||
document[storage.DocumentAttrID] = id
|
document[storage.DocumentAttrID] = id
|
||||||
document[storage.DocumentAttrRevision] = revision
|
|
||||||
document[storage.DocumentAttrCreatedAt] = createdAt
|
document[storage.DocumentAttrCreatedAt] = createdAt
|
||||||
document[storage.DocumentAttrUpdatedAt] = updatedAt
|
document[storage.DocumentAttrUpdatedAt] = updatedAt
|
||||||
|
|
||||||
@ -126,7 +119,7 @@ func (s *DocumentStore) Query(ctx context.Context, collection string, filter *fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
SELECT id, revision, data, created_at, updated_at
|
SELECT id, data, created_at, updated_at
|
||||||
FROM documents
|
FROM documents
|
||||||
WHERE collection = $1 AND (` + criteria + `)
|
WHERE collection = $1 AND (` + criteria + `)
|
||||||
`
|
`
|
||||||
@ -178,19 +171,17 @@ func (s *DocumentStore) Query(ctx context.Context, collection string, filter *fi
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
id storage.DocumentID
|
id storage.DocumentID
|
||||||
revision int
|
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
updatedAt time.Time
|
updatedAt time.Time
|
||||||
data JSONMap
|
data JSONMap
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := rows.Scan(&id, &revision, &data, &createdAt, &updatedAt); err != nil {
|
if err := rows.Scan(&id, &data, &createdAt, &updatedAt); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
document := storage.Document(data)
|
document := storage.Document(data)
|
||||||
document[storage.DocumentAttrID] = id
|
document[storage.DocumentAttrID] = id
|
||||||
document[storage.DocumentAttrRevision] = revision
|
|
||||||
document[storage.DocumentAttrCreatedAt] = createdAt
|
document[storage.DocumentAttrCreatedAt] = createdAt
|
||||||
document[storage.DocumentAttrUpdatedAt] = updatedAt
|
document[storage.DocumentAttrUpdatedAt] = updatedAt
|
||||||
|
|
||||||
@ -215,16 +206,22 @@ func (s *DocumentStore) Upsert(ctx context.Context, collection string, document
|
|||||||
var upsertedDocument storage.Document
|
var upsertedDocument storage.Document
|
||||||
|
|
||||||
err := s.withTx(ctx, func(tx *sql.Tx) error {
|
err := s.withTx(ctx, func(tx *sql.Tx) error {
|
||||||
|
query := `
|
||||||
|
INSERT INTO documents (id, collection, data, created_at, updated_at)
|
||||||
|
VALUES($1, $2, $3, $4, $4)
|
||||||
|
ON CONFLICT (id, collection) DO UPDATE SET
|
||||||
|
data = $3, updated_at = $4
|
||||||
|
RETURNING "id", "data", "created_at", "updated_at"
|
||||||
|
`
|
||||||
|
|
||||||
|
now := time.Now().UTC()
|
||||||
|
|
||||||
id, exists := document.ID()
|
id, exists := document.ID()
|
||||||
if !exists || id == "" {
|
if !exists || id == "" {
|
||||||
id = storage.NewDocumentID()
|
id = storage.NewDocumentID()
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `
|
args := []any{id, collection, JSONMap(document), now, now}
|
||||||
SELECT revision FROM documents WHERE id = $1
|
|
||||||
`
|
|
||||||
|
|
||||||
args := []any{id}
|
|
||||||
|
|
||||||
logger.Debug(
|
logger.Debug(
|
||||||
ctx, "executing query",
|
ctx, "executing query",
|
||||||
@ -234,44 +231,14 @@ func (s *DocumentStore) Upsert(ctx context.Context, collection string, document
|
|||||||
|
|
||||||
row := tx.QueryRowContext(ctx, query, args...)
|
row := tx.QueryRowContext(ctx, query, args...)
|
||||||
|
|
||||||
var storedRevision int
|
|
||||||
|
|
||||||
if err := row.Scan(&storedRevision); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
revision, found := document.Revision()
|
|
||||||
if found && storedRevision != revision {
|
|
||||||
return errors.Wrapf(storage.ErrDocumentRevisionConflict, "document revision '%d' does not match stored '%d'", revision, storedRevision)
|
|
||||||
}
|
|
||||||
|
|
||||||
query = `
|
|
||||||
INSERT INTO documents (id, collection, data, created_at, updated_at)
|
|
||||||
VALUES($1, $2, $3, $4, $4)
|
|
||||||
ON CONFLICT (id, collection) DO UPDATE SET
|
|
||||||
data = $3, updated_at = $4, revision = revision + 1
|
|
||||||
RETURNING "id", "revision", "data", "created_at", "updated_at"
|
|
||||||
`
|
|
||||||
|
|
||||||
now := time.Now().UTC()
|
|
||||||
|
|
||||||
args = []any{id, collection, JSONMap(document), now, now}
|
|
||||||
|
|
||||||
logger.Debug(
|
|
||||||
ctx, "executing query",
|
|
||||||
logger.F("query", query),
|
|
||||||
logger.F("args", args),
|
|
||||||
)
|
|
||||||
|
|
||||||
row = tx.QueryRowContext(ctx, query, args...)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
createdAt time.Time
|
createdAt time.Time
|
||||||
updatedAt time.Time
|
updatedAt time.Time
|
||||||
data JSONMap
|
data JSONMap
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := row.Scan(&id, &revision, &data, &createdAt, &updatedAt); err != nil {
|
err := row.Scan(&id, &data, &createdAt, &updatedAt)
|
||||||
|
if err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +249,6 @@ func (s *DocumentStore) Upsert(ctx context.Context, collection string, document
|
|||||||
upsertedDocument = storage.Document(data)
|
upsertedDocument = storage.Document(data)
|
||||||
|
|
||||||
upsertedDocument[storage.DocumentAttrID] = id
|
upsertedDocument[storage.DocumentAttrID] = id
|
||||||
upsertedDocument[storage.DocumentAttrRevision] = revision
|
|
||||||
upsertedDocument[storage.DocumentAttrCreatedAt] = createdAt
|
upsertedDocument[storage.DocumentAttrCreatedAt] = createdAt
|
||||||
upsertedDocument[storage.DocumentAttrUpdatedAt] = updatedAt
|
upsertedDocument[storage.DocumentAttrUpdatedAt] = updatedAt
|
||||||
|
|
||||||
@ -310,13 +276,29 @@ func (s *DocumentStore) withTx(ctx context.Context, fn func(tx *sql.Tx) error) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateSchema(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 {
|
err := WithTx(ctx, db, func(tx *sql.Tx) error {
|
||||||
for _, migr := range documentStoreMigrations {
|
query := `
|
||||||
if err := migr(ctx, tx); err != nil {
|
CREATE TABLE IF NOT EXISTS documents (
|
||||||
return errors.WithStack(err)
|
id TEXT PRIMARY KEY,
|
||||||
}
|
collection TEXT NOT NULL,
|
||||||
|
data TEXT,
|
||||||
|
created_at TIMESTAMP NOT NULL,
|
||||||
|
updated_at TIMESTAMP NOT NULL,
|
||||||
|
UNIQUE(id, collection) ON CONFLICT REPLACE
|
||||||
|
);
|
||||||
|
`
|
||||||
|
if _, err := tx.ExecContext(ctx, query); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query = `
|
||||||
|
CREATE INDEX IF NOT EXISTS collection_idx ON documents (collection);
|
||||||
|
`
|
||||||
|
if _, err := tx.ExecContext(ctx, query); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -362,7 +344,7 @@ func withLimitOffsetClause(query string, args []any, limit int, offset int) (str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDocumentStore(path string) *DocumentStore {
|
func NewDocumentStore(path string) *DocumentStore {
|
||||||
getDB := NewGetDBFunc(path, migrateSchema)
|
getDB := NewGetDBFunc(path, ensureDocumentTables)
|
||||||
|
|
||||||
return &DocumentStore{
|
return &DocumentStore{
|
||||||
getDB: getDB,
|
getDB: getDB,
|
||||||
@ -370,7 +352,7 @@ func NewDocumentStore(path string) *DocumentStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDocumentStoreWithDB(db *sql.DB) *DocumentStore {
|
func NewDocumentStoreWithDB(db *sql.DB) *DocumentStore {
|
||||||
getDB := NewGetDBFuncFromDB(db, migrateSchema)
|
getDB := NewGetDBFuncFromDB(db, ensureDocumentTables)
|
||||||
|
|
||||||
return &DocumentStore{
|
return &DocumentStore{
|
||||||
getDB: getDB,
|
getDB: getDB,
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS documents (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
collection TEXT NOT NULL,
|
|
||||||
data TEXT,
|
|
||||||
created_at TIMESTAMP NOT NULL,
|
|
||||||
updated_at TIMESTAMP NOT NULL,
|
|
||||||
UNIQUE(id, collection) ON CONFLICT REPLACE
|
|
||||||
);
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS collection_idx ON documents (collection);
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
ALTER TABLE documents ADD COLUMN revision INTEGER DEFAULT 0;
|
|
@ -1,98 +0,0 @@
|
|||||||
package sqlite
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MigrateFunc func(ctx context.Context, tx *sql.Tx) error
|
|
||||||
|
|
||||||
var documentStoreMigrations = []MigrateFunc{
|
|
||||||
documentStoreMigrationBaseSchema,
|
|
||||||
documentStoreMigrationAddIDIndex,
|
|
||||||
documentStoreMigrationAddRevisionColumn,
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentStoreMigrationBaseSchema(ctx context.Context, tx *sql.Tx) error {
|
|
||||||
query := `
|
|
||||||
CREATE TABLE IF NOT EXISTS documents (
|
|
||||||
id TEXT PRIMARY KEY,
|
|
||||||
collection TEXT NOT NULL,
|
|
||||||
data TEXT,
|
|
||||||
created_at TIMESTAMP NOT NULL,
|
|
||||||
updated_at TIMESTAMP NOT NULL,
|
|
||||||
UNIQUE(id, collection) ON CONFLICT REPLACE
|
|
||||||
);
|
|
||||||
`
|
|
||||||
|
|
||||||
if _, err := tx.ExecContext(ctx, query); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentStoreMigrationAddIDIndex(ctx context.Context, tx *sql.Tx) error {
|
|
||||||
query := `
|
|
||||||
CREATE INDEX IF NOT EXISTS collection_idx ON documents (collection);
|
|
||||||
`
|
|
||||||
|
|
||||||
if _, err := tx.ExecContext(ctx, query); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentStoreMigrationAddRevisionColumn(ctx context.Context, tx *sql.Tx) error {
|
|
||||||
query := `PRAGMA table_info(documents)`
|
|
||||||
|
|
||||||
rows, err := tx.QueryContext(ctx, query)
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := rows.Close(); err != nil {
|
|
||||||
logger.Error(ctx, "could not close rows", logger.CapturedE(errors.WithStack(err)))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var hasRevisionColumn bool
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
var (
|
|
||||||
id int
|
|
||||||
name string
|
|
||||||
dataType string
|
|
||||||
nullable int
|
|
||||||
defaultValue any
|
|
||||||
primaryKey int
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := rows.Scan(&id, &name, &dataType, &nullable, &defaultValue, &primaryKey); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == "revision" {
|
|
||||||
hasRevisionColumn = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasRevisionColumn {
|
|
||||||
query = `ALTER TABLE documents ADD COLUMN revision INTEGER DEFAULT 0`
|
|
||||||
if _, err := tx.ExecContext(ctx, query); err != nil {
|
|
||||||
return errors.WithStack(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ func TestDocumentStore(t *testing.T) {
|
|||||||
t.Fatalf("%+v", errors.WithStack(err))
|
t.Fatalf("%+v", errors.WithStack(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d&_pragma=journal_mode=wal", file, (60 * time.Second).Milliseconds())
|
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d", file, (60 * time.Second).Milliseconds())
|
||||||
store := NewDocumentStore(dsn)
|
store := NewDocumentStore(dsn)
|
||||||
|
|
||||||
testsuite.TestDocumentStore(context.Background(), t, store)
|
testsuite.TestDocumentStore(context.Background(), t, store)
|
||||||
|
@ -26,7 +26,7 @@ func newTestStore(testName string) (share.Store, error) {
|
|||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d&_pragma=journal_mode=wal", file, (60 * time.Second).Milliseconds())
|
dsn := fmt.Sprintf("%s?_pragma=foreign_keys(1)&_pragma=busy_timeout=%d", file, (60 * time.Second).Milliseconds())
|
||||||
store := NewShareStore(dsn)
|
store := NewShareStore(dsn)
|
||||||
|
|
||||||
return store, nil
|
return store, nil
|
||||||
|
@ -185,13 +185,8 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
|
|||||||
return errors.Errorf("upsertedDoc[\"attr1\"]: expected '%v', got '%v'", e, g)
|
return errors.Errorf("upsertedDoc[\"attr1\"]: expected '%v', got '%v'", e, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
upsertedDocRevision, _ := upsertedDoc.Revision()
|
|
||||||
if e, g := 0, upsertedDocRevision; e != g {
|
|
||||||
return errors.Errorf("upsertedDoc.Revision(): expected '%v', got '%v'", e, g)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that document does not have unexpected properties
|
// Check that document does not have unexpected properties
|
||||||
if e, g := 5, len(upsertedDoc); e != g {
|
if e, g := 4, len(upsertedDoc); e != g {
|
||||||
return errors.Errorf("len(upsertedDoc): expected '%v', got '%v'", e, g)
|
return errors.Errorf("len(upsertedDoc): expected '%v', got '%v'", e, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,11 +217,6 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
|
|||||||
return errors.New("upsertedDoc2.UpdatedAt() should have been different than upsertedDoc.UpdatedAt()")
|
return errors.New("upsertedDoc2.UpdatedAt() should have been different than upsertedDoc.UpdatedAt()")
|
||||||
}
|
}
|
||||||
|
|
||||||
upsertedDoc2Revision, _ := upsertedDoc2.Revision()
|
|
||||||
if e, g := 1, upsertedDoc2Revision; e != g {
|
|
||||||
return errors.Errorf("upsertedDoc.Revision(): expected '%v', got '%v'", e, g)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that there is no additional created document in the collection
|
// Verify that there is no additional created document in the collection
|
||||||
|
|
||||||
results, err := store.Query(ctx, collection, nil)
|
results, err := store.Query(ctx, collection, nil)
|
||||||
@ -238,11 +228,6 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
|
|||||||
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
|
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
firstResultRevision, _ := results[0].Revision()
|
|
||||||
if e, g := 1, firstResultRevision; e != g {
|
|
||||||
return errors.Errorf("results[0].Revision(): expected '%v', got '%v'", e, g)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -452,6 +437,7 @@ func testDocumentStoreOps(ctx context.Context, t *testing.T, store storage.Docum
|
|||||||
for _, tc := range documentStoreOpsTestCases {
|
for _, tc := range documentStoreOpsTestCases {
|
||||||
func(tc documentStoreOpsTestCase) {
|
func(tc documentStoreOpsTestCase) {
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
if err := tc.Run(ctx, store); err != nil {
|
if err := tc.Run(ctx, store); err != nil {
|
||||||
t.Errorf("%+v", errors.WithStack(err))
|
t.Errorf("%+v", errors.WithStack(err))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user