Skip to content

Commit

Permalink
add factory methods to make storages
Browse files Browse the repository at this point in the history
- Implement new function `NewPostgres` for creating a Postgres database connection with proper error handling.
- Create `storage.go` file to manage database connections, supporting Sqlite, Postgres, and MySQL.
- Implement `prepareStoreURL` to determine the database type from the connection URL and handle connection string formatting.
  • Loading branch information
umputun committed Jan 12, 2025
1 parent b079d4f commit ade67bd
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
12 changes: 11 additions & 1 deletion app/storage/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
Unknown Type = ""
Sqlite Type = "sqlite"
Postgres Type = "postgres"
Mysql Type = "mysql"
)

// SQL is a wrapper for sqlx.DB with type.
Expand All @@ -31,14 +32,23 @@ type SQL struct {
func NewSqlite(file, gid string) (*SQL, error) {
db, err := sqlx.Connect("sqlite", file)
if err != nil {
return &SQL{}, err
return &SQL{}, fmt.Errorf("failed to connect to sqlite: %w", err)
}
if err := setSqlitePragma(db); err != nil {
return &SQL{}, err
}
return &SQL{DB: *db, gid: gid, dbType: Sqlite}, nil
}

// NewPostgres creates a new postgres database
func NewPostgres(ctx context.Context, connURL, gid string) (*SQL, error) {
db, err := sqlx.ConnectContext(ctx, "postgres", connURL)
if err != nil {
return &SQL{}, fmt.Errorf("failed to connect to postgres: %w", err)
}
return &SQL{DB: *db, gid: gid, dbType: Postgres}, nil
}

// GID returns the group id
func (e *SQL) GID() string {
return e.gid
Expand Down
67 changes: 67 additions & 0 deletions app/storage/storage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package storage

import (
"context"
"fmt"
"strings"

"github.com/umputun/tg-spam/app/storage/engine"
)

// New creates a new store based on the connection URL and the session duration.
func New(ctx context.Context, connURL, gid string) (*engine.SQL, error) {
dbType, conn, err := prepareStoreURL(connURL)
if err != nil {
return nil, err
}

switch dbType {
case engine.Sqlite:
res, err := engine.NewSqlite(conn, gid)
if err != nil {
return nil, fmt.Errorf("failed to create sqlite engine: %w", err)
}
return res, nil
case engine.Postgres:
res, err := engine.NewPostgres(ctx, conn, gid)
if err != nil {
return nil, fmt.Errorf("failed to create postgres engine: %w", err)
}
return res, nil
default:
return nil, fmt.Errorf("unsupported database type in connection string")
}
}

// prepareStoreURL returns the type of the store based on the connection URL and the connection URL.
// supported connection strings for psq, mysql and sqlite
// returns the type of the store and the connection string to use with sqlx
func prepareStoreURL(connURL string) (dbType engine.Type, conn string, err error) {
if strings.HasPrefix(connURL, "postgres://") {
return engine.Postgres, connURL, nil
}
if strings.Contains(connURL, "@tcp(") {
// check if parseTime=true is set in the connection string and add it if not
if !strings.Contains(connURL, "parseTime=true") {
if strings.Contains(connURL, "?") {
connURL += "&parseTime=true"
} else {
connURL += "?parseTime=true"
}
}
return engine.Mysql, connURL, nil
}
if strings.HasPrefix(connURL, "sqlite:/") || strings.HasPrefix(connURL, "sqlite3:/") ||
strings.HasSuffix(connURL, ".sqlite") || strings.HasSuffix(connURL, ".db") {
connURL = strings.Replace(connURL, "sqlite:/", "file:/", 1)
connURL = strings.Replace(connURL, "sqlite3:/", "file:/", 1)
return engine.Sqlite, connURL, nil
}

if connURL == "memory" || strings.Contains(connURL, ":memory:") ||
strings.HasPrefix(connURL, "memory://") || strings.HasPrefix(connURL, "mem://") {
return engine.Sqlite, ":memory:", nil
}

return engine.Unknown, "", fmt.Errorf("unsupported database type in connection string")
}

0 comments on commit ade67bd

Please sign in to comment.