From de290aeb25a51eaceff0db5c9057a6ae315b3a72 Mon Sep 17 00:00:00 2001 From: mleku Date: Wed, 3 Dec 2025 12:31:40 +0000 Subject: [PATCH] implement wasm/js specific database engine --- pkg/database/factory_wasm.go | 115 +++++++++++++++++++++++++++++++++++ pkg/database/types.go | 26 ++++++++ 2 files changed, 141 insertions(+) create mode 100644 pkg/database/factory_wasm.go create mode 100644 pkg/database/types.go diff --git a/pkg/database/factory_wasm.go b/pkg/database/factory_wasm.go new file mode 100644 index 0000000..07d4876 --- /dev/null +++ b/pkg/database/factory_wasm.go @@ -0,0 +1,115 @@ +//go:build js && wasm + +package database + +import ( + "context" + "fmt" + "strings" + "time" +) + +// DatabaseConfig holds all database configuration options that can be passed +// to any database backend. Each backend uses the relevant fields for its type. +// This centralizes configuration instead of having each backend read env vars directly. +type DatabaseConfig struct { + // Common settings for all backends + DataDir string + LogLevel string + + // Badger-specific settings (not available in WASM) + BlockCacheMB int // ORLY_DB_BLOCK_CACHE_MB + IndexCacheMB int // ORLY_DB_INDEX_CACHE_MB + QueryCacheSizeMB int // ORLY_QUERY_CACHE_SIZE_MB + QueryCacheMaxAge time.Duration // ORLY_QUERY_CACHE_MAX_AGE + InlineEventThreshold int // ORLY_INLINE_EVENT_THRESHOLD + + // DGraph-specific settings + DgraphURL string // ORLY_DGRAPH_URL + + // Neo4j-specific settings + Neo4jURI string // ORLY_NEO4J_URI + Neo4jUser string // ORLY_NEO4J_USER + Neo4jPassword string // ORLY_NEO4J_PASSWORD +} + +// NewDatabase creates a database instance based on the specified type. +// Supported types in WASM: "wasmdb", "dgraph", "neo4j" +// Note: "badger" is not available in WASM builds due to filesystem dependencies +func NewDatabase( + ctx context.Context, + cancel context.CancelFunc, + dbType string, + dataDir string, + logLevel string, +) (Database, error) { + // Create a default config for backward compatibility with existing callers + cfg := &DatabaseConfig{ + DataDir: dataDir, + LogLevel: logLevel, + } + return NewDatabaseWithConfig(ctx, cancel, dbType, cfg) +} + +// NewDatabaseWithConfig creates a database instance with full configuration. +// This is the preferred method when you have access to the app config. +func NewDatabaseWithConfig( + ctx context.Context, + cancel context.CancelFunc, + dbType string, + cfg *DatabaseConfig, +) (Database, error) { + switch strings.ToLower(dbType) { + case "wasmdb", "indexeddb", "wasm", "badger", "": + // In WASM builds, default to wasmdb (IndexedDB backend) + // "badger" is mapped to wasmdb since Badger is not available + if newWasmDBDatabase == nil { + return nil, fmt.Errorf("wasmdb database backend not available (import _ \"next.orly.dev/pkg/wasmdb\")") + } + return newWasmDBDatabase(ctx, cancel, cfg) + case "dgraph": + // Use the dgraph implementation (HTTP-based, works in WASM) + if newDgraphDatabase == nil { + return nil, fmt.Errorf("dgraph database backend not available (import _ \"next.orly.dev/pkg/dgraph\")") + } + return newDgraphDatabase(ctx, cancel, cfg) + case "neo4j": + // Use the neo4j implementation (HTTP-based, works in WASM) + if newNeo4jDatabase == nil { + return nil, fmt.Errorf("neo4j database backend not available (import _ \"next.orly.dev/pkg/neo4j\")") + } + return newNeo4jDatabase(ctx, cancel, cfg) + default: + return nil, fmt.Errorf("unsupported database type: %s (supported in WASM: wasmdb, dgraph, neo4j)", dbType) + } +} + +// newDgraphDatabase creates a dgraph database instance +// This is defined here to avoid import cycles +var newDgraphDatabase func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error) + +// RegisterDgraphFactory registers the dgraph database factory +// This is called from the dgraph package's init() function +func RegisterDgraphFactory(factory func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error)) { + newDgraphDatabase = factory +} + +// newNeo4jDatabase creates a neo4j database instance +// This is defined here to avoid import cycles +var newNeo4jDatabase func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error) + +// RegisterNeo4jFactory registers the neo4j database factory +// This is called from the neo4j package's init() function +func RegisterNeo4jFactory(factory func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error)) { + newNeo4jDatabase = factory +} + +// newWasmDBDatabase creates a wasmdb database instance (IndexedDB backend for WebAssembly) +// This is defined here to avoid import cycles +var newWasmDBDatabase func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error) + +// RegisterWasmDBFactory registers the wasmdb database factory +// This is called from the wasmdb package's init() function +func RegisterWasmDBFactory(factory func(context.Context, context.CancelFunc, *DatabaseConfig) (Database, error)) { + newWasmDBDatabase = factory +} diff --git a/pkg/database/types.go b/pkg/database/types.go new file mode 100644 index 0000000..ba16988 --- /dev/null +++ b/pkg/database/types.go @@ -0,0 +1,26 @@ +package database + +import "time" + +// Subscription represents a user's subscription status +type Subscription struct { + TrialEnd time.Time `json:"trial_end"` + PaidUntil time.Time `json:"paid_until"` + BlossomLevel string `json:"blossom_level,omitempty"` // Service level name (e.g., "basic", "premium") + BlossomStorage int64 `json:"blossom_storage,omitempty"` // Storage quota in MB +} + +// Payment represents a recorded payment +type Payment struct { + Amount int64 `json:"amount"` + Timestamp time.Time `json:"timestamp"` + Invoice string `json:"invoice"` + Preimage string `json:"preimage"` +} + +// NIP43Membership represents membership metadata for NIP-43 +type NIP43Membership struct { + Pubkey []byte + AddedAt time.Time + InviteCode string +}