From 5b88e9382f07ab3c6c5054a78f9c199bc1baa0a7 Mon Sep 17 00:00:00 2001 From: Luciano Rolando Lorenti Date: Mon, 16 Mar 2020 00:30:49 +0100 Subject: [PATCH] Add the option to select fields returned by select_all --- Project.toml | 2 +- src/NonRelational/Redis.jl | 35 ++++++++++++++++++++++------------- src/Relational/Relational.jl | 24 ++++++++++++++++-------- src/StructDatabaseMapping.jl | 10 +++++----- test/includes/basic_test.jl | 23 ++++++++++++++++++----- test/postgresql/TestLibPQ.jl | 1 + test/sqlite/TestSQLite.jl | 1 + 7 files changed, 64 insertions(+), 32 deletions(-) diff --git a/Project.toml b/Project.toml index 42ce35e..a3e30fb 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "StructDatabaseMapping" uuid = "66daddfc-c305-4fd9-8f84-fb59daccc546" authors = ["Luciano Rolando Lorenti "] -version = "0.3.1" +version = "0.3.2" [deps] DBInterface = "a10d1c49-ce27-4219-8d33-6db1a4562965" diff --git a/src/NonRelational/Redis.jl b/src/NonRelational/Redis.jl index 6e9ff79..58a6db9 100644 --- a/src/NonRelational/Redis.jl +++ b/src/NonRelational/Redis.jl @@ -79,16 +79,21 @@ function select_by_key_and_params(mapper::DBMapper, dbtype::Type{Redis.RedisConn return unmarshal(mapper, T, Dict(zip(params_key, elem_values)); partial=true) end -function iterate_all(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}, params, f) +function iterate_all(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}, + conditions, apply_function, fields::Array{Symbol}=Symbol[]) conn = get_connection(mapper.pool) cursor = -1 - params_key = collect(keys(params)) + conditions_fields = collect(keys(conditions)) + if isempty(fields) + fields = column_names(mapper, T) + end + fields_to_obtain = union(conditions_fields, fields) while cursor != 0 (cursor, results) = Redis.scan(conn, cursor == -1 ? 0 : cursor, "match", redis_wildcard(T)) - for elem_key in results - elem_values = Redis.hmget(conn, elem_key, params_key...) - elem = unmarshal(mapper, T, Dict(zip(params_key, elem_values)); partial=true) - ret = f(elem_key, elem, params, params_key) + for elem_key in results + elem_values = Redis.hmget(conn, elem_key, fields_to_obtain...) + elem = unmarshal(mapper, T, Dict{Symbol, Any}(zip(fields_to_obtain, elem_values)); partial=true) + ret = apply_function(elem_key, elem, conditions, conditions_fields) if (typeof(ret) <: Bool && ret == true) || (!(typeof(ret) <: Bool) && ret !== nothing) release_connection(mapper.pool, conn) return ret @@ -122,8 +127,8 @@ function exists(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{< end return false end - -function Base.delete!(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}; kwargs...) +import Base:delete! +function delete!(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}; kwargs...) (id, params) = extract_id_from_kwargs(mapper, T; kwargs...) if id !== nothing if length(params) == 0 @@ -153,15 +158,19 @@ function Base.delete!(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T:: end end -function select_all(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}; kwargs...) - params = Dict(kwargs...) +function select_all(mapper::DBMapper, dbtype::Type{Redis.RedisConnection}, T::Type{<:Model}; fields::Array{Symbol}=[], kwargs...) ::Array{T} + conditions = Dict(kwargs...) all_elems = [] - found = (elem_key, elem, params, params_key)->begin + found_function = (elem_key, elem, params, params_key)->begin if all([params[k] == elem[k] for k in params_key]) push!(all_elems, elem) end return nothing end - ret = iterate_all(mapper, dbtype, T, params, found) - return all_elems + ret = iterate_all(mapper, dbtype, T, conditions, found_function, fields) + if isempty(all_elems) + return nothing + else + return [T(;unmarshal(mapper, T, elem, partial=!isempty(fields))...) for elem in all_elems] + end end diff --git a/src/Relational/Relational.jl b/src/Relational/Relational.jl index 2c56c06..586c465 100644 --- a/src/Relational/Relational.jl +++ b/src/Relational/Relational.jl @@ -166,7 +166,9 @@ function totuple(mapper::DBMapper, table::Table, dbtype::DataType, db_results) : db_data = Dict(field=>getindex(row, field) for field in propertynames(row)) for field in fieldlist(table) - push!(r, field.struct_field=>unmarshal(mapper, dbtype, field.type, db_data[field.name])) + if haskey(db_data, field.name) + push!(r, field.struct_field=>unmarshal(mapper, dbtype, field.type, db_data[field.name])) + end end push!(results, r) end @@ -177,26 +179,32 @@ function totuple(results) [(;(prop=>getindex(row, prop) for prop in propertynames(row))...) for row in results] end -function select_query(mapper::DBMapper, T::Type{<:Model}; select_one=true, kwargs...) +function select_query(mapper::DBMapper, T::Type{<:Model}; select_one=true, fields::Array{Symbol}=Symbol[], kwargs...) dbtype = mapper.pool.dbtype table = mapper.tables[T] - cnames = join(column_names(mapper, T), ", ") + if isempty(fields) + fields = column_names(mapper, T) + end + cnames = join(fields, ", ") conditions = join(["$field=?" for (field, value) in kwargs], " AND ") sql = """ SELECT $cnames FROM $(table.name) - WHERE $(conditions) """ + if !isempty(conditions) + sql *= """ + WHERE $(conditions)""" + end if select_one sql *= " LIMIT 1" end return clean_sql(sql) end -function select(mapper::DBMapper, T::Type{<:Model}; select_one=true, kwargs...) +function select(mapper::DBMapper, T::Type{<:Model}; select_one=true, fields::Array{Symbol}=Symbol[], kwargs...) dbtype = mapper.pool.dbtype table = mapper.tables[T] - sql = select_query(mapper, T; select_one=select_one, kwargs...) + sql = select_query(mapper, T; select_one=select_one, fields=fields, kwargs...) values = [v[2] for v in kwargs] @info sql conn = get_connection(mapper.pool) @@ -215,8 +223,8 @@ function select_one(mapper::DBMapper, ::Type{Relational}, T::Type{<:Model}; kwar end end -function select_all(mapper::DBMapper, ::Type{Relational}, T::Type{<:Model}; kwargs...) :: Array{T} - result = select(mapper, T; select_one=false, kwargs...) +function select_all(mapper::DBMapper, ::Type{Relational}, T::Type{<:Model}; fields::Array{Symbol} =Symbol[], kwargs...) :: Array{T} + result = select(mapper, T; select_one=false, fields=fields, kwargs...) if isempty(result) return T[] else diff --git a/src/StructDatabaseMapping.jl b/src/StructDatabaseMapping.jl index 3ceb0e5..4600920 100644 --- a/src/StructDatabaseMapping.jl +++ b/src/StructDatabaseMapping.jl @@ -569,7 +569,7 @@ function Base.delete!(mapper::DBMapper, elem::T) where T<:Model end """ - select_all(mapper::DBMapper, T::Type{<:Model}; kwargs...) + select_all(mapper::DBMapper, T::Type{<:Model}; ; fields::Array{Symbol}=[], kwargs...) Select all the elements that meet a criteria @@ -583,12 +583,12 @@ struct Author <: Model ... end select_all(mapper, Author, age=30) ``` """ -function select_all(mapper::DBMapper, T::Type{<:Model}; kwargs...) +function select_all(mapper::DBMapper, T::Type{<:Model}; fields::Array{Symbol}=Symbol[], kwargs...) check_valid_type(mapper, T) - return select_all(mapper, mapper.pool.dbtype, T; kwargs...) + return select_all(mapper, mapper.pool.dbtype, T; fields=fields, kwargs...) end -function select_all(mapper::DBMapper, dbtype::DataType, T::Type{<:Model}; kwargs...) - return select_all(mapper, database_kind(dbtype), T; kwargs...) +function select_all(mapper::DBMapper, dbtype::DataType, T::Type{<:Model}; fields::Array{Symbol}=Symbol[], kwargs...) + return select_all(mapper, database_kind(dbtype), T; fields=fields, kwargs...) end """ diff --git a/test/includes/basic_test.jl b/test/includes/basic_test.jl index 5dbb729..43daca4 100644 --- a/test/includes/basic_test.jl +++ b/test/includes/basic_test.jl @@ -2,13 +2,15 @@ mutable struct Author <: Model id::DBId{Integer} name::String age::Integer + country::String date::DateTime end function Author(;id::Union{Integer, Nothing} = nothing, name::String="", age::Integer=0, + country::String="", date::DateTime=now()) - return Author(id, name, age, date) + return Author(id, name, age, country, date) end mutable struct Book <: Model id::DBId{String} @@ -62,18 +64,21 @@ function _test_basic_functionalities(creator) create_table(mapper, Author) create_table(mapper, Book) - author = Author(name="pirulo", age=50) + author = Author(name="pirulo", age=50, country="Argentina") insert!(mapper, author) @test !isnothing(author.id.x) id = author.id.x - author = Author(name="Author 1", age=3) + author = Author(name="Author 1", age=3, country="Argentina") insert!(mapper, author) - author = Author(name="Author 2", age=3) + author = Author(name="Author 2", age=3, country="Brasil") insert!(mapper, author) - author = Author(name="Author 3", age=3) + author = Author(name="Author 5", age=25, country="Italia") + insert!(mapper, author) + + author = Author(name="Author 3", age=3, country="Uruguay") insert!(mapper, author) @test StructDatabaseMapping.exists(mapper, Author, name="Enrique Banch") == false @@ -87,8 +92,16 @@ function _test_basic_functionalities(creator) authors = select_all(mapper, Author, age=3) + @test isa(authors[1], Author) @test length(authors) == 3 + authors = select_all(mapper, Author) + @test length(authors) == 5 + + authors = select_all(mapper, Author, age=3, fields=[:name, :country]) + @test Set([author.country for author in authors]) == Set(["Brasil", "Argentina", "Uruguay"]) + + a = select_one(mapper, Author, id=999) @test isnothing(a) a = select_one(mapper, Author, id=id) diff --git a/test/postgresql/TestLibPQ.jl b/test/postgresql/TestLibPQ.jl index 4bba815..6479748 100644 --- a/test/postgresql/TestLibPQ.jl +++ b/test/postgresql/TestLibPQ.jl @@ -34,6 +34,7 @@ function test_create_tables() @test (StructDatabaseMapping.create_table_query(mapper, Author) == "CREATE TABLE IF NOT EXISTS author (" * "age INTEGER NOT NULL, " * + "country VARCHAR NOT NULL, " * "date TIMESTAMP NOT NULL, " * "id SERIAL PRIMARY KEY, " * "name VARCHAR NOT NULL)") diff --git a/test/sqlite/TestSQLite.jl b/test/sqlite/TestSQLite.jl index 077f02c..785253c 100644 --- a/test/sqlite/TestSQLite.jl +++ b/test/sqlite/TestSQLite.jl @@ -27,6 +27,7 @@ function test_create_tables() @test (StructDatabaseMapping.create_table_query(mapper, Author) == "CREATE TABLE IF NOT EXISTS author (" * "age INTEGER NOT NULL, " * + "country VARCHAR NOT NULL, " * "date DATETIME NOT NULL, " * "id INTEGER PRIMARY KEY, " * "name VARCHAR NOT NULL)")