DEV: remove exec_sql and replace with mini_sql

Introduce new patterns for direct sql that are safe and fast.

MiniSql is not prone to memory bloat that can happen with direct PG usage.
It also has an extremely fast materializer and very a convenient API

- DB.exec(sql, *params) => runs sql returns row count
- DB.query(sql, *params) => runs sql returns usable objects (not a hash)
- DB.query_hash(sql, *params) => runs sql returns an array of hashes
- DB.query_single(sql, *params) => runs sql and returns a flat one dimensional array
- DB.build(sql) => returns a sql builder

See more at: https://github.com/discourse/mini_sql
This commit is contained in:
Sam
2018-06-19 16:13:14 +10:00
parent cc3fc87dd7
commit 5f64fd0a21
112 changed files with 782 additions and 763 deletions

View File

@@ -48,7 +48,7 @@ Migration::ColumnDropper.drop(
},
on_drop: ->() {
STDERR.puts "Removing superflous user stats columns!"
ActiveRecord::Base.exec_sql "DROP FUNCTION IF EXISTS first_unread_topic_for(int)"
DB.exec "DROP FUNCTION IF EXISTS first_unread_topic_for(int)"
}
)

View File

@@ -10,18 +10,18 @@ uncat_id = -1 unless Numeric === uncat_id
if uncat_id == -1 || !Category.exists?(uncat_id)
puts "Seeding uncategorized category!"
result = Category.exec_sql "SELECT 1 FROM categories WHERE lower(name) = 'uncategorized'"
count = DB.exec "SELECT 1 FROM categories WHERE lower(name) = 'uncategorized'"
name = 'Uncategorized'
name << SecureRandom.hex if result.count > 0
name << SecureRandom.hex if count > 0
result = Category.exec_sql "INSERT INTO categories
result = DB.query_single "INSERT INTO categories
(name,color,slug,description,text_color, user_id, created_at, updated_at, position, name_lower)
VALUES ('#{name}', 'AB9364', 'uncategorized', '', 'FFFFFF', -1, now(), now(), 1, '#{name.downcase}' )
RETURNING id
"
category_id = result[0]["id"].to_i
category_id = result.first.to_i
Category.exec_sql "DELETE FROM site_settings where name = 'uncategorized_category_id'"
Category.exec_sql "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
DB.exec "DELETE FROM site_settings where name = 'uncategorized_category_id'"
DB.exec "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
VALUES ('uncategorized_category_id', 3, #{category_id}, now(), now())"
end

View File

@@ -31,7 +31,7 @@ BadgeGrouping.seed do |g|
end
# BUGFIX
Badge.exec_sql <<-SQL.squish
DB.exec <<-SQL.squish
UPDATE badges
SET badge_grouping_id = -1
WHERE NOT EXISTS (

View File

@@ -36,7 +36,7 @@ unless Rails.env.test?
end
# Reset topic count because we don't count the description topic
Category.exec_sql "UPDATE categories SET topic_count = 0 WHERE id = #{lounge.id}"
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{lounge.id}"
end
end
end

View File

@@ -25,7 +25,7 @@ unless Rails.env.test?
end
# Reset topic count because we don't count the description topic
Category.exec_sql "UPDATE categories SET topic_count = 0 WHERE id = #{meta.id}"
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{meta.id}"
end
end
end

View File

@@ -33,7 +33,7 @@ unless Rails.env.test?
end
# Reset topic count because we don't count the description topic
Category.exec_sql "UPDATE categories SET topic_count = 0 WHERE id = #{staff.id}"
DB.exec "UPDATE categories SET topic_count = 0 WHERE id = #{staff.id}"
end
end
end

View File

@@ -1,7 +1,7 @@
class AddStarredAtToForumThreadUser < ActiveRecord::Migration[4.2]
def up
add_column :forum_thread_users, :starred_at, :datetime
User.exec_sql 'update forum_thread_users f set starred_at = COALESCE(created_at, ?)
DB.exec 'update forum_thread_users f set starred_at = COALESCE(created_at, ?)
from
(
select f1.forum_thread_id, f1.user_id, t.created_at from forum_thread_users f1

View File

@@ -1,7 +1,7 @@
class MakePostNumberDistinct < ActiveRecord::Migration[4.2]
def up
Topic.exec_sql('update posts p
DB.exec('update posts p
set post_number = calc
from
(

View File

@@ -3,25 +3,25 @@ class AddLoungeCategory < ActiveRecord::Migration[4.2]
return if Rails.env.test?
I18n.overrides_disabled do
result = Category.exec_sql "SELECT 1 FROM site_settings where name = 'lounge_category_id'"
if result.count == 0
result = DB.exec "SELECT 1 FROM site_settings where name = 'lounge_category_id'"
if result == 0
description = I18n.t('vip_category_description')
default_name = I18n.t('vip_category_name')
name = if Category.exec_sql("SELECT 1 FROM categories where name = '#{default_name}'").count == 0
name = if DB.exec("SELECT 1 FROM categories where name = '#{default_name}'") == 0
default_name
else
"CHANGE_ME"
end
result = Category.exec_sql "INSERT INTO categories
result = DB.query_single "INSERT INTO categories
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
VALUES (:name, 'EEEEEE', '652D90', now(), now(), -1, '', :description, true, 3)
RETURNING id", name: name, description: description
category_id = result[0]["id"].to_i
category_id = result.first.to_i
Category.exec_sql "UPDATE categories SET slug = :slug
DB.exec "UPDATE categories SET slug = :slug
WHERE id = :category_id",
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id

View File

@@ -3,20 +3,20 @@ class AddMetaCategory < ActiveRecord::Migration[4.2]
return if Rails.env.test?
I18n.overrides_disabled do
result = Category.exec_sql "SELECT 1 FROM site_settings where name = 'meta_category_id'"
if result.count == 0
result = DB.exec "SELECT 1 FROM site_settings where name = 'meta_category_id'"
if result == 0
description = I18n.t('meta_category_description')
name = I18n.t('meta_category_name')
if Category.exec_sql("SELECT 1 FROM categories where name ilike :name", name: name).count == 0
result = Category.exec_sql "INSERT INTO categories
if DB.exec("SELECT 1 FROM categories where name ilike :name", name: name) == 0
result = DB.query_single "INSERT INTO categories
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
VALUES (:name, '808281', 'FFFFFF', now(), now(), -1, :slug, :description, true, 1)
RETURNING id", name: name, slug: '', description: description
category_id = result[0]["id"].to_i
category_id = result.first.to_i
Category.exec_sql "UPDATE categories SET slug=:slug WHERE id=:category_id",
DB.exec "UPDATE categories SET slug=:slug WHERE id=:category_id",
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id
execute "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)

View File

@@ -3,24 +3,24 @@ class AddStaffCategory < ActiveRecord::Migration[4.2]
return if Rails.env.test?
I18n.overrides_disabled do
result = Category.exec_sql "SELECT 1 FROM site_settings where name = 'staff_category_id'"
if result.count == 0
result = DB.exec "SELECT 1 FROM site_settings where name = 'staff_category_id'"
if result == 0
description = I18n.t('staff_category_description')
name = I18n.t('staff_category_name')
if Category.exec_sql("SELECT 1 FROM categories where name ilike :name", name: name).count == 0
if DB.exec("SELECT 1 FROM categories where name ilike :name", name: name) == 0
result = Category.exec_sql "INSERT INTO categories
result = DB.query_single "INSERT INTO categories
(name, color, text_color, created_at, updated_at, user_id, slug, description, read_restricted, position)
VALUES (:name, '283890', 'FFFFFF', now(), now(), -1, '', :description, true, 2)
RETURNING id", name: name, description: description
category_id = result[0]["id"].to_i
category_id = result.first.to_i
Category.exec_sql "UPDATE categories SET slug=:slug WHERE id=:category_id",
DB.exec "UPDATE categories SET slug=:slug WHERE id=:category_id",
slug: Slug.for(name, "#{category_id}-category"), category_id: category_id
execute "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
DB.exec "INSERT INTO site_settings(name, data_type, value, created_at, updated_at)
VALUES ('staff_category_id', 3, #{category_id.to_i}, now(), now())"
end
end

View File

@@ -1,10 +1,10 @@
class InitFixedCategoryPositionsValue < ActiveRecord::Migration[4.2]
def up
# Look at existing categories to determine if positions have been specified
result = Category.exec_sql("SELECT count(*) FROM categories WHERE position IS NOT NULL")
result = DB.query_single("SELECT count(*) FROM categories WHERE position IS NOT NULL")
# Greater than 4 because uncategorized, meta, staff, lounge all have positions by default
if result[0]['count'].to_i > 4
if result.first.to_i > 4
execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('fixed_category_positions', 5, 't', now(), now())"
end
end

View File

@@ -1,17 +1,17 @@
class GoogleOpenidDefaultHasChanged < ActiveRecord::Migration[4.2]
def up
users_count_query = User.exec_sql("SELECT count(*) FROM users")
if users_count_query[0]['count'].to_i > 1
users_count_query = DB.query_single("SELECT count(*) FROM users")
if users_count_query.first.to_i > 1
# This is an existing site.
result = User.exec_sql("SELECT count(*) FROM site_settings WHERE name = 'enable_google_logins'")
if result[0]['count'].to_i == 0
result = DB.query_single("SELECT count(*) FROM site_settings WHERE name = 'enable_google_logins'")
if result.first.to_i == 0
# The old default was true, so add a row to keep it that way.
execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('enable_google_logins', 5, 't', now(), now())"
end
# Don't enable the new Google setting on an existing site.
result = User.exec_sql("SELECT count(*) FROM site_settings WHERE name = 'enable_google_oauth2_logins'")
if result[0]['count'].to_i == 0
result = DB.query_single("SELECT count(*) FROM site_settings WHERE name = 'enable_google_oauth2_logins'")
if result.first.to_i == 0
execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('enable_google_oauth2_logins', 5, 'f', now(), now())"
end
end

View File

@@ -1,15 +1,15 @@
class DisableExternalAuthsByDefault < ActiveRecord::Migration[4.2]
def enable_setting_if_default(name)
result = User.exec_sql("SELECT count(*) count FROM site_settings WHERE name = '#{name}'")
if result[0]['count'].to_i == 0
result = DB.query_single("SELECT count(*) count FROM site_settings WHERE name = '#{name}'")
if result.first.to_i == 0
execute "INSERT INTO site_settings (name, data_type, value, created_at, updated_at) VALUES ('#{name}', 5, 't', now(), now())"
end
end
def up
users_count_query = User.exec_sql("SELECT count(*) FROM users")
if users_count_query[0]['count'].to_i > 1
users_count_query = DB.query_single("SELECT count(*) FROM users")
if users_count_query.first.to_i > 1
# existing site, so keep settings as they are
enable_setting_if_default 'enable_yahoo_logins'
enable_setting_if_default 'enable_google_oauth2_logins'

View File

@@ -1,16 +1,16 @@
class RemoveEmailInAddressSetting < ActiveRecord::Migration[4.2]
def up
uncat_id = ActiveRecord::Base.exec_sql("SELECT value FROM site_settings WHERE name = 'uncategorized_category_id'").first
cat_id_r = ActiveRecord::Base.exec_sql("SELECT value FROM site_settings WHERE name = 'email_in_category'").first
email_r = ActiveRecord::Base.exec_sql("SELECT value FROM site_settings WHERE name = 'email_in_address'").first
uncat_id = DB.query_single("SELECT value FROM site_settings WHERE name = 'uncategorized_category_id'").first
cat_id_r = DB.query_single("SELECT value FROM site_settings WHERE name = 'email_in_category'").first
email_r = DB.query_single("SELECT value FROM site_settings WHERE name = 'email_in_address'").first
if email_r
category_id = uncat_id["value"].to_i
category_id = cat_id_r["value"].to_i if cat_id_r
email = email_r["value"]
ActiveRecord::Base.exec_sql("UPDATE categories SET email_in = ? WHERE id = ?", email, category_id)
DB.exec("UPDATE categories SET email_in = ? WHERE id = ?", email, category_id)
end
ActiveRecord::Base.exec_sql("DELETE FROM site_settings WHERE name = 'email_in_category' OR name = 'email_in_address'")
DB.exec("DELETE FROM site_settings WHERE name = 'email_in_category' OR name = 'email_in_address'")
end
def down

View File

@@ -1,14 +1,14 @@
class ResolveDuplicateGroupNames < ActiveRecord::Migration[4.2]
def up
results = Group.exec_sql 'SELECT id FROM groups
results = DB.query_single 'SELECT id FROM groups
WHERE name ILIKE
(SELECT lower(name)
FROM groups
GROUP BY lower(name)
HAVING count(*) > 1);'
groups = Group.where id: results.map { |r| r['id'] }
groups = Group.where id: results
groups.group_by { |g| g.name.downcase }.each do |key, value|
value.each_with_index do |dup, index|
dup.update! name: "#{dup.name[0..18]}_#{index + 1}" if index > 0

View File

@@ -2,7 +2,7 @@ class FixCategoryLogoAndBackgroundUrls < ActiveRecord::Migration[4.2]
def up
return true if Discourse.asset_host.blank?
Category.exec_sql <<-SQL
DB.exec <<-SQL
UPDATE categories
SET logo_url = replace(logo_url, '#{Discourse.asset_host}', '')
, background_url = replace(background_url, '#{Discourse.asset_host}', '')

View File

@@ -1,7 +1,7 @@
class AddSeenAtToUserAuthToken < ActiveRecord::Migration[4.2]
def up
add_column :user_auth_tokens, :seen_at, :datetime
ActiveRecord::Base.exec_sql "UPDATE user_auth_tokens SET seen_at = :now WHERE auth_token_seen", now: Time.zone.now
DB.exec "UPDATE user_auth_tokens SET seen_at = :now WHERE auth_token_seen", now: Time.zone.now
end
def down

View File

@@ -3,7 +3,7 @@ class SplitPublicInGroups < ActiveRecord::Migration[4.2]
add_column :groups, :public_exit, :boolean, default: false, null: false
add_column :groups, :public_admission, :boolean, default: false, null: false
ActiveRecord::Base.exec_sql <<~SQL
DB.exec <<~SQL
UPDATE groups
SET public_exit = true, public_admission = true
WHERE public = true

View File

@@ -1,6 +1,6 @@
class DropRaiseReadOnlyFunction < ActiveRecord::Migration[5.1]
def up
ActiveRecord::Base.exec_sql(
DB.exec(
"DROP FUNCTION IF EXISTS raise_read_only() CASCADE;"
)
end