Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generating tables from struct definitions #74

Open
PGimenez opened this issue Aug 25, 2023 · 1 comment
Open

Generating tables from struct definitions #74

PGimenez opened this issue Aug 25, 2023 · 1 comment
Assignees

Comments

@PGimenez
Copy link
Member

PGimenez commented Aug 25, 2023

In ORMS like Django you only define a class for the data type and it'll automatically create the migration and the table with the makemigrationand migratecommands. This certainly makes the workflow easier as the user only needs to modify one file. We could do something similar to avoid having to manually edit the migration file. I've taken a first step by creating the migration file from a struct

using Dates, SearchLight

function generate_migration(migration_name, struct_list...)
    # Convert Julia types to DB column types
    function type_to_dbcolumn(t)
        return t == String ? :string :
               t == Float64 ? :float :
               t == Int ? :int : error("Unsupported type: $t")
    end

    # Generate migration for a single struct
    function migration_for_struct(s, table_name)
        field_names = fieldnames(s)
        field_types = fieldtypes(s)

        col_defs = [":$(field_names[i]) => :$(type_to_dbcolumn(field_types[i]))" for i in 2:length(field_names)]

        return """
        function up()
            create_table(:$table_name) do
                [
                    pk()
                    columns([
                        $(join(col_defs, ",\n\t\t"))
                    ])
                ]
            end
        end

        function down()
            drop_table($table_name)
        end
        """
    end

    # Process struct_list to separate structs from optional table names
    structs_with_processed_names = []

    @show struct_list
    for item in struct_list
        if typeof(item) == Tuple{DataType, String}
            s, name = item
            push!(structs_with_processed_names, (s, name))
        elseif typeof(item) == DataType
            s = item
            push!(structs_with_processed_names, (s, lowercase(string(s))*"s"))
        end
    end
    # Loop over each struct and generate the migration code
    migrations = [migration_for_struct(s, table_name) for (s, table_name) in structs_with_processed_names]

    # Bundle the generated migrations into a module
    migration_code = """
    module $migration_name

    import SearchLight.Migrations: create_table, column, columns, pk, add_index, drop_table, add_indices

    $(join(migrations, "\n\n"))

    end
    """

    # Save to file
    filename = SearchLight.Migration.migration_file_name(migration_name)
    open(filename, "w") do file
        write(file, migration_code)
    end
    println("Migration saved to $filename")

    return migration_code
end

Example usage

import SearchLight: AbstractModel, DbId
import Base: @kwdef
@kwdef mutable struct RandomVector <: AbstractModel
    id::DbId = DbId()
    x::String = ""
    m::Float64 = 0.0
    N::Int = 0
end

# Using the function with a mix of explicit table names and just structs
println(generate_migration("RandomVectors", RandomVector, (RandomVector, "my_table_name")))
@PGimenez PGimenez self-assigned this Aug 25, 2023
@essenciary
Copy link
Member

Nice, this is something that came up a few times already. It would be a great feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants