From 3d0b91fe2305e9772468b095f18abd67107f123a Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 27 Jun 2026 12:59:33 +0800 Subject: [PATCH] feat: data models and database migration --- internal/model/model.go | 75 ++++++++++++++++++++++++++++++++++++ migrations/001_init.down.sql | 6 +++ migrations/001_init.up.sql | 72 ++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 internal/model/model.go create mode 100644 migrations/001_init.down.sql create mode 100644 migrations/001_init.up.sql diff --git a/internal/model/model.go b/internal/model/model.go new file mode 100644 index 0000000..bdb062b --- /dev/null +++ b/internal/model/model.go @@ -0,0 +1,75 @@ +package model + +import ( + "database/sql" + "encoding/json" + "time" +) + +type Source struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` + APIKey string `db:"api_key" json:"api_key,omitempty"` + ParseMode string `db:"parse_mode" json:"parse_mode"` + ParsePattern string `db:"parse_pattern" json:"parse_pattern,omitempty"` + Status int `db:"status" json:"status"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + +type Template struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Content string `db:"content" json:"content"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + +type Channel struct { + ID int `db:"id" json:"id"` + Name string `db:"name" json:"name"` + Type string `db:"type" json:"type"` + Config *json.RawMessage `db:"config" json:"config"` + Status int `db:"status" json:"status"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + +type Rule struct { + ID int `db:"id" json:"id"` + SourceID int `db:"source_id" json:"source_id"` + Event string `db:"event" json:"event"` + TemplateID int `db:"template_id" json:"template_id"` + Conditions *json.RawMessage `db:"conditions" json:"conditions,omitempty"` + Enabled int `db:"enabled" json:"enabled"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + +type Condition struct { + Field string `json:"field"` + Op string `json:"op"` + Value string `json:"value,omitempty"` +} + +type RuleChannel struct { + ID int `db:"id" json:"id"` + RuleID int `db:"rule_id" json:"rule_id"` + ChannelID int `db:"channel_id" json:"channel_id"` + Enabled int `db:"enabled" json:"enabled"` +} + +type MessageLog struct { + ID int64 `db:"id" json:"id"` + RuleID int `db:"rule_id" json:"rule_id"` + ChannelID int `db:"channel_id" json:"channel_id"` + Source string `db:"source" json:"source"` + Event string `db:"event" json:"event"` + Payload json.RawMessage `db:"payload" json:"payload"` + Content string `db:"content" json:"content"` + Status string `db:"status" json:"status"` + RetryCount int `db:"retry_count" json:"retry_count"` + Response sql.NullString `db:"response" json:"response,omitempty"` + ErrorMsg sql.NullString `db:"error_msg" json:"error_msg,omitempty"` + CreatedAt time.Time `db:"created_at" json:"created_at"` +} diff --git a/migrations/001_init.down.sql b/migrations/001_init.down.sql new file mode 100644 index 0000000..e3f53ec --- /dev/null +++ b/migrations/001_init.down.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS message_log; +DROP TABLE IF EXISTS rule_channel; +DROP TABLE IF EXISTS rule; +DROP TABLE IF EXISTS channel; +DROP TABLE IF EXISTS template; +DROP TABLE IF EXISTS source; diff --git a/migrations/001_init.up.sql b/migrations/001_init.up.sql new file mode 100644 index 0000000..ef19e5a --- /dev/null +++ b/migrations/001_init.up.sql @@ -0,0 +1,72 @@ +CREATE TABLE source ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(64) NOT NULL, + api_key VARCHAR(128) NOT NULL, + parse_mode VARCHAR(16) NOT NULL DEFAULT 'json', + parse_pattern VARCHAR(512) DEFAULT NULL, + status TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_name (name), + UNIQUE KEY uk_api_key (api_key) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE template ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(64) NOT NULL, + content TEXT NOT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_name (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE channel ( + id INT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(32) NOT NULL, + type VARCHAR(32) NOT NULL, + config JSON NOT NULL, + status TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_name (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE rule ( + id INT AUTO_INCREMENT PRIMARY KEY, + source_id INT NOT NULL, + event VARCHAR(64) NOT NULL, + template_id INT NOT NULL, + conditions JSON DEFAULT NULL, + enabled TINYINT NOT NULL DEFAULT 1, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + UNIQUE KEY uk_source_event (source_id, event), + FOREIGN KEY (source_id) REFERENCES source(id), + FOREIGN KEY (template_id) REFERENCES template(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE rule_channel ( + id INT AUTO_INCREMENT PRIMARY KEY, + rule_id INT NOT NULL, + channel_id INT NOT NULL, + enabled TINYINT NOT NULL DEFAULT 1, + UNIQUE KEY uk_rule_channel (rule_id, channel_id), + FOREIGN KEY (rule_id) REFERENCES rule(id) ON DELETE CASCADE, + FOREIGN KEY (channel_id) REFERENCES channel(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CREATE TABLE message_log ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + rule_id INT NOT NULL, + channel_id INT NOT NULL, + source VARCHAR(64) NOT NULL, + event VARCHAR(64) NOT NULL, + payload JSON NOT NULL, + content TEXT NOT NULL, + status ENUM('pending','success','failed','retrying') NOT NULL DEFAULT 'pending', + retry_count INT NOT NULL DEFAULT 0, + response TEXT DEFAULT NULL, + error_msg TEXT DEFAULT NULL, + created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + INDEX idx_source_event_time (source, event, created_at) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;