1
0

refactor: migrate backend database

This commit is contained in:
2026-07-16 20:13:49 +08:00
parent 7e335c51c6
commit 14350f84c5
5 changed files with 1380 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
package database
import (
"context"
"log/slog"
"github.com/yyc12345/coconut-leaf/backend/config"
)
// ResponseBody is the envelope returned by every Database operation, mirroring
// the legacy database.ResponseBody. Data is any so each method can return its
// own shape (scalar, []string, []any row, [][]any rows, ...). JSON tags keep the
// legacy lowercase keys (success/error/data) used by ConstructResponseBody.
type ResponseBody struct {
Success bool `json:"success"`
Error string `json:"error"`
Data any `json:"data"`
}
// CalendarUpdateOptions carries the optional fields of CalendarUpdate. A nil
// pointer means "not provided", mirroring the legacy **optArgs semantics: a
// field is applied only when its pointer is non-nil.
type CalendarUpdateOptions struct {
BelongTo *string
Title *string
Description *string
EventDateTimeStart *int64
EventDateTimeEnd *int64
LoopRules *string
TimezoneOffset *int64
}
// AdminUpdateOptions carries the optional fields of AdminUpdate. A nil pointer
// means "not provided".
type AdminUpdateOptions struct {
Password *string
IsAdmin *bool
}
// Deps bundles the shared dependencies a database implementation needs: the
// loaded configuration and a logger. It is passed to database constructors and
// stored inside each implementation so they can read config and emit logs.
type Deps struct {
Cfg *config.Config
Logger *slog.Logger
}
// Database describes every database operation the Gin server may use. It is the
// Go equivalent of the legacy CalendarDatabase public surface: each method takes
// a context.Context for cancellation and returns a ResponseBody whose
// Success/Error fields encode failure (mirroring the legacy decorator behavior).
type Database interface {
Init(username, password string) error
Close() error
CommonSalt(ctx context.Context, username string) ResponseBody
CommonLogin(ctx context.Context, username, password, clientUa, clientIp string) ResponseBody
CommonWebLogin(ctx context.Context, username, password, clientUa, clientIp string) ResponseBody
CommonLogout(ctx context.Context, token string) ResponseBody
CommonTokenValid(ctx context.Context, token string) ResponseBody
CalendarGetFull(ctx context.Context, token string, startDateTime, endDateTime int64) ResponseBody
CalendarGetList(ctx context.Context, token string, startDateTime, endDateTime int64) ResponseBody
CalendarGetDetail(ctx context.Context, token, uuid string) ResponseBody
CalendarUpdate(ctx context.Context, token, uuid, lastChange string, opts CalendarUpdateOptions) ResponseBody
CalendarAdd(ctx context.Context, token, belongTo, title, description string, eventDateTimeStart, eventDateTimeEnd int64, loopRules string, timezoneOffset int64) ResponseBody
CalendarDelete(ctx context.Context, token, uuid, lastChange string) ResponseBody
CollectionGetFullOwn(ctx context.Context, token string) ResponseBody
CollectionGetListOwn(ctx context.Context, token string) ResponseBody
CollectionGetDetailOwn(ctx context.Context, token, uuid string) ResponseBody
CollectionAddOwn(ctx context.Context, token, name string) ResponseBody
CollectionUpdateOwn(ctx context.Context, token, uuid, name, lastChange string) ResponseBody
CollectionDeleteOwn(ctx context.Context, token, uuid, lastChange string) ResponseBody
CollectionGetSharing(ctx context.Context, token, uuid string) ResponseBody
CollectionDeleteSharing(ctx context.Context, token, uuid, target, lastChange string) ResponseBody
CollectionAddSharing(ctx context.Context, token, uuid, target, lastChange string) ResponseBody
CollectionGetShared(ctx context.Context, token string) ResponseBody
TodoGetFull(ctx context.Context, token string) ResponseBody
TodoGetList(ctx context.Context, token string) ResponseBody
TodoGetDetail(ctx context.Context, token, uuid string) ResponseBody
TodoAdd(ctx context.Context, token string) ResponseBody
TodoUpdate(ctx context.Context, token, uuid, data, lastChange string) ResponseBody
TodoDelete(ctx context.Context, token, uuid, lastChange string) ResponseBody
AdminGet(ctx context.Context, token string) ResponseBody
AdminAdd(ctx context.Context, token, username string) ResponseBody
AdminUpdate(ctx context.Context, token, username string, opts AdminUpdateOptions) ResponseBody
AdminDelete(ctx context.Context, token, username string) ResponseBody
ProfileIsAdmin(ctx context.Context, token string) ResponseBody
ProfileChangePassword(ctx context.Context, token, password string) ResponseBody
ProfileGetToken(ctx context.Context, token string) ResponseBody
ProfileDeleteToken(ctx context.Context, token, deleteToken string) ResponseBody
}

