Allow query results to be read as named tuples directly (#56)
This commit is contained in:
parent
28b17b7dba
commit
d55a34e851
|
@ -138,6 +138,12 @@ describe DummyDriver do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "with a named tuple" do
|
||||||
|
with_dummy do |db|
|
||||||
|
db.query_one("3,4", as: {a: Int64, b: Int64}).should eq({a: 3i64, b: 4i64})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "with as, just one" do
|
it "with as, just one" do
|
||||||
with_dummy do |db|
|
with_dummy do |db|
|
||||||
db.query_one("3", as: Int64).should eq(3i64)
|
db.query_one("3", as: Int64).should eq(3i64)
|
||||||
|
@ -176,6 +182,14 @@ describe DummyDriver do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "with as" do
|
||||||
|
with_dummy do |db|
|
||||||
|
value = db.query_one?("3,4", as: {a: Int64, b: Int64})
|
||||||
|
value.should be_a(NamedTuple(a: Int64, b: Int64)?)
|
||||||
|
value.should eq({a: 3i64, b: 4i64})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "with as, just one" do
|
it "with as, just one" do
|
||||||
with_dummy do |db|
|
with_dummy do |db|
|
||||||
value = db.query_one?("3", as: Int64)
|
value = db.query_one?("3", as: Int64)
|
||||||
|
@ -200,6 +214,13 @@ describe DummyDriver do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "queries with a named tuple" do
|
||||||
|
with_dummy do |db|
|
||||||
|
ary = db.query_all "3,4 1,2", as: {a: Int64, b: Int64}
|
||||||
|
ary.should eq([{a: 3, b: 4}, {a: 1, b: 2}])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "queries with as, just one" do
|
it "queries with as, just one" do
|
||||||
with_dummy do |db|
|
with_dummy do |db|
|
||||||
ary = db.query_all "3 1", as: Int64
|
ary = db.query_all "3 1", as: Int64
|
||||||
|
|
|
@ -88,6 +88,21 @@ module DB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a *query* that expects a single row and returns it
|
||||||
|
# as a named tuple of the given *types* (the keys of the named tuple
|
||||||
|
# are not necessarily the column names).
|
||||||
|
#
|
||||||
|
# Raises `DB::Error` if there were no rows, or if there were more than one row.
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# db.query_one "select name, age from contacts where id = ?", 1, as: {name: String, age: Int32}
|
||||||
|
# ```
|
||||||
|
def query_one(query, *args, as types : NamedTuple)
|
||||||
|
query_one(query, *args) do |rs|
|
||||||
|
rs.read(**types)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Executes a *query* that expects a single row
|
# Executes a *query* that expects a single row
|
||||||
# and returns the first column's value as the given *type*.
|
# and returns the first column's value as the given *type*.
|
||||||
#
|
#
|
||||||
|
@ -141,6 +156,24 @@ module DB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a *query* that expects a single row and returns it
|
||||||
|
# as a named tuple of the given *types* (the keys of the named tuple
|
||||||
|
# are not necessarily the column names).
|
||||||
|
#
|
||||||
|
# Returns `nil` if there were no rows.
|
||||||
|
#
|
||||||
|
# Raises `DB::Error` if there were more than one row.
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# result = db.query_one? "select name, age from contacts where id = ?", 1, as: {age: String, name: Int32}
|
||||||
|
# typeof(result) # => NamedTuple(age: String, name: Int32) | Nil
|
||||||
|
# ```
|
||||||
|
def query_one?(query, *args, as types : NamedTuple)
|
||||||
|
query_one(query, *args) do |rs|
|
||||||
|
rs.read(**types)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Executes a *query* that expects a single row
|
# Executes a *query* that expects a single row
|
||||||
# and returns the first column's value as the given *type*.
|
# and returns the first column's value as the given *type*.
|
||||||
#
|
#
|
||||||
|
@ -184,6 +217,19 @@ module DB
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Executes a *query* and returns an array where each row is
|
||||||
|
# read as a named tuple of the given *types* (the keys of the named tuple
|
||||||
|
# are not necessarily the column names).
|
||||||
|
#
|
||||||
|
# ```
|
||||||
|
# contacts = db.query_all "select name, age from contacts", as: {name: String, age: Int32}
|
||||||
|
# ```
|
||||||
|
def query_all(query, *args, as types : NamedTuple)
|
||||||
|
query_all(query, *args) do |rs|
|
||||||
|
rs.read(**types)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Executes a *query* and returns an array where the
|
# Executes a *query* and returns an array where the
|
||||||
# value of each row is read as the given *type*.
|
# value of each row is read as the given *type*.
|
||||||
#
|
#
|
||||||
|
|
|
@ -89,6 +89,11 @@ module DB
|
||||||
internal_read(*types)
|
internal_read(*types)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reads the next columns and returns a named tuple of the values.
|
||||||
|
def read(**types : Class)
|
||||||
|
internal_read(**types)
|
||||||
|
end
|
||||||
|
|
||||||
private def internal_read(*types : *T) forall T
|
private def internal_read(*types : *T) forall T
|
||||||
{% begin %}
|
{% begin %}
|
||||||
Tuple.new(
|
Tuple.new(
|
||||||
|
@ -99,6 +104,16 @@ module DB
|
||||||
{% end %}
|
{% end %}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private def internal_read(**types : **T) forall T
|
||||||
|
{% begin %}
|
||||||
|
NamedTuple.new(
|
||||||
|
{% for name, type in T %}
|
||||||
|
{{ name }}: read({{type.instance}}),
|
||||||
|
{% end %}
|
||||||
|
)
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
|
||||||
# def read_blob
|
# def read_blob
|
||||||
# yield ... io ....
|
# yield ... io ....
|
||||||
# end
|
# end
|
||||||
|
|
Loading…
Reference in New Issue