mirror of
https://github.com/aykhans/slash-e.git
synced 2025-06-15 04:17:50 +00:00
refactor: update stores
This commit is contained in:
110
store/db/db.go
110
store/db/db.go
@ -23,12 +23,12 @@ var migrationFS embed.FS
|
||||
var seedFS embed.FS
|
||||
|
||||
type DB struct {
|
||||
profile *profile.Profile
|
||||
// sqlite db connection instance
|
||||
DBInstance *sql.DB
|
||||
profile *profile.Profile
|
||||
}
|
||||
|
||||
// NewDB returns a new instance of DB associated with the given datasource name.
|
||||
// NewDB returns a new instance of DB.
|
||||
func NewDB(profile *profile.Profile) *DB {
|
||||
db := &DB{
|
||||
profile: profile,
|
||||
@ -50,64 +50,70 @@ func (db *DB) Open(ctx context.Context) (err error) {
|
||||
db.DBInstance = sqliteDB
|
||||
|
||||
if db.profile.Mode == "prod" {
|
||||
// If db file not exists, we should migrate the database.
|
||||
if _, err := os.Stat(db.profile.DSN); errors.Is(err, os.ErrNotExist) {
|
||||
if err := db.applyLatestSchema(ctx); err != nil {
|
||||
return fmt.Errorf("failed to apply latest schema: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
currentVersion := version.GetCurrentVersion(db.profile.Mode)
|
||||
migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{})
|
||||
_, err := os.Stat(db.profile.DSN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find migration history, err: %w", err)
|
||||
}
|
||||
if len(migrationHistoryList) == 0 {
|
||||
_, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
|
||||
Version: currentVersion,
|
||||
})
|
||||
// If db file not exists, we should apply the latest schema.
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
if err := db.applyLatestSchema(ctx); err != nil {
|
||||
return fmt.Errorf("failed to apply latest schema: %w", err)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("failed to check database file: %w", err)
|
||||
}
|
||||
} else {
|
||||
// If db file exists, we should check the migration history and apply the migration if needed.
|
||||
currentVersion := version.GetCurrentVersion(db.profile.Mode)
|
||||
migrationHistoryList, err := db.FindMigrationHistoryList(ctx, &MigrationHistoryFind{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upsert migration history, err: %w", err)
|
||||
return fmt.Errorf("failed to find migration history, err: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
migrationHistoryVersionList := []string{}
|
||||
for _, migrationHistory := range migrationHistoryList {
|
||||
migrationHistoryVersionList = append(migrationHistoryVersionList, migrationHistory.Version)
|
||||
}
|
||||
sort.Sort(version.SortVersion(migrationHistoryVersionList))
|
||||
latestMigrationHistoryVersion := migrationHistoryVersionList[len(migrationHistoryVersionList)-1]
|
||||
|
||||
if version.IsVersionGreaterThan(version.GetSchemaVersion(currentVersion), latestMigrationHistoryVersion) {
|
||||
minorVersionList := getMinorVersionList()
|
||||
|
||||
// backup the raw database file before migration
|
||||
rawBytes, err := os.ReadFile(db.profile.DSN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read raw database file, err: %w", err)
|
||||
if len(migrationHistoryList) == 0 {
|
||||
_, err := db.UpsertMigrationHistory(ctx, &MigrationHistoryUpsert{
|
||||
Version: currentVersion,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to upsert migration history, err: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
backupDBFilePath := fmt.Sprintf("%s/shortify_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix())
|
||||
if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write raw database file, err: %w", err)
|
||||
}
|
||||
println("succeed to copy a backup database file")
|
||||
|
||||
println("start migrate")
|
||||
for _, minorVersion := range minorVersionList {
|
||||
normalizedVersion := minorVersion + ".0"
|
||||
if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) {
|
||||
println("applying migration for", normalizedVersion)
|
||||
if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil {
|
||||
return fmt.Errorf("failed to apply minor version migration: %w", err)
|
||||
migrationHistoryVersionList := []string{}
|
||||
for _, migrationHistory := range migrationHistoryList {
|
||||
migrationHistoryVersionList = append(migrationHistoryVersionList, migrationHistory.Version)
|
||||
}
|
||||
sort.Sort(version.SortVersion(migrationHistoryVersionList))
|
||||
latestMigrationHistoryVersion := migrationHistoryVersionList[len(migrationHistoryVersionList)-1]
|
||||
|
||||
if version.IsVersionGreaterThan(version.GetSchemaVersion(currentVersion), latestMigrationHistoryVersion) {
|
||||
minorVersionList := getMinorVersionList()
|
||||
|
||||
// backup the raw database file before migration
|
||||
rawBytes, err := os.ReadFile(db.profile.DSN)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read raw database file, err: %w", err)
|
||||
}
|
||||
backupDBFilePath := fmt.Sprintf("%s/shortify_%s_%d_backup.db", db.profile.Data, db.profile.Version, time.Now().Unix())
|
||||
if err := os.WriteFile(backupDBFilePath, rawBytes, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write raw database file, err: %w", err)
|
||||
}
|
||||
println("succeed to copy a backup database file")
|
||||
|
||||
println("start migrate")
|
||||
for _, minorVersion := range minorVersionList {
|
||||
normalizedVersion := minorVersion + ".0"
|
||||
if version.IsVersionGreaterThan(normalizedVersion, latestMigrationHistoryVersion) && version.IsVersionGreaterOrEqualThan(currentVersion, normalizedVersion) {
|
||||
println("applying migration for", normalizedVersion)
|
||||
if err := db.applyMigrationForMinorVersion(ctx, minorVersion); err != nil {
|
||||
return fmt.Errorf("failed to apply minor version migration: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
println("end migrate")
|
||||
println("end migrate")
|
||||
|
||||
// remove the created backup db file after migrate succeed
|
||||
if err := os.Remove(backupDBFilePath); err != nil {
|
||||
println(fmt.Sprintf("Failed to remove temp database file, err %v", err))
|
||||
// remove the created backup db file after migrate succeed
|
||||
if err := os.Remove(backupDBFilePath); err != nil {
|
||||
println(fmt.Sprintf("Failed to remove temp database file, err %v", err))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -4,23 +4,47 @@ CREATE TABLE migration_history (
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
|
||||
-- workspace
|
||||
CREATE TABLE workspace (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
resource_id TEXT NOT NULL UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('workspace', 1);
|
||||
|
||||
-- workspace_setting
|
||||
CREATE TABLE workspace_setting (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
UNIQUE(workspace_id, key)
|
||||
);
|
||||
|
||||
-- user
|
||||
CREATE TABLE user (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
display_name TEXT NOT NULL,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
nickname TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
open_id TEXT NOT NULL UNIQUE,
|
||||
role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('user', 100);
|
||||
('user', 10);
|
||||
|
||||
-- user_setting
|
||||
CREATE TABLE user_setting (
|
||||
@ -30,31 +54,6 @@ CREATE TABLE user_setting (
|
||||
UNIQUE(user_id, key)
|
||||
);
|
||||
|
||||
-- workspace
|
||||
CREATE TABLE workspace (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
creator_id INTEGER NOT NULL,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('workspace', 10);
|
||||
|
||||
-- workspace_setting
|
||||
CREATE TABLE workspace_setting (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
UNIQUE(workspace_id, key)
|
||||
);
|
||||
|
||||
-- workspace_user
|
||||
CREATE TABLE workspace_user (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
@ -80,4 +79,4 @@ CREATE TABLE shortcut (
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('shortcut', 1000);
|
||||
('shortcut', 100);
|
||||
|
@ -4,23 +4,47 @@ CREATE TABLE migration_history (
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
|
||||
-- workspace
|
||||
CREATE TABLE workspace (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
resource_id TEXT NOT NULL UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('workspace', 1);
|
||||
|
||||
-- workspace_setting
|
||||
CREATE TABLE workspace_setting (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
UNIQUE(workspace_id, key)
|
||||
);
|
||||
|
||||
-- user
|
||||
CREATE TABLE user (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
display_name TEXT NOT NULL,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
nickname TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
open_id TEXT NOT NULL UNIQUE,
|
||||
role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('user', 100);
|
||||
('user', 10);
|
||||
|
||||
-- user_setting
|
||||
CREATE TABLE user_setting (
|
||||
@ -30,31 +54,6 @@ CREATE TABLE user_setting (
|
||||
UNIQUE(user_id, key)
|
||||
);
|
||||
|
||||
-- workspace
|
||||
CREATE TABLE workspace (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
creator_id INTEGER NOT NULL,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT ''
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('workspace', 10);
|
||||
|
||||
-- workspace_setting
|
||||
CREATE TABLE workspace_setting (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
UNIQUE(workspace_id, key)
|
||||
);
|
||||
|
||||
-- workspace_user
|
||||
CREATE TABLE workspace_user (
|
||||
workspace_id INTEGER NOT NULL,
|
||||
@ -80,4 +79,4 @@ CREATE TABLE shortcut (
|
||||
INSERT INTO
|
||||
sqlite_sequence (name, seq)
|
||||
VALUES
|
||||
('shortcut', 1000);
|
||||
('shortcut', 100);
|
||||
|
@ -67,7 +67,7 @@ func findMigrationHistoryList(ctx context.Context, tx *sql.Tx, find *MigrationHi
|
||||
FROM
|
||||
migration_history
|
||||
WHERE ` + strings.Join(where, " AND ") + `
|
||||
ORDER BY version DESC
|
||||
ORDER BY created_ts DESC
|
||||
`
|
||||
rows, err := tx.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
|
@ -1,17 +1,11 @@
|
||||
DELETE FROM
|
||||
shortcut;
|
||||
DELETE FROM shortcut;
|
||||
|
||||
DELETE FROM
|
||||
workspace_user;
|
||||
DELETE FROM workspace_user;
|
||||
|
||||
DELETE FROM
|
||||
user_setting;
|
||||
DELETE FROM user_setting;
|
||||
|
||||
DELETE FROM
|
||||
user;
|
||||
DELETE FROM user;
|
||||
|
||||
DELETE FROM
|
||||
workspace_setting;
|
||||
DELETE FROM workspace_setting;
|
||||
|
||||
DELETE FROM
|
||||
workspace;
|
||||
DELETE FROM workspace;
|
||||
|
@ -1,35 +1,35 @@
|
||||
INSERT INTO
|
||||
user (
|
||||
`id`,
|
||||
`username`,
|
||||
`nickname`,
|
||||
`email`,
|
||||
`display_name`,
|
||||
`password_hash`,
|
||||
`open_id`
|
||||
`password_hash`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
101,
|
||||
'frank@shortify.demo',
|
||||
11,
|
||||
'frank',
|
||||
'Frank',
|
||||
'frank@shortify.demo',
|
||||
-- raw password: secret
|
||||
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK',
|
||||
'frank_open_id'
|
||||
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
user (
|
||||
`id`,
|
||||
`username`,
|
||||
`nickname`,
|
||||
`email`,
|
||||
`display_name`,
|
||||
`password_hash`,
|
||||
`open_id`
|
||||
`password_hash`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
102,
|
||||
'bob@shortify.demo',
|
||||
12,
|
||||
'bob',
|
||||
'Bob',
|
||||
'bob@shortify.demo',
|
||||
-- raw password: secret
|
||||
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK',
|
||||
'bob_open_id'
|
||||
);
|
||||
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
|
||||
);
|
||||
|
@ -1,33 +1,14 @@
|
||||
INSERT INTO
|
||||
workspace (
|
||||
`id`,
|
||||
`creator_id`,
|
||||
`name`,
|
||||
`title`,
|
||||
`description`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
11,
|
||||
101,
|
||||
1,
|
||||
'minecraft',
|
||||
'minecraft',
|
||||
''
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
workspace (
|
||||
`id`,
|
||||
`creator_id`,
|
||||
`name`,
|
||||
`title`,
|
||||
`description`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
12,
|
||||
102,
|
||||
'bob',
|
||||
'bob-room',
|
||||
''
|
||||
);
|
@ -6,8 +6,8 @@ INSERT INTO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
11,
|
||||
101,
|
||||
1,
|
||||
11,
|
||||
'ADMIN'
|
||||
);
|
||||
|
||||
@ -19,33 +19,7 @@ INSERT INTO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
11,
|
||||
102,
|
||||
'USER'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
workspace_user (
|
||||
`workspace_id`,
|
||||
`user_id`,
|
||||
`role`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
12,
|
||||
102,
|
||||
'ADMIN'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
workspace_user (
|
||||
`workspace_id`,
|
||||
`user_id`,
|
||||
`role`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
12,
|
||||
101,
|
||||
1,
|
||||
12,
|
||||
'USER'
|
||||
);
|
||||
|
@ -9,8 +9,8 @@ INSERT INTO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
101,
|
||||
11,
|
||||
11,
|
||||
1,
|
||||
'baidu',
|
||||
'https://baidu.com',
|
||||
'百度搜索',
|
||||
@ -28,8 +28,8 @@ INSERT INTO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
102,
|
||||
11,
|
||||
12,
|
||||
1,
|
||||
'bl',
|
||||
'https://bilibili.com',
|
||||
'B站',
|
||||
@ -47,48 +47,10 @@ INSERT INTO
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
101,
|
||||
11,
|
||||
11,
|
||||
1,
|
||||
'ph',
|
||||
'https://producthunt.com',
|
||||
'PH',
|
||||
'PRIVATE'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
shortcut (
|
||||
`creator_id`,
|
||||
`workspace_id`,
|
||||
`name`,
|
||||
`link`,
|
||||
`description`,
|
||||
`visibility`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
101,
|
||||
12,
|
||||
'github',
|
||||
'https://producthunt.com',
|
||||
'GitHub',
|
||||
'PRIVATE'
|
||||
);
|
||||
|
||||
INSERT INTO
|
||||
shortcut (
|
||||
`creator_id`,
|
||||
`workspace_id`,
|
||||
`name`,
|
||||
`link`,
|
||||
`description`,
|
||||
`visibility`
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
102,
|
||||
12,
|
||||
'go',
|
||||
'https://google.com',
|
||||
'google',
|
||||
'WORKSPACE'
|
||||
);
|
||||
|
Reference in New Issue
Block a user