Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.work.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1657,4 +1657,4 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
1 change: 1 addition & 0 deletions pkg/gofr/migration/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Datasource struct {
Redis Redis
PubSub PubSub
Clickhouse Clickhouse
Oracle Oracle
Cassandra Cassandra
Mongo Mongo
ArangoDB ArangoDB
Expand Down
5 changes: 5 additions & 0 deletions pkg/gofr/migration/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ type Clickhouse interface {
HealthCheck(ctx context.Context) (any, error)
}

type Oracle interface {
Select(ctx context.Context, dest any, query string, args ...any) error
Exec(ctx context.Context, query string, args ...any) error
}

type Cassandra interface {
Exec(query string, args ...any) error
NewBatch(name string, batchType int) error
Expand Down
11 changes: 9 additions & 2 deletions pkg/gofr/migration/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ func initializeDatasources(c *container.Container, ds *Datasource, mg migrator)
apply: func(m migrator) migrator { return clickHouseDS{ds.Clickhouse}.apply(m) },
logIdentifier: "Clickhouse",
},
{
condition: func() bool { return !isNil(c.Oracle) },
setDS: func() { ds.Oracle = c.Oracle },
apply: func(m migrator) migrator { return oracleDS{c.Oracle}.apply(m) },
logIdentifier: "Oracle",
},

{
condition: func() bool { return c.PubSub != nil },
setDS: func() { ds.PubSub = c.PubSub },
Expand Down Expand Up @@ -223,9 +230,9 @@ func initializeDatasources(c *container.Container, ds *Datasource, mg migrator)
}

func isNil(i any) bool {
// Get the value of the interface
// Get the value of the interface.
val := reflect.ValueOf(i)

// If the interface is not assigned or is nil, return true
// If the interface is not assigned or is nil, return true.
return !val.IsValid() || val.IsNil()
}
1 change: 1 addition & 0 deletions pkg/gofr/migration/migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func initializeClickHouseRunMocks(t *testing.T) (*MockClickhouse, *container.Con
mockContainer.Elasticsearch = nil
mockContainer.OpenTSDB = nil
mockContainer.ScyllaDB = nil
mockContainer.Oracle = nil
mockContainer.Logger = logging.NewMockLogger(logging.DEBUG)
mockContainer.Clickhouse = mockClickHouse

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the method initializeClickHouseRunMocks we need to mark Oracle as nil else it's tests will fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure , I will mark it as nil

Expand Down
63 changes: 63 additions & 0 deletions pkg/gofr/migration/mock_interface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

110 changes: 110 additions & 0 deletions pkg/gofr/migration/oracle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package migration

import (
"context"
"time"

"gofr.dev/pkg/gofr/container"
)

type oracleDS struct {
Oracle
}

type oracleMigrator struct {
Oracle
migrator
}

// Provides a wrapper to apply the oracle migrator logic.
func (od oracleDS) apply(m migrator) migrator {
return oracleMigrator{
Oracle: od.Oracle,
migrator: m,
}
}

const (
checkAndCreateOracleMigrationTable = `
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE gofr_migrations (
version NUMBER NOT NULL,
method VARCHAR2(64) NOT NULL,
start_time TIMESTAMP NOT NULL,
duration NUMBER NULL,
PRIMARY KEY (version, method)
)';
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE != -955 THEN RAISE; END IF;
END;
`
getLastOracleGoFrMigration = `
SELECT NVL(MAX(version), 0) AS last_migration
FROM gofr_migrations
`
insertOracleGoFrMigrationRow = `
INSERT INTO gofr_migrations (version, method, start_time, duration)
VALUES (:1, :2, :3, :4)
`
)

// Create migration table if it doesn't exist.
func (om oracleMigrator) checkAndCreateMigrationTable(_ *container.Container) error {
return om.Oracle.Exec(context.Background(), checkAndCreateOracleMigrationTable)
}

// Get the last applied migration version.
func (om oracleMigrator) getLastMigration(c *container.Container) int64 {
type LastMigration struct {
LastMigration int64 `db:"last_migration"`
}

var lastMigrations []LastMigration

var lastMigration int64

err := om.Oracle.Select(context.Background(), &lastMigrations, getLastOracleGoFrMigration)
if err != nil {
return 0
}

if len(lastMigrations) != 0 {
lastMigration = lastMigrations[0].LastMigration
}

lm2 := om.migrator.getLastMigration(c)

if lm2 > lastMigration {
return lm2
}

return lastMigration
}

// Begin a new migration transaction.
func (om oracleMigrator) beginTransaction(c *container.Container) transactionData {
td := om.migrator.beginTransaction(c)
c.Debug("OracleDB Migrator begin successfully")

return td
}

// Commit the migration.
func (om oracleMigrator) commitMigration(c *container.Container, data transactionData) error {
err := om.Oracle.Exec(context.Background(), insertOracleGoFrMigrationRow, data.MigrationNumber,
"UP", data.StartTime, time.Since(data.StartTime).Milliseconds())
if err != nil {
return err
}

c.Debugf("inserted record for migration %v in oracle gofr_migrations table", data.MigrationNumber)

return om.migrator.commitMigration(c, data)
}

// Rollback the migration.
func (om oracleMigrator) rollback(c *container.Container, data transactionData) {
om.migrator.rollback(c, data)
c.Fatalf("migration %v failed and rolled back", data.MigrationNumber)
}
Loading
Loading