package mysqldriver import ( "context" "database/sql" "git.aiterp.net/stufflog/server/database/repositories" "github.com/jmoiron/sqlx" "github.com/pressly/goose" "strings" // Mysql Driver _ "github.com/go-sql-driver/mysql" ) type DB struct { db *sqlx.DB activities *activityRepository issues *issueRepository issueTasks *issueTaskRepository issueItems *issueItemRepository items *itemRepository projects *projectRepository sessions *sessionRepository users *userRepository projectStatuses *projectStatusRepository logs *logRepository } func (db *DB) Activities() repositories.ActivityRepository { return db.activities } func (db *DB) Issues() repositories.IssueRepository { return db.issues } func (db *DB) IssueTasks() repositories.IssueTaskRepository { return db.issueTasks } func (db *DB) IssueItems() repositories.IssueItemRepository { return db.issueItems } func (db *DB) Items() repositories.ItemRepository { return db.items } func (db *DB) Projects() repositories.ProjectRepository { return db.projects } func (db *DB) Session() repositories.SessionRepository { return db.sessions } func (db *DB) Users() repositories.UserRepository { return db.users } func (db *DB) ProjectStatuses() repositories.ProjectStatusRepository { return db.projectStatuses } func (db *DB) Logs() repositories.LogRepository { return db.logs } func (db *DB) Migrate() error { err := goose.SetDialect("mysql") if err != nil { return err } return goose.Up(db.db.DB, "migrations/mysql") } func Open(connectionString string) (*DB, error) { // Ensure parseTime is true qpos := strings.LastIndexByte(connectionString, '?') if qpos != -1 { connectionString += "&parseTime=true" } else { connectionString += "?parseTime=true" } // Connect to the database db, err := sqlx.Connect("mysql", connectionString) if err != nil { return nil, err } // Test the connection err = db.Ping() if err != nil { return nil, err } // Setup repositories activities := &activityRepository{db: db} issues := &issueRepository{db: db} items := &itemRepository{db: db} projects := &projectRepository{db: db} users := &userRepository{db: db} sessions := &sessionRepository{db: db} projectStatuses := &projectStatusRepository{db: db} issueTasks := &issueTaskRepository{db: db} issueItems := &issueItemRepository{db: db} logs := &logRepository{db: db} return &DB{ db: db, activities: activities, issues: issues, issueTasks: issueTasks, issueItems: issueItems, items: items, projects: projects, users: users, sessions: sessions, projectStatuses: projectStatuses, logs: logs, }, nil } func incCounter(ctx context.Context, tx *sqlx.Tx, kind, name string) (int, error) { value := 1 err := tx.GetContext(ctx, &value, ` SELECT value FROM counters WHERE kind=? AND name=? FOR UPDATE `, kind, name) if err != nil && err != sql.ErrNoRows { return -1, err } _, err = tx.ExecContext(ctx, "REPLACE INTO counters (kind, name, value) VALUES (?, ?, ?)", kind, name, value+1) if err != nil { return -1, err } return value, nil }