mirror of
https://github.com/pikami/cosmium.git
synced 2025-12-19 17:00:37 +00:00
DataStore is interface now. Liskov would be proud.
This commit is contained in:
44
internal/datastore/datastore.go
Normal file
44
internal/datastore/datastore.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package datastore
|
||||
|
||||
type DataStore interface {
|
||||
GetAllDatabases() ([]Database, DataStoreStatus)
|
||||
GetDatabase(databaseId string) (Database, DataStoreStatus)
|
||||
DeleteDatabase(databaseId string) DataStoreStatus
|
||||
CreateDatabase(newDatabase Database) (Database, DataStoreStatus)
|
||||
|
||||
GetAllCollections(databaseId string) ([]Collection, DataStoreStatus)
|
||||
GetCollection(databaseId string, collectionId string) (Collection, DataStoreStatus)
|
||||
DeleteCollection(databaseId string, collectionId string) DataStoreStatus
|
||||
CreateCollection(databaseId string, newCollection Collection) (Collection, DataStoreStatus)
|
||||
|
||||
GetAllDocuments(databaseId string, collectionId string) ([]Document, DataStoreStatus)
|
||||
GetDocumentIterator(databaseId string, collectionId string) (DocumentIterator, DataStoreStatus)
|
||||
GetDocument(databaseId string, collectionId string, documentId string) (Document, DataStoreStatus)
|
||||
DeleteDocument(databaseId string, collectionId string, documentId string) DataStoreStatus
|
||||
CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (Document, DataStoreStatus)
|
||||
|
||||
GetAllTriggers(databaseId string, collectionId string) ([]Trigger, DataStoreStatus)
|
||||
GetTrigger(databaseId string, collectionId string, triggerId string) (Trigger, DataStoreStatus)
|
||||
DeleteTrigger(databaseId string, collectionId string, triggerId string) DataStoreStatus
|
||||
CreateTrigger(databaseId string, collectionId string, trigger Trigger) (Trigger, DataStoreStatus)
|
||||
|
||||
GetAllStoredProcedures(databaseId string, collectionId string) ([]StoredProcedure, DataStoreStatus)
|
||||
GetStoredProcedure(databaseId string, collectionId string, storedProcedureId string) (StoredProcedure, DataStoreStatus)
|
||||
DeleteStoredProcedure(databaseId string, collectionId string, storedProcedureId string) DataStoreStatus
|
||||
CreateStoredProcedure(databaseId string, collectionId string, storedProcedure StoredProcedure) (StoredProcedure, DataStoreStatus)
|
||||
|
||||
GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]UserDefinedFunction, DataStoreStatus)
|
||||
GetUserDefinedFunction(databaseId string, collectionId string, udfId string) (UserDefinedFunction, DataStoreStatus)
|
||||
DeleteUserDefinedFunction(databaseId string, collectionId string, udfId string) DataStoreStatus
|
||||
CreateUserDefinedFunction(databaseId string, collectionId string, udf UserDefinedFunction) (UserDefinedFunction, DataStoreStatus)
|
||||
|
||||
GetPartitionKeyRanges(databaseId string, collectionId string) ([]PartitionKeyRange, DataStoreStatus)
|
||||
|
||||
Close()
|
||||
DumpToJson() (string, error)
|
||||
}
|
||||
|
||||
type DocumentIterator interface {
|
||||
Next() (Document, DataStoreStatus)
|
||||
HasMore() bool
|
||||
}
|
||||
21
internal/datastore/map_datastore/array_document_iterator.go
Normal file
21
internal/datastore/map_datastore/array_document_iterator.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package mapdatastore
|
||||
|
||||
import "github.com/pikami/cosmium/internal/datastore"
|
||||
|
||||
type ArrayDocumentIterator struct {
|
||||
documents []datastore.Document
|
||||
index int
|
||||
}
|
||||
|
||||
func (i *ArrayDocumentIterator) Next() (datastore.Document, datastore.DataStoreStatus) {
|
||||
i.index++
|
||||
if i.index >= len(i.documents) {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
return i.documents[i.index], datastore.StatusOk
|
||||
}
|
||||
|
||||
func (i *ArrayDocumentIterator) HasMore() bool {
|
||||
return i.index < len(i.documents)-1
|
||||
}
|
||||
89
internal/datastore/map_datastore/collections.go
Normal file
89
internal/datastore/map_datastore/collections.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
structhidrators "github.com/pikami/cosmium/internal/struct_hidrators"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllCollections(databaseId string) ([]datastore.Collection, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return make([]datastore.Collection, 0), datastore.StatusNotFound
|
||||
}
|
||||
|
||||
return maps.Values(r.storeState.Collections[databaseId]), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetCollection(databaseId string, collectionId string) (datastore.Collection, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Collection{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.Collection{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
return r.storeState.Collections[databaseId][collectionId], datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteCollection(databaseId string, collectionId string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.Collections[databaseId], collectionId)
|
||||
delete(r.storeState.Documents[databaseId], collectionId)
|
||||
delete(r.storeState.Triggers[databaseId], collectionId)
|
||||
delete(r.storeState.StoredProcedures[databaseId], collectionId)
|
||||
delete(r.storeState.UserDefinedFunctions[databaseId], collectionId)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateCollection(databaseId string, newCollection datastore.Collection) (datastore.Collection, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var ok bool
|
||||
var database datastore.Database
|
||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Collection{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok = r.storeState.Collections[databaseId][newCollection.ID]; ok {
|
||||
return datastore.Collection{}, datastore.Conflict
|
||||
}
|
||||
|
||||
newCollection = structhidrators.Hidrate(newCollection).(datastore.Collection)
|
||||
|
||||
newCollection.TimeStamp = time.Now().Unix()
|
||||
newCollection.ResourceID = resourceid.NewCombined(database.ResourceID, resourceid.New(resourceid.ResourceTypeCollection))
|
||||
newCollection.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
newCollection.Self = fmt.Sprintf("dbs/%s/colls/%s/", database.ResourceID, newCollection.ResourceID)
|
||||
|
||||
r.storeState.Collections[databaseId][newCollection.ID] = newCollection
|
||||
r.storeState.Documents[databaseId][newCollection.ID] = make(map[string]datastore.Document)
|
||||
r.storeState.Triggers[databaseId][newCollection.ID] = make(map[string]datastore.Trigger)
|
||||
r.storeState.StoredProcedures[databaseId][newCollection.ID] = make(map[string]datastore.StoredProcedure)
|
||||
r.storeState.UserDefinedFunctions[databaseId][newCollection.ID] = make(map[string]datastore.UserDefinedFunction)
|
||||
|
||||
return newCollection, datastore.StatusOk
|
||||
}
|
||||
70
internal/datastore/map_datastore/databases.go
Normal file
70
internal/datastore/map_datastore/databases.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllDatabases() ([]datastore.Database, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
return maps.Values(r.storeState.Databases), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetDatabase(id string) (datastore.Database, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if database, ok := r.storeState.Databases[id]; ok {
|
||||
return database, datastore.StatusOk
|
||||
}
|
||||
|
||||
return datastore.Database{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteDatabase(id string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[id]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.Databases, id)
|
||||
delete(r.storeState.Collections, id)
|
||||
delete(r.storeState.Documents, id)
|
||||
delete(r.storeState.Triggers, id)
|
||||
delete(r.storeState.StoredProcedures, id)
|
||||
delete(r.storeState.UserDefinedFunctions, id)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateDatabase(newDatabase datastore.Database) (datastore.Database, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[newDatabase.ID]; ok {
|
||||
return datastore.Database{}, datastore.Conflict
|
||||
}
|
||||
|
||||
newDatabase.TimeStamp = time.Now().Unix()
|
||||
newDatabase.ResourceID = resourceid.New(resourceid.ResourceTypeDatabase)
|
||||
newDatabase.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
newDatabase.Self = fmt.Sprintf("dbs/%s/", newDatabase.ResourceID)
|
||||
|
||||
r.storeState.Databases[newDatabase.ID] = newDatabase
|
||||
r.storeState.Collections[newDatabase.ID] = make(map[string]datastore.Collection)
|
||||
r.storeState.Documents[newDatabase.ID] = make(map[string]map[string]datastore.Document)
|
||||
r.storeState.Triggers[newDatabase.ID] = make(map[string]map[string]datastore.Trigger)
|
||||
r.storeState.StoredProcedures[newDatabase.ID] = make(map[string]map[string]datastore.StoredProcedure)
|
||||
r.storeState.UserDefinedFunctions[newDatabase.ID] = make(map[string]map[string]datastore.UserDefinedFunction)
|
||||
|
||||
return newDatabase, datastore.StatusOk
|
||||
}
|
||||
113
internal/datastore/map_datastore/documents.go
Normal file
113
internal/datastore/map_datastore/documents.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllDocuments(databaseId string, collectionId string) ([]datastore.Document, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return make([]datastore.Document, 0), datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return make([]datastore.Document, 0), datastore.StatusNotFound
|
||||
}
|
||||
|
||||
return maps.Values(r.storeState.Documents[databaseId][collectionId]), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetDocument(databaseId string, collectionId string, documentId string) (datastore.Document, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
return r.storeState.Documents[databaseId][collectionId][documentId], datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteDocument(databaseId string, collectionId string, documentId string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.Documents[databaseId][collectionId], documentId)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateDocument(databaseId string, collectionId string, document map[string]interface{}) (datastore.Document, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var ok bool
|
||||
var documentId string
|
||||
var database datastore.Database
|
||||
var collection datastore.Collection
|
||||
if documentId, ok = document["id"].(string); !ok || documentId == "" {
|
||||
documentId = fmt.Sprint(uuid.New())
|
||||
document["id"] = documentId
|
||||
}
|
||||
|
||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.Document{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Documents[databaseId][collectionId][documentId]; ok {
|
||||
return datastore.Document{}, datastore.Conflict
|
||||
}
|
||||
|
||||
document["_ts"] = time.Now().Unix()
|
||||
document["_rid"] = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeDocument))
|
||||
document["_etag"] = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
document["_self"] = fmt.Sprintf("dbs/%s/colls/%s/docs/%s/", database.ResourceID, collection.ResourceID, document["_rid"])
|
||||
|
||||
r.storeState.Documents[databaseId][collectionId][documentId] = document
|
||||
|
||||
return document, datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetDocumentIterator(databaseId string, collectionId string) (datastore.DocumentIterator, datastore.DataStoreStatus) {
|
||||
documents, status := r.GetAllDocuments(databaseId, collectionId)
|
||||
if status != datastore.StatusOk {
|
||||
return nil, status
|
||||
}
|
||||
|
||||
return &ArrayDocumentIterator{
|
||||
documents: documents,
|
||||
index: -1,
|
||||
}, datastore.StatusOk
|
||||
}
|
||||
34
internal/datastore/map_datastore/map_datastore.go
Normal file
34
internal/datastore/map_datastore/map_datastore.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package mapdatastore
|
||||
|
||||
import "github.com/pikami/cosmium/internal/datastore"
|
||||
|
||||
type MapDataStore struct {
|
||||
storeState State
|
||||
|
||||
initialDataFilePath string
|
||||
persistDataFilePath string
|
||||
}
|
||||
|
||||
type MapDataStoreOptions struct {
|
||||
InitialDataFilePath string
|
||||
PersistDataFilePath string
|
||||
}
|
||||
|
||||
func NewMapDataStore(options MapDataStoreOptions) *MapDataStore {
|
||||
dataStore := &MapDataStore{
|
||||
storeState: State{
|
||||
Databases: make(map[string]datastore.Database),
|
||||
Collections: make(map[string]map[string]datastore.Collection),
|
||||
Documents: make(map[string]map[string]map[string]datastore.Document),
|
||||
Triggers: make(map[string]map[string]map[string]datastore.Trigger),
|
||||
StoredProcedures: make(map[string]map[string]map[string]datastore.StoredProcedure),
|
||||
UserDefinedFunctions: make(map[string]map[string]map[string]datastore.UserDefinedFunction),
|
||||
},
|
||||
initialDataFilePath: options.InitialDataFilePath,
|
||||
persistDataFilePath: options.PersistDataFilePath,
|
||||
}
|
||||
|
||||
dataStore.InitializeDataStore()
|
||||
|
||||
return dataStore
|
||||
}
|
||||
49
internal/datastore/map_datastore/partition_key_ranges.go
Normal file
49
internal/datastore/map_datastore/partition_key_ranges.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
)
|
||||
|
||||
// I have no idea what this is tbh
|
||||
func (r *MapDataStore) GetPartitionKeyRanges(databaseId string, collectionId string) ([]datastore.PartitionKeyRange, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
databaseRid := databaseId
|
||||
collectionRid := collectionId
|
||||
var timestamp int64 = 0
|
||||
|
||||
if database, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
databaseRid = database.ResourceID
|
||||
}
|
||||
|
||||
if collection, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
collectionRid = collection.ResourceID
|
||||
timestamp = collection.TimeStamp
|
||||
}
|
||||
|
||||
pkrResourceId := resourceid.NewCombined(collectionRid, resourceid.New(resourceid.ResourceTypePartitionKeyRange))
|
||||
pkrSelf := fmt.Sprintf("dbs/%s/colls/%s/pkranges/%s/", databaseRid, collectionRid, pkrResourceId)
|
||||
etag := fmt.Sprintf("\"%s\"", uuid.New())
|
||||
|
||||
return []datastore.PartitionKeyRange{
|
||||
{
|
||||
ResourceID: pkrResourceId,
|
||||
ID: "0",
|
||||
Etag: etag,
|
||||
MinInclusive: "",
|
||||
MaxExclusive: "FF",
|
||||
RidPrefix: 0,
|
||||
Self: pkrSelf,
|
||||
ThroughputFraction: 1,
|
||||
Status: "online",
|
||||
Parents: []interface{}{},
|
||||
TimeStamp: timestamp,
|
||||
Lsn: 17,
|
||||
},
|
||||
}, datastore.StatusOk
|
||||
}
|
||||
236
internal/datastore/map_datastore/state.go
Normal file
236
internal/datastore/map_datastore/state.go
Normal file
@@ -0,0 +1,236 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/logger"
|
||||
)
|
||||
|
||||
type State struct {
|
||||
sync.RWMutex
|
||||
|
||||
// Map databaseId -> Database
|
||||
Databases map[string]datastore.Database `json:"databases"`
|
||||
|
||||
// Map databaseId -> collectionId -> Collection
|
||||
Collections map[string]map[string]datastore.Collection `json:"collections"`
|
||||
|
||||
// Map databaseId -> collectionId -> documentId -> Documents
|
||||
Documents map[string]map[string]map[string]datastore.Document `json:"documents"`
|
||||
|
||||
// Map databaseId -> collectionId -> triggerId -> Trigger
|
||||
Triggers map[string]map[string]map[string]datastore.Trigger `json:"triggers"`
|
||||
|
||||
// Map databaseId -> collectionId -> spId -> StoredProcedure
|
||||
StoredProcedures map[string]map[string]map[string]datastore.StoredProcedure `json:"sprocs"`
|
||||
|
||||
// Map databaseId -> collectionId -> udfId -> UserDefinedFunction
|
||||
UserDefinedFunctions map[string]map[string]map[string]datastore.UserDefinedFunction `json:"udfs"`
|
||||
}
|
||||
|
||||
func (r *MapDataStore) InitializeDataStore() {
|
||||
if r.initialDataFilePath != "" {
|
||||
r.LoadStateFS(r.initialDataFilePath)
|
||||
return
|
||||
}
|
||||
|
||||
if r.persistDataFilePath != "" {
|
||||
stat, err := os.Stat(r.persistDataFilePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if stat.IsDir() {
|
||||
logger.ErrorLn("Argument '-Persist' must be a path to file, not a directory.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
r.LoadStateFS(r.persistDataFilePath)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MapDataStore) LoadStateFS(filePath string) {
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading state JSON file: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = r.LoadStateJSON(string(data))
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshalling state JSON: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MapDataStore) LoadStateJSON(jsonData string) error {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var state State
|
||||
if err := json.Unmarshal([]byte(jsonData), &state); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.storeState.Collections = state.Collections
|
||||
r.storeState.Databases = state.Databases
|
||||
r.storeState.Documents = state.Documents
|
||||
|
||||
r.ensureStoreStateNoNullReferences()
|
||||
|
||||
logger.InfoLn("Loaded state:")
|
||||
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
||||
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
||||
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
||||
logger.Infof("Triggers: %d\n", getLength(r.storeState.Triggers))
|
||||
logger.Infof("Stored procedures: %d\n", getLength(r.storeState.StoredProcedures))
|
||||
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *MapDataStore) SaveStateFS(filePath string) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
data, err := json.MarshalIndent(r.storeState, "", "\t")
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to save state: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
os.WriteFile(filePath, data, os.ModePerm)
|
||||
|
||||
logger.InfoLn("Saved state:")
|
||||
logger.Infof("Databases: %d\n", getLength(r.storeState.Databases))
|
||||
logger.Infof("Collections: %d\n", getLength(r.storeState.Collections))
|
||||
logger.Infof("Documents: %d\n", getLength(r.storeState.Documents))
|
||||
logger.Infof("Triggers: %d\n", getLength(r.storeState.Triggers))
|
||||
logger.Infof("Stored procedures: %d\n", getLength(r.storeState.StoredProcedures))
|
||||
logger.Infof("User defined functions: %d\n", getLength(r.storeState.UserDefinedFunctions))
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DumpToJson() (string, error) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
data, err := json.MarshalIndent(r.storeState, "", "\t")
|
||||
if err != nil {
|
||||
logger.Errorf("Failed to serialize state: %v\n", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
|
||||
}
|
||||
|
||||
func (r *MapDataStore) Close() {
|
||||
if r.persistDataFilePath != "" {
|
||||
r.SaveStateFS(r.persistDataFilePath)
|
||||
}
|
||||
}
|
||||
|
||||
func getLength(v interface{}) int {
|
||||
switch v.(type) {
|
||||
case datastore.Database,
|
||||
datastore.Collection,
|
||||
datastore.Document,
|
||||
datastore.Trigger,
|
||||
datastore.StoredProcedure,
|
||||
datastore.UserDefinedFunction:
|
||||
return 1
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Map {
|
||||
return -1
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, key := range rv.MapKeys() {
|
||||
if rv.MapIndex(key).Kind() == reflect.Map {
|
||||
count += getLength(rv.MapIndex(key).Interface())
|
||||
} else {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func (r *MapDataStore) ensureStoreStateNoNullReferences() {
|
||||
if r.storeState.Databases == nil {
|
||||
r.storeState.Databases = make(map[string]datastore.Database)
|
||||
}
|
||||
|
||||
if r.storeState.Collections == nil {
|
||||
r.storeState.Collections = make(map[string]map[string]datastore.Collection)
|
||||
}
|
||||
|
||||
if r.storeState.Documents == nil {
|
||||
r.storeState.Documents = make(map[string]map[string]map[string]datastore.Document)
|
||||
}
|
||||
|
||||
if r.storeState.Triggers == nil {
|
||||
r.storeState.Triggers = make(map[string]map[string]map[string]datastore.Trigger)
|
||||
}
|
||||
|
||||
if r.storeState.StoredProcedures == nil {
|
||||
r.storeState.StoredProcedures = make(map[string]map[string]map[string]datastore.StoredProcedure)
|
||||
}
|
||||
|
||||
if r.storeState.UserDefinedFunctions == nil {
|
||||
r.storeState.UserDefinedFunctions = make(map[string]map[string]map[string]datastore.UserDefinedFunction)
|
||||
}
|
||||
|
||||
for database := range r.storeState.Databases {
|
||||
if r.storeState.Collections[database] == nil {
|
||||
r.storeState.Collections[database] = make(map[string]datastore.Collection)
|
||||
}
|
||||
|
||||
if r.storeState.Documents[database] == nil {
|
||||
r.storeState.Documents[database] = make(map[string]map[string]datastore.Document)
|
||||
}
|
||||
|
||||
if r.storeState.Triggers[database] == nil {
|
||||
r.storeState.Triggers[database] = make(map[string]map[string]datastore.Trigger)
|
||||
}
|
||||
|
||||
if r.storeState.StoredProcedures[database] == nil {
|
||||
r.storeState.StoredProcedures[database] = make(map[string]map[string]datastore.StoredProcedure)
|
||||
}
|
||||
|
||||
if r.storeState.UserDefinedFunctions[database] == nil {
|
||||
r.storeState.UserDefinedFunctions[database] = make(map[string]map[string]datastore.UserDefinedFunction)
|
||||
}
|
||||
|
||||
for collection := range r.storeState.Collections[database] {
|
||||
if r.storeState.Documents[database][collection] == nil {
|
||||
r.storeState.Documents[database][collection] = make(map[string]datastore.Document)
|
||||
}
|
||||
|
||||
for document := range r.storeState.Documents[database][collection] {
|
||||
if r.storeState.Documents[database][collection][document] == nil {
|
||||
delete(r.storeState.Documents[database][collection], document)
|
||||
}
|
||||
}
|
||||
|
||||
if r.storeState.Triggers[database][collection] == nil {
|
||||
r.storeState.Triggers[database][collection] = make(map[string]datastore.Trigger)
|
||||
}
|
||||
|
||||
if r.storeState.StoredProcedures[database][collection] == nil {
|
||||
r.storeState.StoredProcedures[database][collection] = make(map[string]datastore.StoredProcedure)
|
||||
}
|
||||
|
||||
if r.storeState.UserDefinedFunctions[database][collection] == nil {
|
||||
r.storeState.UserDefinedFunctions[database][collection] = make(map[string]datastore.UserDefinedFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
internal/datastore/map_datastore/stored_procedures.go
Normal file
91
internal/datastore/map_datastore/stored_procedures.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllStoredProcedures(databaseId string, collectionId string) ([]datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
return maps.Values(r.storeState.StoredProcedures[databaseId][collectionId]), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetStoredProcedure(databaseId string, collectionId string, spId string) (datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if sp, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; ok {
|
||||
return sp, datastore.StatusOk
|
||||
}
|
||||
|
||||
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteStoredProcedure(databaseId string, collectionId string, spId string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.StoredProcedures[databaseId][collectionId][spId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.StoredProcedures[databaseId][collectionId], spId)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateStoredProcedure(databaseId string, collectionId string, sp datastore.StoredProcedure) (datastore.StoredProcedure, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var ok bool
|
||||
var database datastore.Database
|
||||
var collection datastore.Collection
|
||||
if sp.ID == "" {
|
||||
return datastore.StoredProcedure{}, datastore.BadRequest
|
||||
}
|
||||
|
||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StoredProcedure{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok = r.storeState.StoredProcedures[databaseId][collectionId][sp.ID]; ok {
|
||||
return datastore.StoredProcedure{}, datastore.Conflict
|
||||
}
|
||||
|
||||
sp.TimeStamp = time.Now().Unix()
|
||||
sp.ResourceID = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeStoredProcedure))
|
||||
sp.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
sp.Self = fmt.Sprintf("dbs/%s/colls/%s/sprocs/%s/", database.ResourceID, collection.ResourceID, sp.ResourceID)
|
||||
|
||||
r.storeState.StoredProcedures[databaseId][collectionId][sp.ID] = sp
|
||||
|
||||
return sp, datastore.StatusOk
|
||||
}
|
||||
91
internal/datastore/map_datastore/triggers.go
Normal file
91
internal/datastore/map_datastore/triggers.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllTriggers(databaseId string, collectionId string) ([]datastore.Trigger, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
return maps.Values(r.storeState.Triggers[databaseId][collectionId]), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetTrigger(databaseId string, collectionId string, triggerId string) (datastore.Trigger, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Trigger{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.Trigger{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if trigger, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; ok {
|
||||
return trigger, datastore.StatusOk
|
||||
}
|
||||
|
||||
return datastore.Trigger{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteTrigger(databaseId string, collectionId string, triggerId string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Triggers[databaseId][collectionId][triggerId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.Triggers[databaseId][collectionId], triggerId)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateTrigger(databaseId string, collectionId string, trigger datastore.Trigger) (datastore.Trigger, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var ok bool
|
||||
var database datastore.Database
|
||||
var collection datastore.Collection
|
||||
if trigger.ID == "" {
|
||||
return datastore.Trigger{}, datastore.BadRequest
|
||||
}
|
||||
|
||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.Trigger{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.Trigger{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok = r.storeState.Triggers[databaseId][collectionId][trigger.ID]; ok {
|
||||
return datastore.Trigger{}, datastore.Conflict
|
||||
}
|
||||
|
||||
trigger.TimeStamp = time.Now().Unix()
|
||||
trigger.ResourceID = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeTrigger))
|
||||
trigger.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
trigger.Self = fmt.Sprintf("dbs/%s/colls/%s/triggers/%s/", database.ResourceID, collection.ResourceID, trigger.ResourceID)
|
||||
|
||||
r.storeState.Triggers[databaseId][collectionId][trigger.ID] = trigger
|
||||
|
||||
return trigger, datastore.StatusOk
|
||||
}
|
||||
91
internal/datastore/map_datastore/user_defined_functions.go
Normal file
91
internal/datastore/map_datastore/user_defined_functions.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package mapdatastore
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pikami/cosmium/internal/datastore"
|
||||
"github.com/pikami/cosmium/internal/resourceid"
|
||||
"golang.org/x/exp/maps"
|
||||
)
|
||||
|
||||
func (r *MapDataStore) GetAllUserDefinedFunctions(databaseId string, collectionId string) ([]datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
return maps.Values(r.storeState.UserDefinedFunctions[databaseId][collectionId]), datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) GetUserDefinedFunction(databaseId string, collectionId string, udfId string) (datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||
r.storeState.RLock()
|
||||
defer r.storeState.RUnlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if udf, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; ok {
|
||||
return udf, datastore.StatusOk
|
||||
}
|
||||
|
||||
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
func (r *MapDataStore) DeleteUserDefinedFunction(databaseId string, collectionId string, udfId string) datastore.DataStoreStatus {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
if _, ok := r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udfId]; !ok {
|
||||
return datastore.StatusNotFound
|
||||
}
|
||||
|
||||
delete(r.storeState.UserDefinedFunctions[databaseId][collectionId], udfId)
|
||||
|
||||
return datastore.StatusOk
|
||||
}
|
||||
|
||||
func (r *MapDataStore) CreateUserDefinedFunction(databaseId string, collectionId string, udf datastore.UserDefinedFunction) (datastore.UserDefinedFunction, datastore.DataStoreStatus) {
|
||||
r.storeState.Lock()
|
||||
defer r.storeState.Unlock()
|
||||
|
||||
var ok bool
|
||||
var database datastore.Database
|
||||
var collection datastore.Collection
|
||||
if udf.ID == "" {
|
||||
return datastore.UserDefinedFunction{}, datastore.BadRequest
|
||||
}
|
||||
|
||||
if database, ok = r.storeState.Databases[databaseId]; !ok {
|
||||
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if collection, ok = r.storeState.Collections[databaseId][collectionId]; !ok {
|
||||
return datastore.UserDefinedFunction{}, datastore.StatusNotFound
|
||||
}
|
||||
|
||||
if _, ok := r.storeState.UserDefinedFunctions[databaseId][collectionId][udf.ID]; ok {
|
||||
return datastore.UserDefinedFunction{}, datastore.Conflict
|
||||
}
|
||||
|
||||
udf.TimeStamp = time.Now().Unix()
|
||||
udf.ResourceID = resourceid.NewCombined(collection.ResourceID, resourceid.New(resourceid.ResourceTypeUserDefinedFunction))
|
||||
udf.ETag = fmt.Sprintf("\"%s\"", uuid.New())
|
||||
udf.Self = fmt.Sprintf("dbs/%s/colls/%s/udfs/%s/", database.ResourceID, collection.ResourceID, udf.ResourceID)
|
||||
|
||||
r.storeState.UserDefinedFunctions[databaseId][collectionId][udf.ID] = udf
|
||||
|
||||
return udf, datastore.StatusOk
|
||||
}
|
||||
117
internal/datastore/models.go
Normal file
117
internal/datastore/models.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package datastore
|
||||
|
||||
type Database struct {
|
||||
ID string `json:"id"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
ResourceID string `json:"_rid"`
|
||||
ETag string `json:"_etag"`
|
||||
Self string `json:"_self"`
|
||||
}
|
||||
|
||||
type DataStoreStatus int
|
||||
|
||||
const (
|
||||
StatusOk = 1
|
||||
StatusNotFound = 2
|
||||
Conflict = 3
|
||||
BadRequest = 4
|
||||
)
|
||||
|
||||
type TriggerOperation string
|
||||
|
||||
const (
|
||||
All TriggerOperation = "All"
|
||||
Create TriggerOperation = "Create"
|
||||
Delete TriggerOperation = "Delete"
|
||||
Replace TriggerOperation = "Replace"
|
||||
)
|
||||
|
||||
type TriggerType string
|
||||
|
||||
const (
|
||||
Pre TriggerType = "Pre"
|
||||
Post TriggerType = "Post"
|
||||
)
|
||||
|
||||
type Collection struct {
|
||||
ID string `json:"id"`
|
||||
IndexingPolicy CollectionIndexingPolicy `json:"indexingPolicy"`
|
||||
PartitionKey CollectionPartitionKey `json:"partitionKey"`
|
||||
ResourceID string `json:"_rid"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
Self string `json:"_self"`
|
||||
ETag string `json:"_etag"`
|
||||
Docs string `json:"_docs"`
|
||||
Sprocs string `json:"_sprocs"`
|
||||
Triggers string `json:"_triggers"`
|
||||
Udfs string `json:"_udfs"`
|
||||
Conflicts string `json:"_conflicts"`
|
||||
}
|
||||
|
||||
type CollectionIndexingPolicy struct {
|
||||
IndexingMode string `json:"indexingMode"`
|
||||
Automatic bool `json:"automatic"`
|
||||
IncludedPaths []CollectionIndexingPolicyPath `json:"includedPaths"`
|
||||
ExcludedPaths []CollectionIndexingPolicyPath `json:"excludedPaths"`
|
||||
}
|
||||
|
||||
type CollectionIndexingPolicyPath struct {
|
||||
Path string `json:"path"`
|
||||
Indexes []struct {
|
||||
Kind string `json:"kind"`
|
||||
DataType string `json:"dataType"`
|
||||
Precision int `json:"precision"`
|
||||
} `json:"indexes"`
|
||||
}
|
||||
|
||||
type CollectionPartitionKey struct {
|
||||
Paths []string `json:"paths"`
|
||||
Kind string `json:"kind"`
|
||||
Version int `json:"Version"`
|
||||
}
|
||||
|
||||
type UserDefinedFunction struct {
|
||||
Body string `json:"body"`
|
||||
ID string `json:"id"`
|
||||
ResourceID string `json:"_rid"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
Self string `json:"_self"`
|
||||
ETag string `json:"_etag"`
|
||||
}
|
||||
|
||||
type StoredProcedure struct {
|
||||
Body string `json:"body"`
|
||||
ID string `json:"id"`
|
||||
ResourceID string `json:"_rid"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
Self string `json:"_self"`
|
||||
ETag string `json:"_etag"`
|
||||
}
|
||||
|
||||
type Trigger struct {
|
||||
Body string `json:"body"`
|
||||
ID string `json:"id"`
|
||||
TriggerOperation TriggerOperation `json:"triggerOperation"`
|
||||
TriggerType TriggerType `json:"triggerType"`
|
||||
ResourceID string `json:"_rid"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
Self string `json:"_self"`
|
||||
ETag string `json:"_etag"`
|
||||
}
|
||||
|
||||
type Document map[string]interface{}
|
||||
|
||||
type PartitionKeyRange struct {
|
||||
ResourceID string `json:"_rid"`
|
||||
ID string `json:"id"`
|
||||
Etag string `json:"_etag"`
|
||||
MinInclusive string `json:"minInclusive"`
|
||||
MaxExclusive string `json:"maxExclusive"`
|
||||
RidPrefix int `json:"ridPrefix"`
|
||||
Self string `json:"_self"`
|
||||
ThroughputFraction int `json:"throughputFraction"`
|
||||
Status string `json:"status"`
|
||||
Parents []any `json:"parents"`
|
||||
TimeStamp int64 `json:"_ts"`
|
||||
Lsn int `json:"lsn"`
|
||||
}
|
||||
Reference in New Issue
Block a user