☕ 🚀 Database Migrations in TuskLang Java
🚀 Database Migrations in TuskLang Java
"We don't bow to any king" - Migrate your database like a Java master
TuskLang Java provides sophisticated database migration capabilities that integrate seamlessly with Spring Boot, JPA, and modern Java patterns. Create, manage, and execute database migrations with enterprise-grade reliability and version control.
🎯 Overview
Database migrations in TuskLang Java combine the power of Java migration technologies with TuskLang's configuration system. From JPA schema generation to Spring Boot Flyway integration, we'll show you how to build robust, scalable migration systems.
🔧 Core Migration Features
1. JPA Schema Migrations
import org.tusklang.java.TuskLang;
import org.tusklang.java.migrations.TuskJPAMigrationManager;
import javax.persistence.*;
import java.util.Map;
import java.util.List;@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(unique = true, nullable = false)
private String email;
@Column(name = "created_at")
private java.time.LocalDateTime createdAt;
// Constructors, getters, setters
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
this.createdAt = java.time.LocalDateTime.now();
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public java.time.LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(java.time.LocalDateTime createdAt) { this.createdAt = createdAt; }
}
public class JPAMigrationExample {
public static void main(String[] args) {
TuskLang parser = new TuskLang();
String tskContent = """
[jpa_migrations]
# JPA Schema Migration Configuration
enable_schema_generation: true
enable_schema_validation: true
enable_schema_update: true
[schema_config]
# Schema configuration
create_schema: true
drop_schema: false
validate_schema: true
update_schema: true
[migration_001_initial_schema]
# Initial schema migration
version: "001"
description: "Create initial database schema"
environment: ["development", "test", "staging", "production"]
up_method: """
function migrateUp(entityManager) {
// Create users table
entityManager.createNativeQuery("""
CREATE TABLE IF NOT EXISTS users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""").executeUpdate();
// Create orders table
entityManager.createNativeQuery("""
CREATE TABLE IF NOT EXISTS orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
)
""").executeUpdate();
// Create posts table
entityManager.createNativeQuery("""
CREATE TABLE IF NOT EXISTS posts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
author_id BIGINT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
)
""").executeUpdate();
return 3; // Number of tables created
}
"""
down_method: """
function migrateDown(entityManager) {
// Drop tables in reverse order
entityManager.createNativeQuery("DROP TABLE IF EXISTS posts").executeUpdate();
entityManager.createNativeQuery("DROP TABLE IF EXISTS orders").executeUpdate();
entityManager.createNativeQuery("DROP TABLE IF EXISTS users").executeUpdate();
return 3; // Number of tables dropped
}
"""
[migration_002_add_user_roles]
# Add user roles migration
version: "002"
description: "Add user roles and permissions"
environment: ["development", "test", "staging", "production"]
up_method: """
function migrateUp(entityManager) {
// Create roles table
entityManager.createNativeQuery("""
CREATE TABLE IF NOT EXISTS roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""").executeUpdate();
// Create user_roles junction table
entityManager.createNativeQuery("""
CREATE TABLE IF NOT EXISTS user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
)
""").executeUpdate();
// Insert default roles
entityManager.createNativeQuery("""
INSERT INTO roles (name, description) VALUES
('user', 'Regular user'),
('admin', 'Administrator'),
('moderator', 'Content moderator')
""").executeUpdate();
return 2; // Number of tables created
}
"""
down_method: """
function migrateDown(entityManager) {
// Drop tables in reverse order
entityManager.createNativeQuery("DROP TABLE IF EXISTS user_roles").executeUpdate();
entityManager.createNativeQuery("DROP TABLE IF EXISTS roles").executeUpdate();
return 2; // Number of tables dropped
}
"""
[migration_003_add_indexes]
# Add database indexes migration
version: "003"
description: "Add performance indexes"
environment: ["development", "test", "staging", "production"]
up_method: """
function migrateUp(entityManager) {
// Add indexes for better performance
entityManager.createNativeQuery("""
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)
""").executeUpdate();
entityManager.createNativeQuery("""
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders(user_id)
""").executeUpdate();
entityManager.createNativeQuery("""
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status)
""").executeUpdate();
entityManager.createNativeQuery("""
CREATE INDEX IF NOT EXISTS idx_posts_author_id ON posts(author_id)
""").executeUpdate();
entityManager.createNativeQuery("""
CREATE INDEX IF NOT EXISTS idx_posts_created_at ON posts(created_at)
""").executeUpdate();
return 5; // Number of indexes created
}
"""
down_method: """
function migrateDown(entityManager) {
// Drop indexes
entityManager.createNativeQuery("DROP INDEX IF EXISTS idx_posts_created_at").executeUpdate();
entityManager.createNativeQuery("DROP INDEX IF EXISTS idx_posts_author_id").executeUpdate();
entityManager.createNativeQuery("DROP INDEX IF EXISTS idx_orders_status").executeUpdate();
entityManager.createNativeQuery("DROP INDEX IF EXISTS idx_orders_user_id").executeUpdate();
entityManager.createNativeQuery("DROP INDEX IF EXISTS idx_users_email").executeUpdate();
return 5; // Number of indexes dropped
}
"""
""";
Map<String, Object> config = parser.parse(tskContent);
// Initialize JPA migration manager
TuskJPAMigrationManager jpaMigrationManager = new TuskJPAMigrationManager();
jpaMigrationManager.configure(config);
// Execute migrations
int tablesCreated = jpaMigrationManager.migrateUp("migration_001_initial_schema");
int rolesAdded = jpaMigrationManager.migrateUp("migration_002_add_user_roles");
int indexesAdded = jpaMigrationManager.migrateUp("migration_003_add_indexes");
System.out.println("Migration 001: Created " + tablesCreated + " tables");
System.out.println("Migration 002: Added " + rolesAdded + " role tables");
System.out.println("Migration 003: Added " + indexesAdded + " indexes");
// Rollback if needed
// jpaMigrationManager.migrateDown("migration_003_add_indexes");
}
}
2. Spring Boot Flyway Integration
import org.tusklang.java.TuskLang;
import org.tusklang.java.migrations.TuskFlywayMigrationManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.Map;
import java.util.List;@SpringBootApplication
public class FlywayMigrationExample {
public static void main(String[] args) {
TuskLang parser = new TuskLang();
String tskContent = """
[flyway_migrations]
# Flyway Migration Configuration
enable_flyway: true
enable_baseline: true
enable_clean: false
[flyway_config]
# Flyway configuration
locations: ["classpath:db/migration"]
baseline_on_migrate: true
validate_on_migrate: true
out_of_order: false
[migration_001_initial_schema]
# Initial schema migration
version: "001"
description: "Create initial database schema"
sql_file: "V001__Create_initial_schema.sql"
sql_content: """
-- Create users table
CREATE TABLE IF NOT EXISTS users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create orders table
CREATE TABLE IF NOT EXISTS orders (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10,2) NOT NULL,
status VARCHAR(50) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Create posts table
CREATE TABLE IF NOT EXISTS posts (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
author_id BIGINT NOT NULL,
title VARCHAR(255) NOT NULL,
content TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (author_id) REFERENCES users(id)
);
"""
[migration_002_add_user_roles]
# Add user roles migration
version: "002"
description: "Add user roles and permissions"
sql_file: "V002__Add_user_roles.sql"
sql_content: """
-- Create roles table
CREATE TABLE IF NOT EXISTS roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) UNIQUE NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Create user_roles junction table
CREATE TABLE IF NOT EXISTS user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
-- Insert default roles
INSERT INTO roles (name, description) VALUES
('user', 'Regular user'),
('admin', 'Administrator'),
('moderator', 'Content moderator');
"""
[migration_003_add_user_profile]
# Add user profile migration
version: "003"
description: "Add user profile information"
sql_file: "V003__Add_user_profile.sql"
sql_content: """
-- Add profile columns to users table
ALTER TABLE users ADD COLUMN bio TEXT;
ALTER TABLE users ADD COLUMN avatar VARCHAR(255);
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
ALTER TABLE users ADD COLUMN date_of_birth DATE;
-- Create user_profiles table for extended profile data
CREATE TABLE IF NOT EXISTS user_profiles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT UNIQUE NOT NULL,
bio TEXT,
avatar VARCHAR(255),
phone VARCHAR(20),
date_of_birth DATE,
location VARCHAR(255),
website VARCHAR(255),
social_links JSON,
preferences JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
"""
[migration_004_add_audit_tables]
# Add audit tables migration
version: "004"
description: "Add audit and logging tables"
sql_file: "V004__Add_audit_tables.sql"
sql_content: """
-- Create audit_log table
CREATE TABLE IF NOT EXISTS audit_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT,
action VARCHAR(100) NOT NULL,
table_name VARCHAR(100),
record_id BIGINT,
old_values JSON,
new_values JSON,
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
-- Create system_log table
CREATE TABLE IF NOT EXISTS system_log (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
level VARCHAR(20) NOT NULL,
message TEXT NOT NULL,
stack_trace TEXT,
context JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Add indexes for audit tables
CREATE INDEX idx_audit_log_user_id ON audit_log(user_id);
CREATE INDEX idx_audit_log_action ON audit_log(action);
CREATE INDEX idx_audit_log_created_at ON audit_log(created_at);
CREATE INDEX idx_system_log_level ON system_log(level);
CREATE INDEX idx_system_log_created_at ON system_log(created_at);
"""
[flyway_methods]
# Flyway migration methods
execute_flyway_migration: """
function executeFlywayMigration(migrationName) {
let flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("classpath:db/migration");
flyway.setBaselineOnMigrate(true);
flyway.setValidateOnMigrate(true);
// Execute migration
let result = flyway.migrate();
return {
applied: result.applied,
target: result.target,
executionTime: result.executionTime
};
}
"""
create_migration_file: """
function createMigrationFile(version, description, sqlContent) {
let fileName = "V" + version + "__" + description.replace(/[^a-zA-Z0-9]/g, "_") + ".sql";
let filePath = "src/main/resources/db/migration/" + fileName;
// Write SQL content to file
writeFile(filePath, sqlContent);
return {
fileName: fileName,
filePath: filePath,
version: version,
description: description
};
}
"""
validate_migration: """
function validateMigration(migrationName) {
let flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("classpath:db/migration");
// Validate migrations
let validationResult = flyway.validate();
return {
valid: validationResult.errorDetails === null,
errors: validationResult.errorDetails,
warnings: validationResult.warningDetails
};
}
"""
""";
Map<String, Object> config = parser.parse(tskContent);
// Initialize Flyway migration manager
TuskFlywayMigrationManager flywayMigrationManager = new TuskFlywayMigrationManager();
flywayMigrationManager.configure(config);
// Create migration files
Map<String, Object> migration1 = flywayMigrationManager.createMigrationFile("flyway_methods",
"create_migration_file", Map.of(
"version", "001",
"description", "Create initial schema",
"sqlContent", config.get("migration_001_initial_schema.sql_content")
));
Map<String, Object> migration2 = flywayMigrationManager.createMigrationFile("flyway_methods",
"create_migration_file", Map.of(
"version", "002",
"description", "Add user roles",
"sqlContent", config.get("migration_002_add_user_roles.sql_content")
));
Map<String, Object> migration3 = flywayMigrationManager.createMigrationFile("flyway_methods",
"create_migration_file", Map.of(
"version", "003",
"description", "Add user profile",
"sqlContent", config.get("migration_003_add_user_profile.sql_content")
));
Map<String, Object> migration4 = flywayMigrationManager.createMigrationFile("flyway_methods",
"create_migration_file", Map.of(
"version", "004",
"description", "Add audit tables",
"sqlContent", config.get("migration_004_add_audit_tables.sql_content")
));
// Execute migrations
Map<String, Object> result1 = flywayMigrationManager.executeMigration("flyway_methods",
"execute_flyway_migration", Map.of("migrationName", "001"));
Map<String, Object> result2 = flywayMigrationManager.executeMigration("flyway_methods",
"execute_flyway_migration", Map.of("migrationName", "002"));
Map<String, Object> result3 = flywayMigrationManager.executeMigration("flyway_methods",
"execute_flyway_migration", Map.of("migrationName", "003"));
Map<String, Object> result4 = flywayMigrationManager.executeMigration("flyway_methods",
"execute_flyway_migration", Map.of("migrationName", "004"));
// Validate migrations
Map<String, Object> validation = flywayMigrationManager.validateMigration("flyway_methods",
"validate_migration", Map.of("migrationName", "all"));
System.out.println("Created migration files:");
System.out.println("- " + migration1.get("fileName"));
System.out.println("- " + migration2.get("fileName"));
System.out.println("- " + migration3.get("fileName"));
System.out.println("- " + migration4.get("fileName"));
System.out.println("Migration results:");
System.out.println("Migration 001: " + result1.get("applied") + " applied");
System.out.println("Migration 002: " + result2.get("applied") + " applied");
System.out.println("Migration 003: " + result3.get("applied") + " applied");
System.out.println("Migration 004: " + result4.get("applied") + " applied");
System.out.println("Validation result: " + validation.get("valid"));
}
}
3. Data Migrations
import org.tusklang.java.TuskLang;
import org.tusklang.java.migrations.TuskDataMigrationManager;
import java.util.Map;
import java.util.List;public class DataMigrationExample {
public static void main(String[] args) {
TuskLang parser = new TuskLang();
String tskContent = """
[data_migrations]
# Data Migration Configuration
enable_data_migration: true
enable_data_validation: true
enable_rollback_support: true
[data_migration_001_seed_default_data]
# Seed default data migration
version: "001"
description: "Seed default application data"
environment: ["development", "test", "staging"]
up_method: """
function migrateUp(entityManager) {
let inserted = 0;
// Insert default roles
let roles = [
{ name: 'user', description: 'Regular user' },
{ name: 'admin', description: 'Administrator' },
{ name: 'moderator', description: 'Content moderator' }
];
for (let role of roles) {
let existingRole = entityManager.createQuery("SELECT r FROM Role r WHERE r.name = :name")
.setParameter("name", role.name)
.getResultList();
if (existingRole.length === 0) {
let newRole = new Role(role.name, role.description);
entityManager.persist(newRole);
inserted++;
}
}
// Insert default users
let users = [
{ name: 'System Admin', email: 'admin@example.com', role: 'admin' },
{ name: 'Default User', email: 'user@example.com', role: 'user' }
];
for (let userData of users) {
let existingUser = entityManager.createQuery("SELECT u FROM User u WHERE u.email = :email")
.setParameter("email", userData.email)
.getResultList();
if (existingUser.length === 0) {
let user = new User(userData.name, userData.email);
entityManager.persist(user);
// Assign role
let role = entityManager.createQuery("SELECT r FROM Role r WHERE r.name = :name")
.setParameter("name", userData.role)
.getSingleResult();
user.getRoles().add(role);
inserted++;
}
}
return inserted;
}
"""
down_method: """
function migrateDown(entityManager) {
let deleted = 0;
// Delete default users
let defaultEmails = ['admin@example.com', 'user@example.com'];
for (let email of defaultEmails) {
let users = entityManager.createQuery("SELECT u FROM User u WHERE u.email = :email")
.setParameter("email", email)
.getResultList();
for (let user of users) {
entityManager.remove(user);
deleted++;
}
}
// Delete default roles
let defaultRoles = ['user', 'admin', 'moderator'];
for (let roleName of defaultRoles) {
let roles = entityManager.createQuery("SELECT r FROM Role r WHERE r.name = :name")
.setParameter("name", roleName)
.getResultList();
for (let role of roles) {
entityManager.remove(role);
deleted++;
}
}
return deleted;
}
"""
[data_migration_002_migrate_user_data]
# Migrate user data structure
version: "002"
description: "Migrate user data to new structure"
environment: ["development", "test", "staging", "production"]
up_method: """
function migrateUp(entityManager) {
let migrated = 0;
// Get all users without profiles
let users = entityManager.createQuery("SELECT u FROM User u WHERE u.profile IS NULL")
.getResultList();
for (let user of users) {
// Create user profile
let profile = new UserProfile();
profile.setUser(user);
profile.setBio(user.getBio() || "");
profile.setAvatar(user.getAvatar() || "");
profile.setPhone(user.getPhone() || "");
profile.setDateOfBirth(user.getDateOfBirth());
entityManager.persist(profile);
user.setProfile(profile);
migrated++;
}
return migrated;
}
"""
down_method: """
function migrateDown(entityManager) {
let reverted = 0;
// Get all user profiles
let profiles = entityManager.createQuery("SELECT p FROM UserProfile p")
.getResultList();
for (let profile of profiles) {
let user = profile.getUser();
// Restore data to user table
user.setBio(profile.getBio());
user.setAvatar(profile.getAvatar());
user.setPhone(profile.getPhone());
user.setDateOfBirth(profile.getDateOfBirth());
user.setProfile(null);
entityManager.remove(profile);
reverted++;
}
return reverted;
}
"""
[data_migration_003_update_order_statuses]
# Update order status values
version: "003"
description: "Update order status values to new format"
environment: ["development", "test", "staging", "production"]
up_method: """
function migrateUp(entityManager) {
let updated = 0;
// Update old status values to new format
let statusUpdates = [
{ old: 'pending', new: 'PENDING' },
{ old: 'processing', new: 'PROCESSING' },
{ old: 'completed', new: 'COMPLETED' },
{ old: 'cancelled', new: 'CANCELLED' },
{ old: 'refunded', new: 'REFUNDED' }
];
for (let update of statusUpdates) {
let orders = entityManager.createQuery("SELECT o FROM Order o WHERE o.status = :oldStatus")
.setParameter("oldStatus", update.old)
.getResultList();
for (let order of orders) {
order.setStatus(update.new);
updated++;
}
}
return updated;
}
"""
down_method: """
function migrateDown(entityManager) {
let reverted = 0;
// Revert status values to old format
let statusReverts = [
{ new: 'PENDING', old: 'pending' },
{ new: 'PROCESSING', old: 'processing' },
{ new: 'COMPLETED', old: 'completed' },
{ new: 'CANCELLED', old: 'cancelled' },
{ new: 'REFUNDED', old: 'refunded' }
];
for (let revert of statusReverts) {
let orders = entityManager.createQuery("SELECT o FROM Order o WHERE o.status = :newStatus")
.setParameter("newStatus", revert.new)
.getResultList();
for (let order of orders) {
order.setStatus(revert.old);
reverted++;
}
}
return reverted;
}
"""
[data_migration_methods]
# Data migration methods
execute_data_migration: """
function executeDataMigration(migrationName) {
let migration = @data_migrations[migrationName];
let entityManager = getEntityManager();
try {
entityManager.getTransaction().begin();
let result = migration.up_method(entityManager);
entityManager.getTransaction().commit();
return {
success: true,
migrated: result,
migration: migrationName
};
} catch (error) {
entityManager.getTransaction().rollback();
return {
success: false,
error: error.message,
migration: migrationName
};
}
}
"""
rollback_data_migration: """
function rollbackDataMigration(migrationName) {
let migration = @data_migrations[migrationName];
let entityManager = getEntityManager();
try {
entityManager.getTransaction().begin();
let result = migration.down_method(entityManager);
entityManager.getTransaction().commit();
return {
success: true,
reverted: result,
migration: migrationName
};
} catch (error) {
entityManager.getTransaction().rollback();
return {
success: false,
error: error.message,
migration: migrationName
};
}
}
"""
validate_data_migration: """
function validateDataMigration(migrationName) {
let migration = @data_migrations[migrationName];
let entityManager = getEntityManager();
// Validate migration can be executed
try {
// Test migration logic without committing
entityManager.getTransaction().begin();
// Execute validation logic here
let isValid = true;
let errors = [];
entityManager.getTransaction().rollback();
return {
valid: isValid,
errors: errors,
migration: migrationName
};
} catch (error) {
entityManager.getTransaction().rollback();
return {
valid: false,
errors: [error.message],
migration: migrationName
};
}
}
"""
""";
Map<String, Object> config = parser.parse(tskContent);
// Initialize data migration manager
TuskDataMigrationManager dataMigrationManager = new TuskDataMigrationManager();
dataMigrationManager.configure(config);
// Execute data migrations
Map<String, Object> result1 = dataMigrationManager.executeDataMigration("data_migration_methods",
"execute_data_migration", Map.of("migrationName", "data_migration_001_seed_default_data"));
Map<String, Object> result2 = dataMigrationManager.executeDataMigration("data_migration_methods",
"execute_data_migration", Map.of("migrationName", "data_migration_002_migrate_user_data"));
Map<String, Object> result3 = dataMigrationManager.executeDataMigration("data_migration_methods",
"execute_data_migration", Map.of("migrationName", "data_migration_003_update_order_statuses"));
// Validate migrations
Map<String, Object> validation1 = dataMigrationManager.validateMigration("data_migration_methods",
"validate_data_migration", Map.of("migrationName", "data_migration_001_seed_default_data"));
Map<String, Object> validation2 = dataMigrationManager.validateMigration("data_migration_methods",
"validate_data_migration", Map.of("migrationName", "data_migration_002_migrate_user_data"));
Map<String, Object> validation3 = dataMigrationManager.validateMigration("data_migration_methods",
"validate_data_migration", Map.of("migrationName", "data_migration_003_update_order_statuses"));
System.out.println("Data Migration Results:");
System.out.println("Migration 001: " + (result1.get("success") ? "Success" : "Failed") +
" (" + result1.get("migrated") + " records)");
System.out.println("Migration 002: " + (result2.get("success") ? "Success" : "Failed") +
" (" + result2.get("migrated") + " records)");
System.out.println("Migration 003: " + (result3.get("success") ? "Success" : "Failed") +
" (" + result3.get("migrated") + " records)");
System.out.println("Validation Results:");
System.out.println("Migration 001: " + (validation1.get("valid") ? "Valid" : "Invalid"));
System.out.println("Migration 002: " + (validation2.get("valid") ? "Valid" : "Invalid"));
System.out.println("Migration 003: " + (validation3.get("valid") ? "Valid" : "Invalid"));
}
}
4. Migration Version Control
import org.tusklang.java.TuskLang;
import org.tusklang.java.migrations.TuskMigrationVersionControl;
import java.util.Map;
import java.util.List;public class MigrationVersionControlExample {
public static void main(String[] args) {
TuskLang parser = new TuskLang();
String tskContent = """
[migration_version_control]
# Migration Version Control Configuration
enable_version_tracking: true
enable_migration_history: true
enable_rollback_tracking: true
[version_control_config]
# Version control configuration
version_table: "migration_versions"
history_table: "migration_history"
enable_checksums: true
enable_timestamps: true
[migration_versions]
# Migration version definitions
version_001: {
version: "001"
description: "Initial schema"
checksum: "abc123"
applied_at: "2024-01-01 10:00:00"
environment: "development"
}
version_002: {
version: "002"
description: "Add user roles"
checksum: "def456"
applied_at: "2024-01-02 11:00:00"
environment: "development"
}
version_003: {
version: "003"
description: "Add user profile"
checksum: "ghi789"
applied_at: "2024-01-03 12:00:00"
environment: "development"
}
version_004: {
version: "004"
description: "Add audit tables"
checksum: "jkl012"
applied_at: "2024-01-04 13:00:00"
environment: "development"
}
[version_control_methods]
# Version control methods
track_migration: """
function trackMigration(version, description, checksum) {
let entityManager = getEntityManager();
let migrationVersion = new MigrationVersion();
migrationVersion.setVersion(version);
migrationVersion.setDescription(description);
migrationVersion.setChecksum(checksum);
migrationVersion.setAppliedAt(new Date());
migrationVersion.setEnvironment(@env("SPRING_PROFILES_ACTIVE", "development"));
entityManager.persist(migrationVersion);
// Add to history
let history = new MigrationHistory();
history.setVersion(version);
history.setDescription(description);
history.setAction("APPLY");
history.setTimestamp(new Date());
history.setEnvironment(@env("SPRING_PROFILES_ACTIVE", "development"));
entityManager.persist(history);
return {
version: version,
applied: true,
timestamp: new Date()
};
}
"""
get_migration_status: """
function getMigrationStatus() {
let entityManager = getEntityManager();
let appliedMigrations = entityManager.createQuery("SELECT mv FROM MigrationVersion mv ORDER BY mv.version")
.getResultList();
let pendingMigrations = [];
let allVersions = ["001", "002", "003", "004"];
for (let version of allVersions) {
let applied = appliedMigrations.find(mv => mv.getVersion() === version);
if (!applied) {
pendingMigrations.push(version);
}
}
return {
applied: appliedMigrations.map(mv => mv.getVersion()),
pending: pendingMigrations,
total: allVersions.length,
applied_count: appliedMigrations.length,
pending_count: pendingMigrations.length
};
}
"""
rollback_migration: """
function rollbackMigration(version) {
let entityManager = getEntityManager();
// Find migration version
let migrationVersion = entityManager.createQuery("SELECT mv FROM MigrationVersion mv WHERE mv.version = :version")
.setParameter("version", version)
.getSingleResult();
// Remove from version table
entityManager.remove(migrationVersion);
// Add rollback to history
let history = new MigrationHistory();
history.setVersion(version);
history.setDescription(migrationVersion.getDescription());
history.setAction("ROLLBACK");
history.setTimestamp(new Date());
history.setEnvironment(@env("SPRING_PROFILES_ACTIVE", "development"));
entityManager.persist(history);
return {
version: version,
rolled_back: true,
timestamp: new Date()
};
}
"""
get_migration_history: """
function getMigrationHistory(limit) {
let entityManager = getEntityManager();
let history = entityManager.createQuery("SELECT mh FROM MigrationHistory mh ORDER BY mh.timestamp DESC")
.setMaxResults(limit || 50)
.getResultList();
return history.map(h => ({
version: h.getVersion(),
description: h.getDescription(),
action: h.getAction(),
timestamp: h.getTimestamp(),
environment: h.getEnvironment()
}));
}
"""
""";
Map<String, Object> config = parser.parse(tskContent);
// Initialize migration version control
TuskMigrationVersionControl versionControl = new TuskMigrationVersionControl();
versionControl.configure(config);
// Track migrations
Map<String, Object> track1 = versionControl.trackMigration("version_control_methods",
"track_migration", Map.of("version", "001", "description", "Initial schema", "checksum", "abc123"));
Map<String, Object> track2 = versionControl.trackMigration("version_control_methods",
"track_migration", Map.of("version", "002", "description", "Add user roles", "checksum", "def456"));
Map<String, Object> track3 = versionControl.trackMigration("version_control_methods",
"track_migration", Map.of("version", "003", "description", "Add user profile", "checksum", "ghi789"));
// Get migration status
Map<String, Object> status = versionControl.getMigrationStatus("version_control_methods",
"get_migration_status", Map.of());
// Get migration history
List<Map<String, Object>> history = versionControl.getMigrationHistory("version_control_methods",
"get_migration_history", Map.of("limit", 10));
// Rollback a migration
Map<String, Object> rollback = versionControl.rollbackMigration("version_control_methods",
"rollback_migration", Map.of("version", "003"));
System.out.println("Migration Tracking:");
System.out.println("Version 001: " + (track1.get("applied") ? "Applied" : "Failed"));
System.out.println("Version 002: " + (track2.get("applied") ? "Applied" : "Failed"));
System.out.println("Version 003: " + (track3.get("applied") ? "Applied" : "Failed"));
System.out.println("Migration Status:");
System.out.println("Applied: " + status.get("applied_count") + "/" + status.get("total"));
System.out.println("Pending: " + status.get("pending_count"));
System.out.println("Applied versions: " + status.get("applied"));
System.out.println("Pending versions: " + status.get("pending"));
System.out.println("Migration History:");
for (Map<String, Object> entry : history) {
System.out.println(entry.get("timestamp") + " - " + entry.get("action") + " " +
entry.get("version") + ": " + entry.get("description"));
}
System.out.println("Rollback Result:");
System.out.println("Version " + rollback.get("version") + ": " +
(rollback.get("rolled_back") ? "Rolled back" : "Failed"));
}
}
🔧 Spring Boot Integration
1. Spring Boot Configuration
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.tusklang.java.TuskLang;
import org.tusklang.java.spring.TuskMigrationConfig;@SpringBootApplication
@Configuration
public class MigrationApplication {
@Bean
public TuskMigrationConfig tuskMigrationConfig() {
TuskLang parser = new TuskLang();
return parser.parseFile("migrations.tsk", TuskMigrationConfig.class);
}
public static void main(String[] args) {
SpringApplication.run(MigrationApplication.class, args);
}
}
@TuskConfig
public class TuskMigrationConfig {
private JPAMigrationConfig jpaMigrations;
private FlywayMigrationConfig flywayMigrations;
private DataMigrationConfig dataMigrations;
private MigrationVersionControlConfig versionControl;
// Getters and setters
public JPAMigrationConfig getJpaMigrations() { return jpaMigrations; }
public void setJpaMigrations(JPAMigrationConfig jpaMigrations) { this.jpaMigrations = jpaMigrations; }
public FlywayMigrationConfig getFlywayMigrations() { return flywayMigrations; }
public void setFlywayMigrations(FlywayMigrationConfig flywayMigrations) { this.flywayMigrations = flywayMigrations; }
public DataMigrationConfig getDataMigrations() { return dataMigrations; }
public void setDataMigrations(DataMigrationConfig dataMigrations) { this.dataMigrations = dataMigrations; }
public MigrationVersionControlConfig getVersionControl() { return versionControl; }
public void setVersionControl(MigrationVersionControlConfig versionControl) { this.versionControl = versionControl; }
}
🎯 Best Practices
1. Migration Design Patterns
// ✅ Use versioned migrations
- Always use version numbers
- Use descriptive names
- Include rollback support// ✅ Implement proper validation
- Validate migrations before execution
- Check data integrity
- Test rollback procedures
// ✅ Use environment-specific migrations
- Different migrations for different environments
- Conditional migration execution
- Environment-specific data
// ✅ Implement proper error handling
- Use transactions for migrations
- Implement rollback mechanisms
- Log migration errors
2. Performance Optimization
// 1. Migration Execution
- Use batch operations for large datasets
- Implement incremental migrations
- Monitor migration performance// 2. Database Optimization
- Use appropriate indexes
- Optimize SQL queries
- Monitor database performance
// 3. Version Control
- Track migration versions
- Implement checksums
- Maintain migration history
// 4. Testing
- Test migrations in development
- Validate migration results
- Test rollback procedures
🚀 Summary
TuskLang Java database migrations provide:
- JPA Schema Migrations: Seamless JPA integration with schema generation - Spring Boot Flyway Integration: Native Spring Boot Flyway support - Data Migrations: Comprehensive data migration capabilities - Migration Version Control: Complete version tracking and history - Spring Boot Integration: Native Spring Boot configuration support
With these migration features, your Java applications will achieve enterprise-grade database migration management while maintaining the flexibility and power of TuskLang configuration.
"We don't bow to any king" - Migrate your database like a Java master with TuskLang!