✨ Upgrade Go version to 1.23.0 and update dependencies. Introduce new application structure with Clean Architecture principles, including message processing, NATS integration, and PostgreSQL repository. Add configuration management using Koanf and structured logging with Zap. Remove legacy GraphQL integration and related files. Implement dependency injection with Google Wire.
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"caatsm/internal/infra/config"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// ProvideDB creates a PostgreSQL connection pool
|
||||
func ProvideDB(cfg *config.Config) (*pgxpool.Pool, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
poolConfig, err := pgxpool.ParseConfig(cfg.Postgres.URL)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse postgres URL: %w", err)
|
||||
}
|
||||
|
||||
poolConfig.MaxConns = int32(cfg.Postgres.MaxConns)
|
||||
poolConfig.MinConns = int32(cfg.Postgres.MinConns)
|
||||
poolConfig.MaxConnLifetime = time.Hour
|
||||
poolConfig.MaxConnIdleTime = time.Minute * 30
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create connection pool: %w", err)
|
||||
}
|
||||
|
||||
// Test connection
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
return nil, fmt.Errorf("failed to ping database: %w", err)
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"caatsm/internal/adapter"
|
||||
"caatsm/internal/adapter/mapper"
|
||||
"caatsm/internal/domain"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// Repository implements the adapter.Repository interface using PostgreSQL
|
||||
type Repository struct {
|
||||
pool *pgxpool.Pool
|
||||
mapper *mapper.TelegramMapper
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// ProvideRepository creates a PostgreSQL repository
|
||||
func ProvideRepository(pool *pgxpool.Pool, logger *zap.Logger) (adapter.Repository, error) {
|
||||
return &Repository{
|
||||
pool: pool,
|
||||
mapper: mapper.NewTelegramMapper(),
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// InsertOne inserts a single telegram message
|
||||
func (r *Repository) InsertOne(ctx context.Context, msg *domain.ParsedMessage) error {
|
||||
row, err := r.mapper.ToDBRow(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to map message to DB row: %w", err)
|
||||
}
|
||||
|
||||
query := `
|
||||
INSERT INTO aviation.telegrams (
|
||||
uuid, message_id, date_time, priority_indicator, primary_address,
|
||||
secondary_addresses, originator, originator_date_time, category,
|
||||
content, body_data, received_at, parsed_at, dispatched_at, need_dispatch
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
||||
)
|
||||
ON CONFLICT (uuid) DO NOTHING
|
||||
`
|
||||
|
||||
_, err = r.pool.Exec(ctx, query,
|
||||
row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8],
|
||||
row[9], row[10], row[11], row[12], row[13], row[14],
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to insert message: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Debug("Inserted message",
|
||||
zap.String("uuid", msg.Uuid),
|
||||
zap.String("message_id", msg.MessageID),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InsertBatch inserts multiple telegram messages in a batch using CopyFrom
|
||||
func (r *Repository) InsertBatch(ctx context.Context, msgs []*domain.ParsedMessage) error {
|
||||
if len(msgs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert messages to rows
|
||||
rows := make([][]interface{}, len(msgs))
|
||||
for i, msg := range msgs {
|
||||
row, err := r.mapper.ToDBRow(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to map message %d to DB row: %w", i, err)
|
||||
}
|
||||
rows[i] = row
|
||||
}
|
||||
|
||||
// Use CopyFrom for efficient batch insert
|
||||
copyCount, err := r.pool.CopyFrom(
|
||||
ctx,
|
||||
pgx.Identifier{"aviation", "telegrams"},
|
||||
[]string{
|
||||
"uuid", "message_id", "date_time", "priority_indicator", "primary_address",
|
||||
"secondary_addresses", "originator", "originator_date_time", "category",
|
||||
"content", "body_data", "received_at", "parsed_at", "dispatched_at", "need_dispatch",
|
||||
},
|
||||
pgx.CopyFromRows(rows),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to batch insert messages: %w", err)
|
||||
}
|
||||
|
||||
r.logger.Info("Batch inserted messages",
|
||||
zap.Int("count", int(copyCount)),
|
||||
zap.Int("attempted", len(msgs)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user