Skip to content

Commit

Permalink
fixed conflict in select_builder
Browse files Browse the repository at this point in the history
  • Loading branch information
jwoertink committed Jun 19, 2018
2 parents 0b53f84 + 6dd6cf2 commit b32d59d
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 54 deletions.
6 changes: 3 additions & 3 deletions sample/benchmark/model.cr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ init = <<-SQL
end
SQL

init.split(";").each{ |sql| Clear::SQL.execute(sql) }
init.split(";").each { |sql| Clear::SQL.execute(sql) }

class BenchmarkModel
include Clear::Model
Expand All @@ -34,8 +34,8 @@ puts "Starting benchmarking, total to fetch =" +
" #{BenchmarkModel.query.count} records"
Benchmark.ips(warmup: 2, calculation: 5) do |x|
x.report("Simple load 100k") { BenchmarkModel.query.limit(100_000).to_a }
x.report("With cursor") { a = [] of BenchmarkModel; BenchmarkModel.query.limit(100_000).each_with_cursor { |x| a << x } }
x.report("With cursor") { a = [] of BenchmarkModel; BenchmarkModel.query.limit(100_000).each_with_cursor { |o| a << o } }
x.report("With attributes") { BenchmarkModel.query.limit(100_000).to_a(fetch_columns: true) }
x.report("With attributes and cursor") { a = [] of BenchmarkModel; BenchmarkModel.query.limit(100_000).each_with_cursor(fetch_columns: true) { |x| a << x } }
x.report("With attributes and cursor") { a = [] of BenchmarkModel; BenchmarkModel.query.limit(100_000).each_with_cursor(fetch_columns: true) { |h| a << h } }
x.report("SQL only") { a = [] of Hash(String, ::Clear::SQL::Any); BenchmarkModel.query.limit(100_000).fetch { |h| a << h } }
end
8 changes: 4 additions & 4 deletions shard.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ version: 1.0
shards:
admiral:
github: jwaldrip/admiral.cr
version: 1.6.1
version: 1.7.2

ameba:
github: veelenga/ameba
version: 0.6.0
version: 0.7.0

coverage:
github: anykeyh/crystal-coverage
commit: bd604cca80c84a33354525d5dc696cd8c9d4f038
commit: af5246dde152b6e42352ce6e759bb07e9bed09ed

db:
github: crystal-lang/crystal-db
Expand All @@ -26,5 +26,5 @@ shards:

pg:
github: will/crystal-pg
version: 0.14.1
version: 0.15.0

2 changes: 1 addition & 1 deletion shard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@ development_dependencies:
github: anykeyh/crystal-coverage
ameba:
github: veelenga/ameba
version: 0.6.0
version: 0.7.0

license: MIT
36 changes: 23 additions & 13 deletions spec/model/model_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module ModelSpec
column title : String

def validate
ensure_than( title, "is not empty", &.size.>(0) )
ensure_than(title, "is not empty", &.size.>(0))
end

belongs_to user : User, key_type: Int32?
Expand Down Expand Up @@ -120,7 +120,7 @@ module ModelSpec
u.update_h.should eq({"id" => 2})
u.id = 1
u.update_h.should eq({} of String => ::DB::Any) # no more change, because id is back to the same !
u.save! #Nothing should happens
u.save! # Nothing should happens
end
end

Expand All @@ -141,14 +141,14 @@ module ModelSpec
u = User.new
p = Post.new({title: "some post"})
p.user = u
p.save.should eq(false) #< Must save the user first. but user is missing is first name !
p.save.should eq(false) # < Must save the user first. but user is missing is first name !

p.user!.first_name = "I fix the issue!" #< Fix the issue
p.user!.first_name = "I fix the issue!" # < Fix the issue

p.save.should eq(true) #Should save now
p.save.should eq(true) # Should save now

u.id.should eq(1) #Should be set
p.user!.id.should eq(1) #And should be set
u.id.should eq(1) # Should be set
p.user!.id.should eq(1) # And should be set
end
end

Expand Down Expand Up @@ -186,6 +186,16 @@ module ModelSpec
end
end

it "can fetch computed column" do
temporary do
reinit
User.create({first_name: "a", last_name: "b"})

u = User.query.select({full_name: "first_name || ' ' || last_name"}).first!(fetch_columns: true)
u["full_name"].should eq "a b"
end
end

it "define constraints on has_many to build object" do
temporary do
reinit
Expand Down Expand Up @@ -234,17 +244,17 @@ module ModelSpec
temporary do
reinit

u = User.query.find_or_create({last_name: "Henry"}) do |u|
u.first_name = "Thierry"
u.save
u = User.query.find_or_create({last_name: "Henry"}) do |user|
user.first_name = "Thierry"
user.save
end

u.first_name.should eq("Thierry")
u.last_name.should eq("Henry")
u.id.should eq(1)

u = User.query.find_or_create({last_name: "Henry"}) do |u|
u.first_name = "King" #<< This should not be triggered since we found the row
u = User.query.find_or_create({last_name: "Henry"}) do |user|
user.first_name = "King" # << This should not be triggered since we found the row
end
u.first_name.should eq("Thierry")
u.last_name.should eq("Henry")
Expand All @@ -260,7 +270,7 @@ module ModelSpec

ui = UserInfo.create({registration_number: 123, user_id: u.id})

