feat: integrate azure storage handling in migration pipeline
Stream transformer output to an Azure blob container when a job declares ToStorage, with per-job prefix and credential configuration.
This commit is contained in:
@@ -2,10 +2,8 @@ package extractors
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"git.ksdemosapps.com/kylesoda/go-migrate/internal/app/config"
|
||||
"git.ksdemosapps.com/kylesoda/go-migrate/internal/app/custom_errors"
|
||||
@@ -23,7 +21,15 @@ func NewPostgresExtractor(db dbwrapper.DbWrapper) etl.Extractor {
|
||||
return &PostgresExtractor{db: db}
|
||||
}
|
||||
|
||||
func buildExtractQueryPostgres(sourceDbInfo config.SourceTableInfo, columns []models.ColumnType) string {
|
||||
func buildExtractQueryPostgres(
|
||||
sourceDbInfo config.SourceTableInfo,
|
||||
columns []models.ColumnType,
|
||||
includeRange bool,
|
||||
isMinInclusive bool,
|
||||
isMaxInclusive bool,
|
||||
hasMin bool,
|
||||
hasMax bool,
|
||||
) string {
|
||||
var sbColumns strings.Builder
|
||||
|
||||
if len(columns) == 0 {
|
||||
@@ -48,10 +54,44 @@ func buildExtractQueryPostgres(sourceDbInfo config.SourceTableInfo, columns []mo
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(`SELECT %s FROM "%s"."%s" ORDER BY "%s" ASC`, sbColumns.String(), sourceDbInfo.Schema, sourceDbInfo.Table, sourceDbInfo.PrimaryKey)
|
||||
query := fmt.Sprintf(`SELECT %s FROM "%s"."%s"`, sbColumns.String(), sourceDbInfo.Schema, sourceDbInfo.Table)
|
||||
|
||||
if includeRange && (hasMin || hasMax) {
|
||||
query += " WHERE "
|
||||
paramIdx := 1
|
||||
|
||||
if hasMin {
|
||||
query += fmt.Sprintf(`"%s"`, sourceDbInfo.PrimaryKey)
|
||||
if isMinInclusive {
|
||||
query += " >="
|
||||
} else {
|
||||
query += " >"
|
||||
}
|
||||
query += fmt.Sprintf(" $%d", paramIdx)
|
||||
paramIdx++
|
||||
}
|
||||
|
||||
if hasMin && hasMax {
|
||||
query += " AND "
|
||||
}
|
||||
|
||||
if hasMax {
|
||||
query += fmt.Sprintf(`"%s"`, sourceDbInfo.PrimaryKey)
|
||||
if isMaxInclusive {
|
||||
query += " <="
|
||||
} else {
|
||||
query += " <"
|
||||
}
|
||||
query += fmt.Sprintf(" $%d", paramIdx)
|
||||
}
|
||||
}
|
||||
|
||||
query += fmt.Sprintf(` ORDER BY "%s" ASC`, sourceDbInfo.PrimaryKey)
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
func (postgresEx *PostgresExtractor) ProcessPartition(
|
||||
func (postgresEx *PostgresExtractor) Exec(
|
||||
ctx context.Context,
|
||||
tableInfo config.SourceTableInfo,
|
||||
columns []models.ColumnType,
|
||||
@@ -60,14 +100,20 @@ func (postgresEx *PostgresExtractor) ProcessPartition(
|
||||
indexPrimaryKey int,
|
||||
chBatchesOut chan<- models.Batch,
|
||||
) (int, error) {
|
||||
query := buildExtractQueryPostgres(tableInfo, columns)
|
||||
hasMin := partition.HasRange && partition.Range.Min > 0
|
||||
hasMax := partition.HasRange && partition.Range.Max > 0
|
||||
query := buildExtractQueryPostgres(tableInfo, columns, partition.HasRange, partition.Range.IsMinInclusive, partition.Range.IsMaxInclusive, hasMin, hasMax)
|
||||
|
||||
if partition.HasRange {
|
||||
return 0, errors.New("Batch config not yet supported")
|
||||
var queryArgs []any
|
||||
if hasMin {
|
||||
queryArgs = append(queryArgs, partition.Range.Min)
|
||||
}
|
||||
if hasMax {
|
||||
queryArgs = append(queryArgs, partition.Range.Max)
|
||||
}
|
||||
|
||||
rowsRead := 0
|
||||
rows, err := postgresEx.db.Query(ctx, query)
|
||||
rows, err := postgresEx.db.Query(ctx, query, queryArgs...)
|
||||
if err != nil {
|
||||
return rowsRead, &custom_errors.ExtractorError{Partition: partition, HasLastId: false, Msg: err.Error()}
|
||||
}
|
||||
@@ -78,7 +124,7 @@ func (postgresEx *PostgresExtractor) ProcessPartition(
|
||||
for rows.Next() {
|
||||
values, err := rows.Values()
|
||||
if err != nil {
|
||||
return rowsRead, errors.New("Unexpected error reading rows from source")
|
||||
return rowsRead, &custom_errors.ExtractorError{Partition: partition, HasLastId: false, Msg: err.Error()}
|
||||
}
|
||||
rowsRead++
|
||||
|
||||
@@ -96,7 +142,7 @@ func (postgresEx *PostgresExtractor) ProcessPartition(
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return rowsRead, errors.New("Unexpected error reading rows from source")
|
||||
return rowsRead, &custom_errors.ExtractorError{Partition: partition, HasLastId: false, Msg: err.Error()}
|
||||
}
|
||||
|
||||
if len(batchRows) > 0 {
|
||||
@@ -109,17 +155,3 @@ func (postgresEx *PostgresExtractor) ProcessPartition(
|
||||
|
||||
return rowsRead, nil
|
||||
}
|
||||
|
||||
func (postgresEx *PostgresExtractor) Exec(
|
||||
ctx context.Context,
|
||||
tableInfo config.SourceTableInfo,
|
||||
columns []models.ColumnType,
|
||||
batchSize int,
|
||||
chPartitionsIn <-chan models.Partition,
|
||||
chBatchesOut chan<- models.Batch,
|
||||
chErrorsOut chan<- custom_errors.ExtractorError,
|
||||
chJobErrorsOut chan<- custom_errors.JobError,
|
||||
wgActivePartitions *sync.WaitGroup,
|
||||
rowsRead *int64,
|
||||
) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user