diff --git a/docs/src/database_functionality.md b/docs/src/database_functionality.md index 34e2eb4..1eef90f 100644 --- a/docs/src/database_functionality.md +++ b/docs/src/database_functionality.md @@ -9,10 +9,12 @@ A connection to the online [ldp-database](https://www.math.uni-tuebingen.de/forschung/algebra/ldp-database/) is planned. + ```@docs DatabaseAdapter SQLiteAdapter SQLiteAdapterSurfaces +create_table import_from_database find_in_database default_column_functions diff --git a/src/Database/SQLiteAdapter.jl b/src/Database/SQLiteAdapter.jl index 84ba071..8205f36 100644 --- a/src/Database/SQLiteAdapter.jl +++ b/src/Database/SQLiteAdapter.jl @@ -2,10 +2,9 @@ SQLiteAdapter{T} <: DatabaseAdapter{T} An adapter to an SQLite database holding objects of type `T` where `T <: -MoriDreamSpace`. The type `T` should at least implement the following methods -(see their docstrings for more information): - -`default_column_functions`, `find_in_database`, `sqlite_import_row`. +MoriDreamSpace`. The type `T` should at least implement the following methods: +[`create_table`](@ref), [`default_column_functions`](@ref), +[`find_in_database`](@ref), [`sqlite_import_row`](@ref). """ struct SQLiteAdapter{T} <: DatabaseAdapter{T} @@ -21,10 +20,10 @@ end @doc raw""" default_column_functions(::Type{T}) where {T <: MoriDreamSpace} -Returns a `Dict{Symbol, Function}` that serves as a default for the -names of the columns to export and how to export them for a given -subtype of `MoriDreamSpace`. Should be implemented by all subtypes -of `MoriDreamSpace` where database functionality is desired. +Returns a `Dict{Symbol, Function}` that serves as a default for the names of +the columns to export and how to export them for a given subtype of +`MoriDreamSpace`. This should be implemented by all subtypes of +`MoriDreamSpace` where database functionality is desired. The fallback definition for a general `T` returns an empty dictionary. @@ -166,6 +165,7 @@ import_from_database(db :: SQLiteAdapter{T}, id :: Int) where {T <: MoriDreamSpa _argsym_to_arg(T :: Type{<:MoriDreamSpace}, row :: Union{SQLite.Row, NamedTuple}, argsym :: Symbol) = argsym == :variety ? sqlite_import_row(T, row) : row[argsym] + @doc raw""" update_in_database(db :: SQLiteAdapter{T}, column_functions :: Dict{Symbol, <:Function}; sql :: String, column_function_args :: AbstractVector{Symbol}) where {T <: MoriDreamSpace} diff --git a/src/Database/SQLiteAdapterSurfaces.jl b/src/Database/SQLiteAdapterSurfaces.jl index c0b52b3..7b33a78 100644 --- a/src/Database/SQLiteAdapterSurfaces.jl +++ b/src/Database/SQLiteAdapterSurfaces.jl @@ -8,6 +8,120 @@ An adapter to an SQLite database holding objects of type """ const SQLiteAdapterSurfaces = SQLiteAdapter{SurfaceWithTorusAction} + + +# The list of column names together with their SQLite definition. The last +# entry in each tuple says if the column is explicitly exported. It is false +# for columns that are automatically computed from other columns, such as +# `log_canonicity`. +const _db_column_defs = [ + (:is_toric, "INTEGER NOT NULL", true), + (:gen_matrix, "TEXT NOT NULL", true), + (:rays, "TEXT", true), + (:nrays, "INTEGER", true), + (:lss, "TEXT", true), + (:dss, "TEXT", true), + (:case_, "TEXT", true), + (:block_sizes, "TEXT", true), + (:nblocks, "INTEGER", true), + (:number_of_parabolic_fixed_point_curves, "INTEGER", true), + (:orientation, "INTEGER", true), + (:is_intrinsic_quadric, "INTEGER", true), + (:class_group_rank, "INTEGER", true), + (:class_group_torsion, "TEXT", true), + (:class_group_torsion_order, "INTEGER", true), + (:degree_matrix, "TEXT", true), + (:canonical_divisor_class, "TEXT", true), + (:gorenstein_index, "INTEGER", true), + (:picard_index, "INTEGER", true), + (:log_canonicity_numerator, "INTEGER", true), + (:log_canonicity_denominator, "INTEGER", true), + (:log_canonicity, "REAL AS (CAST(log_canonicity_numerator AS FLOAT) / CAST(log_canonicity_denominator AS FLOAT))", false), + (:anticanonical_self_intersection_numerator, "INTEGER", true), + (:anticanonical_self_intersection_denominator, "INTEGER", true), + (:anticanonical_self_intersection, "REAL AS (CAST(anticanonical_self_intersection_numerator AS FLOAT) / CAST(anticanonical_self_intersection_denominator AS FLOAT))", false), + (:admits_kaehler_ricci_soliton, "INTEGER", false), + (:admits_kaehler_einstein_metric, "INTEGER", true), + (:admits_sasaki_einstein_metric, "INTEGER", false), + (:is_quasismooth, "INTEGER", true), + (:is_factorial, "INTEGER", true), + (:is_smooth, "INTEGER", true), + (:number_of_singularities, "INTEGER", true), +] + +@doc raw""" + create_table(db :: SQLiteAdapterSurfaces; temp = false, ifnotexists = true) + +Create a new SQLite table with default column definitions holding +`SurfaceWithTorusAction`s. + +# Example + +Create a new SQLite database for holding `SurfaceWithTorusAction`s. The +resulting table can be inspected with +[`SQLite.jl`](https://juliadatabases.org/SQLite.jl/stable/): + +```jldoctest +julia> db = SQLiteAdapterSurfaces("my_database.db", "surfaces", "surface_id") +SQLiteAdapterSurfaces(SQLite.DB("my_database.db"), "my_database.db", "surfaces", "surface_id") + +julia> create_table(db); + +julia> using SQLite + +julia> SQLite.tables(db.db) +1-element Vector{SQLite.DBTable}: + SQLite.DBTable("surfaces", Tables.Schema: + :surface_id Union{Missing, Int64} + :is_toric Union{Missing, Int64} + :gen_matrix Union{Missing, String} + :rays Union{Missing, String} + :nrays Union{Missing, Int64} + :lss Union{Missing, String} + :dss Union{Missing, String} + :case_ Union{Missing, String} + :block_sizes Union{Missing, String} + :nblocks Union{Missing, Int64} + :number_of_parabolic_fixed_point_curves Union{Missing, Int64} + :orientation Union{Missing, Int64} + :is_intrinsic_quadric Union{Missing, Int64} + :class_group_rank Union{Missing, Int64} + :class_group_torsion Union{Missing, String} + :class_group_torsion_order Union{Missing, Int64} + :degree_matrix Union{Missing, String} + :canonical_divisor_class Union{Missing, String} + :gorenstein_index Union{Missing, Int64} + :picard_index Union{Missing, Int64} + :log_canonicity_numerator Union{Missing, Int64} + :log_canonicity_denominator Union{Missing, Int64} + :log_canonicity Union{Missing, Float64} + :anticanonical_self_intersection_numerator Union{Missing, Int64} + :anticanonical_self_intersection_denominator Union{Missing, Int64} + :anticanonical_self_intersection Union{Missing, Float64} + :admits_kaehler_ricci_soliton Union{Missing, Int64} + :admits_kaehler_einstein_metric Union{Missing, Int64} + :admits_sasaki_einstein_metric Union{Missing, Int64} + :is_quasismooth Union{Missing, Int64} + :is_factorial Union{Missing, Int64} + :is_smooth Union{Missing, Int64} + :number_of_singularities Union{Missing, Int64}) + +``` + +""" +function create_table(db :: SQLiteAdapterSurfaces; temp = false, ifnotexists = true) + temp = temp ? "TEMP" : "" + ifnotexists = ifnotexists ? "IF NOT EXISTS" : "" + columns = [string(db.primary_key, ' ', "INTEGER PRIMARY KEY ASC")] + for (column_name, column_def, _) in _db_column_defs + push!(columns, string(column_name, ' ', column_def)) + end + sql = "CREATE $temp TABLE $ifnotexists $(db.table_name) ($(join(columns, ',')))" + DBInterface.execute(db.db, sql) +end + + + ################################################## # Default functions to compute the columns in the # SQLite database @@ -105,36 +219,9 @@ result as a language-agnostic string for database storage instead of a Julia type. """ -default_column_functions(::Type{<:SurfaceWithTorusAction}) = Dict([ -:is_toric => _db_is_toric, -:gen_matrix => _db_gen_matrix, -:rays => _db_rays, -:nrays => _db_nrays, -:lss => _db_lss, -:dss => _db_dss, -:case_ => _db_case_, -:block_sizes => _db_block_sizes, -:nblocks => _db_nblocks, -:number_of_parabolic_fixed_point_curves => _db_number_of_parabolic_fixed_point_curves, -:orientation => _db_orientation, -:is_intrinsic_quadric => _db_is_intrinsic_quadric, -:class_group_rank => _db_class_group_rank, -:class_group_torsion => _db_class_group_torsion, -:class_group_torsion_order => _db_class_group_torsion_order, -:degree_matrix => _db_degree_matrix, -:canonical_divisor_class => _db_canonical_divisor_class, -:gorenstein_index => _db_gorenstein_index, -:picard_index => _db_picard_index, -:log_canonicity_numerator => _db_log_canonicity_numerator, -:log_canonicity_denominator => _db_log_canonicity_denominator, -:anticanonical_self_intersection_numerator => _db_anticanonical_self_intersection_numerator, -:anticanonical_self_intersection_denominator => _db_anticanonical_self_intersection_denominator, -:admits_kaehler_einstein_metric => _db_admits_kaehler_einstein_metric, -:is_quasismooth => _db_is_quasismooth, -:is_factorial => _db_is_factorial, -:is_smooth => _db_is_smooth, -:number_of_singularities => _db_number_of_singularities -]) +default_column_functions(::Type{<:SurfaceWithTorusAction}) = +Dict([column_name => eval(Symbol(:_db_, column_name)) + for (column_name, _, exported) in _db_column_defs if exported]) @doc raw""" diff --git a/src/exports.jl b/src/exports.jl index a2a391a..f29d3e9 100644 --- a/src/exports.jl +++ b/src/exports.jl @@ -1,3 +1,4 @@ +export create_table export AdmissibleOperation export AdmissibleRowOperation export admits_kaehler_einstein_metric diff --git a/test/Database/create.sql b/test/Database/create.sql deleted file mode 100644 index 1a3decf..0000000 --- a/test/Database/create.sql +++ /dev/null @@ -1,136 +0,0 @@ -CREATE TABLE IF NOT EXISTS surfaces ( - -- the unique id of a surface in the database. - surface_id INTEGER PRIMARY KEY ASC, - - -- 1 if the surface toric, 0 otherwise. - is_toric INTEGER NOT NULL, - - -- the generator matrix (P-Matrix) of the surface. The columns of - -- this matrix are the rays of the canonical toric ambient variety. - -- This field is stored as a list of rows with each row a list of - -- integers. For example: - -- "[[-1, -1, 2, 0], [-1, -1, 0, 2], [0, -2, 1, 1]]" - gen_matrix TEXT NOT NULL, - - -- The rays of the canonical toric ambient, stored as a list of lists - -- of integers. For example: - -- "[[-1, -1, 0], [-1, -1, -2], [2, 0, 1], [0, 2, 1]]" - rays TEXT, - - -- the number of rays of the canonical toric ambient. - nrays INTEGER, - - -- The vectors l_i=(l_{i1}, ..., l_{in_i}) that make up the upper - -- rows of the generator matrix of a C-star surface. For example: - -- [[1, 1], [2], [2]] - lss TEXT, -- NULL for toric surfaces - - -- The vectors d_i=(d_{i1}, ..., d_{in_i}) that make up the lower - -- rows of the generator matrix of a C-star surface. For example: - -- [[0, -2], [1], [1]] - dss TEXT, -- NULL for toric surfaces - - -- The case of the C-star surface, i.e. one of the strings - -- "ee", "pe", "ep" and "pp". - case_ TEXT, -- NULL for toric surfaces - - -- The sizes of the blocks in the generator matrix of a C-star - -- surface. For example: - -- [2, 1, 1]. - block_sizes TEXT,-- NULL for toric surfaces - - -- The number of blocks in the generator matrix of a C-star surface - nblocks INTEGER, -- NULL for toric surfaces - - -- The number of parabolic fixed point curves of a C-star surface. - -- This is always either 0, 1 or 2. - number_of_parabolic_fixed_point_curves INTEGER,-- NULL for toric surfaces - - -- The orientation of the generator matrix of a C-star surface. - -- This is always either -1, 0 or 1. - orientation INTEGER, -- NULL for toric surfaces - - -- Whether the C-star surface is an intrinsic quadric, i.e. its Cox - -- Ring has a single quadratic equation. - is_intrinsic_quadric INTEGER, --NULL for toric surfaces - - -- The rank of the divisor class group. - class_group_rank INTEGER, - - -- The elementary divisors of the torsion part of the class group, - -- as a list of integers. - class_group_torsion TEXT, - - -- The order of the torsion part of the class group. This equals the - -- product of the entries of `class_group_torsion`. - class_group_torsion_order INTEGER, - - -- A (non-unique) choice of the degree matrix of a surface with torus - -- action. This is a gale dual of the generator matrix. - degree_matrix TEXT, - - -- A representation of a canoniacal divisor class as a list of - -- integer coefficients. By convention, the free part comes first, - -- then the torsion part. - canonical_divisor_class TEXT, - - -- The gorenstein index of a surface with torus action. - gorenstein_index INTEGER, - - -- The Picard index of a surface with torus action. - picard_index INTEGER, - - -- the numerator of the macimal log canonicity. - log_canonicity_numerator INTEGER, - - -- the denominator of the macimal log canonicity. - log_canonicity_denominator INTEGER, - - -- The maximal rational number $\epsilon$ such that the surface is - -- $\epsilon$-log terminal, represented by a floating point number. - -- This column is automatically calculated from numerator and denominator. - log_canonicity REAL AS (CAST(log_canonicity_numerator AS FLOAT) / CAST(log_canonicity_denominator AS FLOAT)), - - -- the numerator of the anticanonical self intersection. - anticanonical_self_intersection_numerator INTEGER, - - -- the denominator of the anticanonical self intersection. - anticanonical_self_intersection_denominator INTEGER, - - -- the anticanonical self intersection as a floating point number. - anticanonical_self_intersection REAL AS (CAST(anticanonical_self_intersection_numerator AS FLOAT) / CAST(anticanonical_self_intersection_denominator AS FLOAT)), - - -- whether the surface admits a Kaehler-Ricci soliton - admits_kaehler_ricci_soliton INTEGER, - - -- whether the surface admits a Kaehler Einstein metric - admits_kaehler_einstein_metric INTEGER, - - -- whether the surface admits a Sasaki Einstein metric - admits_sasaki_einstein_metric INTEGER, - - -- whether the surface is quasi-smooth - is_quasismooth INTEGER, - - -- whether the surface is factorial - is_factorial INTEGER, - - -- whether the surface is smooth - is_smooth INTEGER, - - number_of_singularities INTEGER - -) - - - - - - - - - - - - - diff --git a/test/Database/sqlite_database.jl b/test/Database/sqlite_database.jl index 9d76779..1f6205c 100644 --- a/test/Database/sqlite_database.jl +++ b/test/Database/sqlite_database.jl @@ -1,8 +1,7 @@ DB_FILE_PATH = joinpath(dirname(@__FILE__), "test.db") # DB_FILE_PATH = "test/Database/test.db" -CREATE_TABLE_FILE_PATH = joinpath(dirname(@__FILE__), "create.sql") -# CREATE_TABLE_FILE_PATH = "test/Database/create.sql" + TABLE_NAME = "surfaces" PRIMARY_KEY = "surface_id" @@ -10,7 +9,7 @@ PRIMARY_KEY = "surface_id" rm(DB_FILE_PATH, force=true) db = SQLiteAdapter{SurfaceWithTorusAction}(DB_FILE_PATH, TABLE_NAME, PRIMARY_KEY) - DBInterface.execute(db.db, read(CREATE_TABLE_FILE_PATH, String)) + create_table(db) @testset "Insert C-star surface" begin