ui.user_id = nil #Remove user_id, just to see what's going on !
ui.user_id = nil # Remove user_id, just to see what's going on !
ui.save!
end
end
Expand Down
39 changes: 9 additions & 30 deletions src/clear/model/collection.cr
Original file line number Diff line number Diff line change
Expand Up @@ -159,32 +159,13 @@ module Clear::Model
end

# Use SQL `COUNT` over your query, and return this number as a Int64
def count(type : X.class = Int64, what = "*") forall X
def count(type : X.class = Int64) forall X
cr = @cached_result
return X.new(cr.size) unless cr.nil?

return X.new(cr.size) if cr

if(@offset || @limit)
what = "1" if(what == "*") # Optimization in case what is a wildcard.
X.new(Clear::SQL.select("COUNT(*)").from({query_count: self.clear_select.select(what)}).scalar(Int64))
else
X.new(self.clear_select.select("COUNT(#{what})").scalar(Int64))
end
end

# Call an custom aggregation function, like MEDIAN or other
# Note than COUNT, MIN, MAX and AVG are conveniently mapped.
def agg(field, x : X.class) forall X
self.clear_select.select(field).scalar(X)
super(type)
end

{% for x in %w(min max avg) %}
# Call the SQL aggregation function {{x.upcase}}
def {{x.id}}(field, x : X.class) forall X
agg("{{x.id.upcase}}(#{field})", X)
end
{% end %}

# Create an array from the query.
def to_a(fetch_columns = false) : Array(T)
cr = @cached_result
Expand All @@ -197,22 +178,22 @@ module Clear::Model
end

# Basically a custom way to write `OFFSET x LIMIT 1`
def [](off, fetch_columns = false ) : T
def [](off, fetch_columns = false) : T
self[off, fetch_columns]?.not_nil!
end

# Basically a custom way to write `OFFSET x LIMIT 1`
def []?(off, fetch_columns = false ) : T?
def []?(off, fetch_columns = false) : T?
self.offset(off).first(fetch_columns)
end

# Get a range of models
def []( range : Range(Int64), fetch_columns = false ) : Array(T)
def [](range : Range(Int64), fetch_columns = false) : Array(T)
self[range, fetch_columns]?.not_nil
end

# Get a range of models
def []?( range : Range(Int64), fetch_columns = false ) : Array(T)
def []?(range : Range(Int64), fetch_columns = false) : Array(T)
self.offset(range.start).limit(range.end - range.start).to_a(fetch_columns)
end

Expand Down Expand Up @@ -294,12 +275,11 @@ module Clear::Model
def last(fetch_columns = false) : T?
order_by("#{T.pkey}", "ASC") unless T.pkey.nil? || order_bys.any?

arr = order_bys.dup #Save current order by
arr = order_bys.dup # Save current order by

begin

new_order = arr.map do |x|
Clear::SQL::Query::OrderBy::Record.new(x.op, (x.dir == :asc ? :desc : :asc) )
Clear::SQL::Query::OrderBy::Record.new(x.op, (x.dir == :asc ? :desc : :asc))
end

clear_order_bys.order_by(new_order)
Expand All @@ -314,6 +294,5 @@ module Clear::Model
clear_order_bys.order_by(order_bys)
end
end

end
end
23 changes: 23 additions & 0 deletions src/clear/sql/query/aggregate.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Clear::SQL::Query::Aggregate
# Use SQL `COUNT` over your query, and return this number as a Int64
def count(type : X.class = Int64) forall X
if (@offset || @limit)
X.new(Clear::SQL.select("COUNT(*)").from({query_count: self.clear_select.select("1")}).scalar(Int64))
else
X.new(self.clear_select.select("COUNT(*)").scalar(Int64))
end
end

# Call an custom aggregation function, like MEDIAN or other
# Note than COUNT, MIN, MAX and AVG are conveniently mapped.
def agg(field, x : X.class) forall X
self.clear_select.select(field).scalar(X)
end

{% for x in %w(min max avg) %}
# Call the SQL aggregation function {{x.upcase}}
def {{x.id}}(field, x : X.class) forall X
agg("{{x.id.upcase}}(#{field})", X)
end
{% end %}
end
2 changes: 1 addition & 1 deletion src/clear/sql/query/fetch.cr
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ module Clear::SQL::Query::Fetch

we_loop = fetch_result_set(h, rs) { |x| o << x.dup }

o.each { |h| yield(h) }
o.each { |hash| yield(hash) }
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/clear/sql/query/having.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module Clear::SQL::Query::Having
sql = x.map do |k, v|
case v
when Array
"#{k} IN (#{v.map { |x| Clear::Expression[x] }.join(", ")})"
"#{k} IN (#{v.map { |it| Clear::Expression[it] }.join(", ")})"
when SelectBuilder
"#{k} IN (#{v.to_sql})"
else
Expand Down
2 changes: 1 addition & 1 deletion src/clear/sql/query/where.cr
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module Clear::SQL::Query::Where
sql = x.map do |k, v|
case v
when Array
"#{k} IN (#{v.map { |x| Clear::Expression[x] }.join(", ")})"
"#{k} IN (#{v.map { |it| Clear::Expression[it] }.join(", ")})"
when SelectBuilder
"#{k} IN (#{v.to_sql})"
else
Expand Down
1 change: 1 addition & 0 deletions src/clear/sql/select_builder.cr
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module Clear::SQL::SelectBuilder
include Query::BeforeQuery
include Query::CTE
include Query::WithPagination
include Query::Aggregate

def dup : self
self.class.new(columns: @columns.dup,
Expand Down

0 comments on commit b32d59d

Please sign in to comment.