mirror of
https://github.com/discourse/discourse.git
synced 2024-11-26 05:03:39 +08:00
UserSearch refactor
Added .sql_builder to all AR models
This commit is contained in:
parent
6fb78809c2
commit
af810f38dd
|
@ -1,20 +1,19 @@
|
|||
class UserSearch
|
||||
|
||||
def self.search term, topic_id = nil
|
||||
User.find_by_sql sql(term, topic_id)
|
||||
end
|
||||
sql = User.sql_builder(
|
||||
"select id, username, name, email from users u
|
||||
/*left_join*/
|
||||
/*where*/
|
||||
/*order_by*/")
|
||||
|
||||
private
|
||||
|
||||
def self.sql term, topic_id
|
||||
sql = "select id, username, name, email from users u "
|
||||
|
||||
if topic_id
|
||||
sql << "left join (select distinct p.user_id from posts p where topic_id = :topic_id) s on
|
||||
s.user_id = u.id "
|
||||
sql.left_join "(select distinct p.user_id from posts p where topic_id = :topic_id) s on s.user_id = u.id", topic_id: topic_id
|
||||
end
|
||||
|
||||
if term.present?
|
||||
sql << "where username ilike :term_like or
|
||||
|
||||
if term.present?
|
||||
sql.where("username ilike :term_like or
|
||||
to_tsvector('simple', name) @@
|
||||
to_tsquery('simple',
|
||||
regexp_replace(
|
||||
|
@ -22,22 +21,18 @@ class UserSearch
|
|||
cast(plainto_tsquery(:term) as text)
|
||||
,'\''(?: |$)', ':*''', 'g'),
|
||||
'''', '', 'g')
|
||||
) "
|
||||
)", term: term, term_like: "#{term}%")
|
||||
|
||||
sql.order_by "case when username_lower = :term then 0 else 1 end asc"
|
||||
end
|
||||
|
||||
sql << "order by case when username_lower = :term then 0 else 1 end asc, "
|
||||
|
||||
if topic_id
|
||||
sql << " case when s.user_id is null then 0 else 1 end desc, "
|
||||
sql.order_by "case when s.user_id is null then 0 else 1 end desc"
|
||||
end
|
||||
|
||||
sql << " case when last_seen_at is null then 0 else 1 end desc, last_seen_at desc, username asc limit(20)"
|
||||
sql.order_by "case when last_seen_at is null then 0 else 1 end desc, last_seen_at desc, username asc limit(20)"
|
||||
|
||||
sanitize_sql_array(sql, topic_id: topic_id, term_like: "#{term}%", term: term)
|
||||
sql.exec
|
||||
end
|
||||
|
||||
def self.sanitize_sql_array *args
|
||||
ActiveRecord::Base.send(:sanitize_sql_array, args)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
1
config/initializers/sql_builder.rb
Normal file
1
config/initializers/sql_builder.rb
Normal file
|
@ -0,0 +1 @@
|
|||
require 'sql_builder'
|
|
@ -1,9 +1,10 @@
|
|||
class SqlBuilder
|
||||
|
||||
def initialize(template)
|
||||
def initialize(template,klass=nil)
|
||||
@args = {}
|
||||
@sql = template
|
||||
@sections = {}
|
||||
@klass = klass
|
||||
end
|
||||
|
||||
[:set, :where2,:where,:order_by,:limit,:left_join,:join,:offset].each do |k|
|
||||
|
@ -40,9 +41,17 @@ class SqlBuilder
|
|||
|
||||
sql.sub!("/*#{k}*/", joined)
|
||||
end
|
||||
|
||||
ActiveRecord::Base.exec_sql(sql,@args)
|
||||
|
||||
if @klass
|
||||
@klass.find_by_sql(ActiveRecord::Base.send(:sanitize_sql_array, [sql, @args]))
|
||||
else
|
||||
ActiveRecord::Base.exec_sql(sql,@args)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveRecord::Base
|
||||
def self.sql_builder(template)
|
||||
SqlBuilder.new(template, self)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -4,32 +4,48 @@ require_dependency 'sql_builder'
|
|||
|
||||
describe SqlBuilder do
|
||||
|
||||
before do
|
||||
@builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/")
|
||||
describe "attached" do
|
||||
before do
|
||||
@builder = Post.sql_builder("select * from posts /*where*/ /*limit*/")
|
||||
end
|
||||
|
||||
it "should find a post by id" do
|
||||
p = Fabricate(:post)
|
||||
@builder.where('id = :id and topic_id = :topic_id', id: p.id, topic_id: p.topic_id)
|
||||
p2 = @builder.exec.first
|
||||
p2.id.should == p.id
|
||||
p2.should == p
|
||||
end
|
||||
end
|
||||
|
||||
it "should allow for 1 param exec" do
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
describe "detached" do
|
||||
before do
|
||||
@builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/")
|
||||
end
|
||||
|
||||
it "should allow for a single where" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
it "should allow for 1 param exec" do
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
|
||||
it "should allow where chaining" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.where("2 = 1")
|
||||
@builder.exec(a: 1, b: 2).to_a.length.should == 0
|
||||
end
|
||||
it "should allow for a single where" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.exec(a: 1, b: 2).values[0][0].should == '1'
|
||||
end
|
||||
|
||||
it "should allow order by" do
|
||||
@builder.order_by("A desc").limit(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "2"
|
||||
end
|
||||
it "should allow offset" do
|
||||
@builder.order_by("A desc").offset(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "1"
|
||||
it "should allow where chaining" do
|
||||
@builder.where(":a = 1")
|
||||
@builder.where("2 = 1")
|
||||
@builder.exec(a: 1, b: 2).to_a.length.should == 0
|
||||
end
|
||||
|
||||
it "should allow order by" do
|
||||
@builder.order_by("A desc").limit(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "2"
|
||||
end
|
||||
it "should allow offset" do
|
||||
@builder.order_by("A desc").offset(1)
|
||||
.exec(a:1, b:2).values[0][0].should == "1"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user