View File

@@ -0,0 +1,143 @@
package database
import (
"context"
"errors"
)
var errNotImplemented = errors.New("mysql database: not implemented")
var notImplResp = ResponseBody{Success: false, Error: errNotImplemented.Error()}
// stubDatabase provides a not-implemented default for every Database method.
// MysqlDatabase embeds it so the interface is satisfied without hand-writing
// each method; individual methods can be overridden on MysqlDatabase later.
type stubDatabase struct{}
func (stubDatabase) Init(username, password string) error { return errNotImplemented }
func (stubDatabase) Close() error { return errNotImplemented }
func (stubDatabase) CommonSalt(ctx context.Context, username string) ResponseBody {
return notImplResp
}
func (stubDatabase) CommonLogin(ctx context.Context, username, password, clientUa, clientIp string) ResponseBody {
return notImplResp
}
func (stubDatabase) CommonWebLogin(ctx context.Context, username, password, clientUa, clientIp string) ResponseBody {
return notImplResp
}
func (stubDatabase) CommonLogout(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) CommonTokenValid(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarGetFull(ctx context.Context, token string, startDateTime, endDateTime int64) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarGetList(ctx context.Context, token string, startDateTime, endDateTime int64) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarGetDetail(ctx context.Context, token, uuid string) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarUpdate(ctx context.Context, token, uuid, lastChange string, opts CalendarUpdateOptions) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarAdd(ctx context.Context, token, belongTo, title, description string, eventDateTimeStart, eventDateTimeEnd int64, loopRules string, timezoneOffset int64) ResponseBody {
return notImplResp
}
func (stubDatabase) CalendarDelete(ctx context.Context, token, uuid, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionGetFullOwn(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionGetListOwn(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionGetDetailOwn(ctx context.Context, token, uuid string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionAddOwn(ctx context.Context, token, name string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionUpdateOwn(ctx context.Context, token, uuid, name, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionDeleteOwn(ctx context.Context, token, uuid, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionGetSharing(ctx context.Context, token, uuid string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionDeleteSharing(ctx context.Context, token, uuid, target, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionAddSharing(ctx context.Context, token, uuid, target, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) CollectionGetShared(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoGetFull(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoGetList(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoGetDetail(ctx context.Context, token, uuid string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoAdd(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoUpdate(ctx context.Context, token, uuid, data, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) TodoDelete(ctx context.Context, token, uuid, lastChange string) ResponseBody {
return notImplResp
}
func (stubDatabase) AdminGet(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) AdminAdd(ctx context.Context, token, username string) ResponseBody {
return notImplResp
}
func (stubDatabase) AdminUpdate(ctx context.Context, token, username string, opts AdminUpdateOptions) ResponseBody {
return notImplResp
}
func (stubDatabase) AdminDelete(ctx context.Context, token, username string) ResponseBody {
return notImplResp
}
func (stubDatabase) ProfileIsAdmin(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) ProfileChangePassword(ctx context.Context, token, password string) ResponseBody {
return notImplResp
}
func (stubDatabase) ProfileGetToken(ctx context.Context, token string) ResponseBody {
return notImplResp
}
func (stubDatabase) ProfileDeleteToken(ctx context.Context, token, deleteToken string) ResponseBody {
return notImplResp
}
// MysqlDatabase implements Database as a fully not-implemented stub by
// embedding stubDatabase. Real MySQL support can be filled in later by
// overriding individual methods.
type MysqlDatabase struct {
stubDatabase
deps Deps
}
// NewMysqlDatabase returns a not-implemented MysqlDatabase. The deps are stored
// for symmetry with NewSqlite3Database but not yet used.
func NewMysqlDatabase(deps Deps) (*MysqlDatabase, error) {
return &MysqlDatabase{deps: deps}, nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -24,6 +24,7 @@ require (
github.com/klauspost/cpuid/v2 v2.4.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect
github.com/mattn/go-sqlite3 v1.14.48 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.4.3 // indirect

View File

@@ -62,6 +62,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
github.com/mattn/go-sqlite3 v1.14.48 h1:7XHIgl0a8HwOaiK4E47ozLkST78rR9+OtNGx27D/TFs=
github.com/mattn/go-sqlite3 v1.14.48/go.mod h1:6JTjA44L93a0QCyJef5YvlPoKXntQPjzWv5gtm9sB6w=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=