chore: initial commit of ai site platform
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
77
platform/internal/dbsync/echo.go
Normal file
77
platform/internal/dbsync/echo.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package dbsync
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
const FlagTable = "_ajz_sync_flag"
|
||||
|
||||
// EnsureFlagTable:SQLite 用表标记「正在应用远端变更」,避免触发器回声。
|
||||
func EnsureFlagTable(ctx context.Context, db *sql.DB, driver Driver) error {
|
||||
if driver != DriverSQLite {
|
||||
return nil
|
||||
}
|
||||
_, err := db.ExecContext(ctx, `CREATE TABLE IF NOT EXISTS `+FlagTable+` (
|
||||
k TEXT PRIMARY KEY,
|
||||
v INTEGER NOT NULL DEFAULT 0
|
||||
);`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = db.ExecContext(ctx, `INSERT OR IGNORE INTO `+FlagTable+`(k,v) VALUES('applying',0)`)
|
||||
return nil
|
||||
}
|
||||
|
||||
// WithApplying 在写入目标库时置位,使触发器不写 outbox(防 A↔B 回声导致「多」)。
|
||||
func WithApplying(ctx context.Context, db *sql.DB, driver Driver, fn func() error) error {
|
||||
switch driver {
|
||||
case DriverSQLite:
|
||||
if err := EnsureFlagTable(ctx, db, driver); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := db.ExecContext(ctx, `UPDATE `+FlagTable+` SET v=1 WHERE k='applying'`); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_, _ = db.ExecContext(context.Background(), `UPDATE `+FlagTable+` SET v=0 WHERE k='applying'`)
|
||||
}()
|
||||
return fn()
|
||||
case DriverMySQL:
|
||||
if _, err := db.ExecContext(ctx, `SET @ajz_applying = 1`); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _, _ = db.ExecContext(context.Background(), `SET @ajz_applying = 0`) }()
|
||||
return fn()
|
||||
case DriverPostgres:
|
||||
if _, err := db.ExecContext(ctx, `SELECT set_config('ajz.applying', '1', false)`); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_, _ = db.ExecContext(context.Background(), `SELECT set_config('ajz.applying', '0', false)`)
|
||||
}()
|
||||
return fn()
|
||||
default:
|
||||
return fn()
|
||||
}
|
||||
}
|
||||
|
||||
func EnqueueOutbox(ctx context.Context, db *sql.DB, driver Driver, table, pk, op, payload string, version int64) error {
|
||||
if version <= 0 {
|
||||
version = time.Now().UnixMilli()
|
||||
}
|
||||
switch driver {
|
||||
case DriverPostgres:
|
||||
_, err := db.ExecContext(ctx, fmt.Sprintf(`
|
||||
INSERT INTO %s(table_name,row_pk,op,payload,version) VALUES($1,$2,$3,$4,$5)`, OutboxTable),
|
||||
table, pk, op, payload, version)
|
||||
return err
|
||||
default:
|
||||
_, err := db.ExecContext(ctx, fmt.Sprintf(`
|
||||
INSERT INTO %s(table_name,row_pk,op,payload,version) VALUES(?,?,?,?,?)`, OutboxTable),
|
||||
table, pk, op, payload, version)
|
||||
return err
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user