Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
212
native/desktop/maplefile/internal/repo/collection/repository.go
Normal file
212
native/desktop/maplefile/internal/repo/collection/repository.go
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
package collection
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/collection"
|
||||
)
|
||||
|
||||
const (
|
||||
collectionKeyPrefix = "collection:"
|
||||
parentCollIndex = "parent_collection_index:"
|
||||
rootCollIndex = "root_collection_index:"
|
||||
)
|
||||
|
||||
type repository struct {
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
// ProvideRepository creates a new collection repository for Wire
|
||||
func ProvideRepository(storage storage.Storage) collection.Repository {
|
||||
return &repository{storage: storage}
|
||||
}
|
||||
|
||||
func (r *repository) Create(c *collection.Collection) error {
|
||||
return r.save(c)
|
||||
}
|
||||
|
||||
func (r *repository) Get(id string) (*collection.Collection, error) {
|
||||
key := collectionKeyPrefix + id
|
||||
data, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get collection: %w", err)
|
||||
}
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var c collection.Collection
|
||||
if err := json.Unmarshal(data, &c); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal collection: %w", err)
|
||||
}
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func (r *repository) Update(c *collection.Collection) error {
|
||||
// Get existing collection to clean up old indexes if parent changed
|
||||
existing, err := r.Get(c.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get existing collection: %w", err)
|
||||
}
|
||||
if existing != nil && existing.ParentID != c.ParentID {
|
||||
// Clean up old parent index
|
||||
if existing.ParentID == "" {
|
||||
oldRootKey := rootCollIndex + existing.ID
|
||||
_ = r.storage.Delete(oldRootKey)
|
||||
} else {
|
||||
oldParentKey := parentCollIndex + existing.ParentID + ":" + existing.ID
|
||||
_ = r.storage.Delete(oldParentKey)
|
||||
}
|
||||
}
|
||||
|
||||
return r.save(c)
|
||||
}
|
||||
|
||||
func (r *repository) Delete(id string) error {
|
||||
// Get collection first to remove indexes
|
||||
c, err := r.Get(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c == nil {
|
||||
return nil // Nothing to delete
|
||||
}
|
||||
|
||||
// Delete parent index or root index
|
||||
if c.ParentID == "" {
|
||||
rootKey := rootCollIndex + id
|
||||
if err := r.storage.Delete(rootKey); err != nil {
|
||||
return fmt.Errorf("failed to delete root index: %w", err)
|
||||
}
|
||||
} else {
|
||||
parentKey := parentCollIndex + c.ParentID + ":" + id
|
||||
if err := r.storage.Delete(parentKey); err != nil {
|
||||
return fmt.Errorf("failed to delete parent index: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete collection
|
||||
collKey := collectionKeyPrefix + id
|
||||
if err := r.storage.Delete(collKey); err != nil {
|
||||
return fmt.Errorf("failed to delete collection: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) List() ([]*collection.Collection, error) {
|
||||
var collections []*collection.Collection
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, collectionKeyPrefix) {
|
||||
var c collection.Collection
|
||||
if err := json.Unmarshal(value, &c); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal collection: %w", err)
|
||||
}
|
||||
collections = append(collections, &c)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list collections: %w", err)
|
||||
}
|
||||
|
||||
return collections, nil
|
||||
}
|
||||
|
||||
func (r *repository) ListByParent(parentID string) ([]*collection.Collection, error) {
|
||||
var collections []*collection.Collection
|
||||
prefix := parentCollIndex + parentID + ":"
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, prefix) {
|
||||
// Extract collection ID from index key
|
||||
collID := strings.TrimPrefix(keyStr, prefix)
|
||||
c, err := r.Get(collID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != nil {
|
||||
collections = append(collections, c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list collections by parent: %w", err)
|
||||
}
|
||||
|
||||
return collections, nil
|
||||
}
|
||||
|
||||
func (r *repository) ListRoot() ([]*collection.Collection, error) {
|
||||
var collections []*collection.Collection
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, rootCollIndex) {
|
||||
// Extract collection ID from index key
|
||||
collID := strings.TrimPrefix(keyStr, rootCollIndex)
|
||||
c, err := r.Get(collID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c != nil {
|
||||
collections = append(collections, c)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list root collections: %w", err)
|
||||
}
|
||||
|
||||
return collections, nil
|
||||
}
|
||||
|
||||
func (r *repository) Exists(id string) (bool, error) {
|
||||
key := collectionKeyPrefix + id
|
||||
data, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check collection existence: %w", err)
|
||||
}
|
||||
return data != nil, nil
|
||||
}
|
||||
|
||||
// save persists the collection and maintains indexes
|
||||
func (r *repository) save(c *collection.Collection) error {
|
||||
data, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal collection: %w", err)
|
||||
}
|
||||
|
||||
// Save collection by ID
|
||||
collKey := collectionKeyPrefix + c.ID
|
||||
if err := r.storage.Set(collKey, data); err != nil {
|
||||
return fmt.Errorf("failed to save collection: %w", err)
|
||||
}
|
||||
|
||||
// Create parent index (for ListByParent) or root index (for ListRoot)
|
||||
if c.ParentID == "" {
|
||||
rootKey := rootCollIndex + c.ID
|
||||
if err := r.storage.Set(rootKey, []byte(c.ID)); err != nil {
|
||||
return fmt.Errorf("failed to create root index: %w", err)
|
||||
}
|
||||
} else {
|
||||
parentKey := parentCollIndex + c.ParentID + ":" + c.ID
|
||||
if err := r.storage.Set(parentKey, []byte(c.ID)); err != nil {
|
||||
return fmt.Errorf("failed to create parent index: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
213
native/desktop/maplefile/internal/repo/file/repository.go
Normal file
213
native/desktop/maplefile/internal/repo/file/repository.go
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/file"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
||||
)
|
||||
|
||||
const (
|
||||
fileKeyPrefix = "file:"
|
||||
collectionFileIndex = "collection_file_index:"
|
||||
statusFileIndex = "status_file_index:"
|
||||
)
|
||||
|
||||
type repository struct {
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
// ProvideRepository creates a new file repository for Wire
|
||||
func ProvideRepository(storage storage.Storage) file.Repository {
|
||||
return &repository{storage: storage}
|
||||
}
|
||||
|
||||
func (r *repository) Create(f *file.File) error {
|
||||
return r.save(f)
|
||||
}
|
||||
|
||||
func (r *repository) Get(id string) (*file.File, error) {
|
||||
key := fileKeyPrefix + id
|
||||
data, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get file: %w", err)
|
||||
}
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var f file.File
|
||||
if err := json.Unmarshal(data, &f); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal file: %w", err)
|
||||
}
|
||||
|
||||
return &f, nil
|
||||
}
|
||||
|
||||
func (r *repository) Update(f *file.File) error {
|
||||
// Get existing file to clean up old indexes if collection changed
|
||||
existing, err := r.Get(f.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get existing file: %w", err)
|
||||
}
|
||||
if existing != nil {
|
||||
// Clean up old collection index if collection changed
|
||||
if existing.CollectionID != f.CollectionID {
|
||||
oldIndexKey := collectionFileIndex + existing.CollectionID + ":" + existing.ID
|
||||
_ = r.storage.Delete(oldIndexKey)
|
||||
}
|
||||
// Clean up old status index if status changed
|
||||
if existing.SyncStatus != f.SyncStatus {
|
||||
oldStatusKey := statusFileIndex + existing.SyncStatus.String() + ":" + existing.ID
|
||||
_ = r.storage.Delete(oldStatusKey)
|
||||
}
|
||||
}
|
||||
|
||||
return r.save(f)
|
||||
}
|
||||
|
||||
func (r *repository) Delete(id string) error {
|
||||
// Get file first to remove indexes
|
||||
f, err := r.Get(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f == nil {
|
||||
return nil // Nothing to delete
|
||||
}
|
||||
|
||||
// Delete collection index
|
||||
collIndexKey := collectionFileIndex + f.CollectionID + ":" + id
|
||||
if err := r.storage.Delete(collIndexKey); err != nil {
|
||||
return fmt.Errorf("failed to delete collection index: %w", err)
|
||||
}
|
||||
|
||||
// Delete status index
|
||||
statusKey := statusFileIndex + f.SyncStatus.String() + ":" + id
|
||||
if err := r.storage.Delete(statusKey); err != nil {
|
||||
return fmt.Errorf("failed to delete status index: %w", err)
|
||||
}
|
||||
|
||||
// Delete file
|
||||
fileKey := fileKeyPrefix + id
|
||||
if err := r.storage.Delete(fileKey); err != nil {
|
||||
return fmt.Errorf("failed to delete file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) List() ([]*file.File, error) {
|
||||
var files []*file.File
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, fileKeyPrefix) {
|
||||
var f file.File
|
||||
if err := json.Unmarshal(value, &f); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal file: %w", err)
|
||||
}
|
||||
files = append(files, &f)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list files: %w", err)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (r *repository) ListByCollection(collectionID string) ([]*file.File, error) {
|
||||
var files []*file.File
|
||||
prefix := collectionFileIndex + collectionID + ":"
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, prefix) {
|
||||
// Extract file ID from index key
|
||||
fileID := strings.TrimPrefix(keyStr, prefix)
|
||||
f, err := r.Get(fileID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f != nil {
|
||||
files = append(files, f)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list files by collection: %w", err)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (r *repository) ListByStatus(status file.SyncStatus) ([]*file.File, error) {
|
||||
var files []*file.File
|
||||
prefix := statusFileIndex + status.String() + ":"
|
||||
|
||||
err := r.storage.Iterate(func(key, value []byte) error {
|
||||
keyStr := string(key)
|
||||
if strings.HasPrefix(keyStr, prefix) {
|
||||
// Extract file ID from index key
|
||||
fileID := strings.TrimPrefix(keyStr, prefix)
|
||||
f, err := r.Get(fileID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if f != nil {
|
||||
files = append(files, f)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list files by status: %w", err)
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (r *repository) Exists(id string) (bool, error) {
|
||||
key := fileKeyPrefix + id
|
||||
data, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to check file existence: %w", err)
|
||||
}
|
||||
return data != nil, nil
|
||||
}
|
||||
|
||||
// save persists the file and maintains indexes
|
||||
func (r *repository) save(f *file.File) error {
|
||||
data, err := json.Marshal(f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal file: %w", err)
|
||||
}
|
||||
|
||||
// Save file by ID
|
||||
fileKey := fileKeyPrefix + f.ID
|
||||
if err := r.storage.Set(fileKey, data); err != nil {
|
||||
return fmt.Errorf("failed to save file: %w", err)
|
||||
}
|
||||
|
||||
// Create collection index (for ListByCollection)
|
||||
collIndexKey := collectionFileIndex + f.CollectionID + ":" + f.ID
|
||||
if err := r.storage.Set(collIndexKey, []byte(f.ID)); err != nil {
|
||||
return fmt.Errorf("failed to create collection index: %w", err)
|
||||
}
|
||||
|
||||
// Create status index (for ListByStatus)
|
||||
statusKey := statusFileIndex + f.SyncStatus.String() + ":" + f.ID
|
||||
if err := r.storage.Set(statusKey, []byte(f.ID)); err != nil {
|
||||
return fmt.Errorf("failed to create status index: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
55
native/desktop/maplefile/internal/repo/session/repository.go
Normal file
55
native/desktop/maplefile/internal/repo/session/repository.go
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package session
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/session"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
||||
)
|
||||
|
||||
const sessionKey = "current_session"
|
||||
|
||||
type repository struct {
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
// ProvideRepository creates a session repository for Wire
|
||||
func ProvideRepository(storage storage.Storage) session.Repository {
|
||||
return &repository{storage: storage}
|
||||
}
|
||||
|
||||
func (r *repository) Save(sess *session.Session) error {
|
||||
data, err := json.Marshal(sess)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return r.storage.Set(sessionKey, data)
|
||||
}
|
||||
|
||||
func (r *repository) Get() (*session.Session, error) {
|
||||
data, err := r.storage.Get(sessionKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if data == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var sess session.Session
|
||||
if err := json.Unmarshal(data, &sess); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sess, nil
|
||||
}
|
||||
|
||||
func (r *repository) Delete() error {
|
||||
return r.storage.Delete(sessionKey)
|
||||
}
|
||||
|
||||
func (r *repository) Exists() (bool, error) {
|
||||
data, err := r.storage.Get(sessionKey)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return data != nil, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package syncstate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/syncstate"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
||||
)
|
||||
|
||||
const syncStateKey = "sync_state"
|
||||
|
||||
type repository struct {
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
// ProvideRepository creates a new syncstate repository for Wire
|
||||
func ProvideRepository(storage storage.Storage) syncstate.Repository {
|
||||
return &repository{storage: storage}
|
||||
}
|
||||
|
||||
func (r *repository) Get() (*syncstate.SyncState, error) {
|
||||
data, err := r.storage.Get(syncStateKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get sync state: %w", err)
|
||||
}
|
||||
if data == nil {
|
||||
// Return empty sync state if none exists
|
||||
return syncstate.NewSyncState(), nil
|
||||
}
|
||||
|
||||
var state syncstate.SyncState
|
||||
if err := json.Unmarshal(data, &state); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal sync state: %w", err)
|
||||
}
|
||||
|
||||
return &state, nil
|
||||
}
|
||||
|
||||
func (r *repository) Save(state *syncstate.SyncState) error {
|
||||
data, err := json.Marshal(state)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal sync state: %w", err)
|
||||
}
|
||||
|
||||
if err := r.storage.Set(syncStateKey, data); err != nil {
|
||||
return fmt.Errorf("failed to save sync state: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) Reset() error {
|
||||
if err := r.storage.Delete(syncStateKey); err != nil {
|
||||
return fmt.Errorf("failed to reset sync state: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
105
native/desktop/maplefile/internal/repo/user/repository.go
Normal file
105
native/desktop/maplefile/internal/repo/user/repository.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/pkg/storage"
|
||||
"codeberg.org/mapleopentech/monorepo/native/desktop/maplefile/internal/domain/user"
|
||||
)
|
||||
|
||||
const (
|
||||
userKeyPrefix = "user:"
|
||||
emailKeyIndex = "email_index:"
|
||||
)
|
||||
|
||||
type repository struct {
|
||||
storage storage.Storage
|
||||
}
|
||||
|
||||
// ProvideRepository creates a new user repository
|
||||
func ProvideRepository(storage storage.Storage) user.Repository {
|
||||
return &repository{
|
||||
storage: storage,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *repository) Save(u *user.User) error {
|
||||
data, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal user: %w", err)
|
||||
}
|
||||
|
||||
// Save user by ID
|
||||
userKey := userKeyPrefix + u.ID
|
||||
if err := r.storage.Set(userKey, data); err != nil {
|
||||
return fmt.Errorf("failed to save user: %w", err)
|
||||
}
|
||||
|
||||
// Create email index
|
||||
emailKey := emailKeyIndex + u.Email
|
||||
if err := r.storage.Set(emailKey, []byte(u.ID)); err != nil {
|
||||
return fmt.Errorf("failed to create email index: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) GetByID(id string) (*user.User, error) {
|
||||
key := userKeyPrefix + id
|
||||
data, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get user: %w", err)
|
||||
}
|
||||
|
||||
var u user.User
|
||||
if err := json.Unmarshal(data, &u); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal user: %w", err)
|
||||
}
|
||||
|
||||
return &u, nil
|
||||
}
|
||||
|
||||
func (r *repository) GetByEmail(email string) (*user.User, error) {
|
||||
// Get user ID from email index
|
||||
emailKey := emailKeyIndex + email
|
||||
idData, err := r.storage.Get(emailKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("user not found by email: %w", err)
|
||||
}
|
||||
|
||||
userID := string(idData)
|
||||
return r.GetByID(userID)
|
||||
}
|
||||
|
||||
func (r *repository) Delete(id string) error {
|
||||
// Get user first to remove email index
|
||||
u, err := r.GetByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Delete email index
|
||||
emailKey := emailKeyIndex + u.Email
|
||||
if err := r.storage.Delete(emailKey); err != nil {
|
||||
return fmt.Errorf("failed to delete email index: %w", err)
|
||||
}
|
||||
|
||||
// Delete user
|
||||
userKey := userKeyPrefix + id
|
||||
if err := r.storage.Delete(userKey); err != nil {
|
||||
return fmt.Errorf("failed to delete user: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *repository) Exists(id string) (bool, error) {
|
||||
key := userKeyPrefix + id
|
||||
_, err := r.storage.Get(key)
|
||||
if err != nil {
|
||||
// Key doesn't exist
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue