Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignore generated/virtual columns #64

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/polo/adapters/mysql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ def on_duplicate_key_update(inserts, records)
"`#{key}` = VALUES(`#{key}`)"
end

on_dup_syntax = "ON DUPLICATE KEY UPDATE #{values_syntax.join(', ')}"
on_dup_syntax = "ON DUPLICATE KEY UPDATE #{values_syntax.join(', ')};"
insert.gsub!(/;$/, '')

"#{insert} #{on_dup_syntax}"
end
Expand All @@ -22,4 +23,4 @@ def ignore_transform(inserts, records)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/polo/adapters/postgres.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def ignore_transform(inserts, records)
id = record[:id]
table_name = record.class.arel_table.name
end
insert.gsub!(/;$/, '')
insert = insert.gsub(/VALUES \((.+)\)$/m, 'SELECT \\1')
insert << " WHERE NOT EXISTS (SELECT 1 FROM #{table_name} WHERE id=#{id});"
end
Expand Down
18 changes: 14 additions & 4 deletions lib/polo/sql_translator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,24 @@ def records

def inserts
records.map do |record|
if record.is_a?(Hash)
sql = if record.is_a?(Hash)
raw_sql_from_hash(record)
else
raw_sql_from_record(record)
end

sql.end_with?(";") ? sql : sql + ";"
end
end

def insertable_columns(record)
record.class.column_names - virtual_columns(record)
end

def virtual_columns(record)
record.class.columns_hash.select { |k, v| v.try(:virtual?) }.keys
end

private

# Internal: Generates an insert SQL statement for a given record
Expand Down Expand Up @@ -103,7 +113,7 @@ def insert_values(record)
module ActiveRecordFivePointZeroOrOne
# Based on the codepath used in Rails 5
def raw_sql_from_record(record)
values = record.send(:arel_attributes_with_values_for_create, record.class.column_names)
values = record.send(:arel_attributes_with_values_for_create, insertable_columns(record))
model = record.class
substitutes, binds = model.unscoped.substitute_values(values)

Expand All @@ -120,7 +130,7 @@ def raw_sql_from_record(record)
# their set values (for Rails >= 5.2).
module ActiveRecordFive
def raw_sql_from_record(record)
values = record.send(:attributes_with_values_for_create, record.class.column_names)
values = record.send(:attributes_with_values_for_create, insertable_columns(record))
model = record.class
substitutes_and_binds = model.send(:_substitute_values, values)

Expand Down Expand Up @@ -154,7 +164,7 @@ def raw_sql_from_record(record)
# their set values (for Rails 7.0).
module ActiveRecordSeven
def raw_sql_from_record(record)
values = record.send(:attributes_with_values, record.class.column_names)
values = record.send(:attributes_with_values, insertable_columns(record))
model = record.class
substitutes_and_binds = values.transform_keys { |name| model.arel_table[name] }

Expand Down
8 changes: 4 additions & 4 deletions spec/adapters/mysql_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

describe '#ignore_transform' do
it 'appends the IGNORE command after INSERTs' do
insert_netto = [%q{INSERT IGNORE INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]')}]
insert_netto = [%q{INSERT IGNORE INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]');}]

records = translator.records
inserts = translator.inserts
Expand All @@ -29,7 +29,7 @@
describe '#on_duplicate_key_update' do
it 'appends ON DUPLICATE KEY UPDATE with all values to the current INSERT statement' do
insert_netto = [
%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]') ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `email` = VALUES(`email`)}
%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]') ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `email` = VALUES(`email`);}
]

inserts = translator.inserts
Expand All @@ -39,7 +39,7 @@
end
it 'works for hash-values instead of ActiveRecord instances' do
insert_netto = [
%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]') ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `email` = VALUES(`email`)}
%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]') ON DUPLICATE KEY UPDATE `id` = VALUES(`id`), `name` = VALUES(`name`), `email` = VALUES(`email`);}
]

inserts = translator.inserts
Expand All @@ -48,4 +48,4 @@
expect(translated_sql).to eq(insert_netto)
end
end
end
end
34 changes: 17 additions & 17 deletions spec/polo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

it 'generates an insert query for the base object' do
exp = Polo.explore(AR::Chef, 1)
insert = %q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]')}
insert = %q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]');}
expect(exp).to include(insert)
end

it 'generates an insert query for the objects with non-standard primary keys' do
exp = Polo.explore(AR::Person, 1)
insert = %q{INSERT INTO "people" ("ssn", "name") VALUES (1, 'John Doe')}
insert = %q{INSERT INTO "people" ("ssn", "name") VALUES (1, 'John Doe');}
expect(exp).to include(insert)
end

Expand All @@ -25,8 +25,8 @@
serialized_nil = "'null'"
end

turkey_insert = %Q{INSERT INTO "recipes" ("id", "title", "num_steps", "chef_id", "metadata") VALUES (1, 'Turkey Sandwich', NULL, 1, #{serialized_nil})}
cheese_burger_insert = %Q{INSERT INTO "recipes" ("id", "title", "num_steps", "chef_id", "metadata") VALUES (2, 'Cheese Burger', NULL, 1, #{serialized_nil})}
turkey_insert = %Q{INSERT INTO "recipes" ("id", "title", "num_steps", "chef_id", "metadata") VALUES (1, 'Turkey Sandwich', NULL, 1, #{serialized_nil});}
cheese_burger_insert = %Q{INSERT INTO "recipes" ("id", "title", "num_steps", "chef_id", "metadata") VALUES (2, 'Cheese Burger', NULL, 1, #{serialized_nil});}

inserts = Polo.explore(AR::Chef, 1, [:recipes])

Expand All @@ -35,10 +35,10 @@
end

it 'generates queries for nested dependencies' do
patty = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (3, 'Patty', '1')}
turkey = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (1, 'Turkey', 'a lot')}
one_cheese = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (2, 'Cheese', '1 slice')}
two_cheeses = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (4, 'Cheese', '2 slices')}
patty = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (3, 'Patty', '1');}
turkey = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (1, 'Turkey', 'a lot');}
one_cheese = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (2, 'Cheese', '1 slice');}
two_cheeses = %q{INSERT INTO "ingredients" ("id", "name", "quantity") VALUES (4, 'Cheese', '2 slices');}

inserts = Polo.explore(AR::Chef, 1, :recipes => :ingredients)

Expand All @@ -52,8 +52,8 @@
ar_version = ActiveRecord::VERSION::STRING
skip("Not supported on ActiveRecord #{ar_version}") if ar_version < "4.1.0"
habtm_inserts = [
%q{INSERT INTO "recipes_tags" ("recipe_id", "tag_id") VALUES (2, 2)},
%q{INSERT INTO "tags" ("id", "name") VALUES (2, 'burgers')}
%q{INSERT INTO "recipes_tags" ("recipe_id", "tag_id") VALUES (2, 2);},
%q{INSERT INTO "tags" ("id", "name") VALUES (2, 'burgers');}
]

inserts = Polo.explore(AR::Chef, 1, :recipes => :tags)
Expand All @@ -65,10 +65,10 @@

it 'generates inserts for many to many relationships' do
many_to_many_inserts = [
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (1, 1, 1)},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (2, 1, 2)},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (3, 2, 3)},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (4, 2, 4)},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (1, 1, 1);},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (2, 1, 2);},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (3, 2, 3);},
%q{INSERT INTO "recipes_ingredients" ("id", "recipe_id", "ingredient_id") VALUES (4, 2, 4);},
]

inserts = Polo.explore(AR::Chef, 1, :recipes => :ingredients)
Expand All @@ -87,7 +87,7 @@
end

exp = Polo.explore(AR::Chef, 1)
insert = /INSERT INTO "chefs" \("id", "name", "email"\) VALUES \(1, 'Netto', (.+)\)/
insert = /INSERT INTO "chefs" \("id", "name", "email"\) VALUES \(1, 'Netto', (.+)\);/
scrambled_email = insert.match(exp.first)[1]

expect(scrambled_email).to_not eq('[email protected]')
Expand All @@ -101,7 +101,7 @@

inserts = Polo.explore(AR::Chef, 1)

expect(inserts).to eq [ %q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', 'changeme')} ]
expect(inserts).to eq [ %q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', 'changeme');} ]
end

it 'only scrambles instances with the obfuscate field defined' do
Expand Down Expand Up @@ -137,7 +137,7 @@
end

exp = Polo.explore(AR::Chef, 1)
insert = /INSERT IGNORE INTO "chefs" \("id", "name", "email"\) VALUES \(1, 'Netto', (.+)\)/
insert = /INSERT IGNORE INTO "chefs" \("id", "name", "email"\) VALUES \(1, 'Netto', (.+)\);/
expect(insert).to match(exp.first)
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/sql_translator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
end

it 'translates records to inserts' do
insert_netto = [%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]')}]
insert_netto = [%q{INSERT INTO "chefs" ("id", "name", "email") VALUES (1, 'Netto', '[email protected]');}]
netto_to_sql = Polo::SqlTranslator.new(netto).to_sql
expect(netto_to_sql).to eq(insert_netto)
end
Expand Down