Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@absk1317
Last active August 20, 2020 09:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save absk1317/e28fc08220f5faf61b5e922b5e25fcd2 to your computer and use it in GitHub Desktop.
Save absk1317/e28fc08220f5faf61b5e922b5e25fcd2 to your computer and use it in GitHub Desktop.
# frozen_string_literal: true
class ContactStorageWorker
include Sidekiq::Worker
sidekiq_options retry: false
attr_accessor :user_id, :contact_params
def perform(contact_params, user_id)
@user_id = user_id
@contact_params = contact_params
ActiveRecord::Base.connection.exec_query(insertion_query)
end
private
## build a bulk insert query. see https://adevelopersdiary.com/bulk-insert-data-in-a-table-through-ruby-on-rails/
def insertion_query
invalid_starts = %w[0 1 2 3 4 5] # mobile numbers start with 6, 7, 8, or 9 only.
query = contact_params.map do |contact|
number = parse_integers(contact['phone_number'])
next if number.to_s.length != 10 # mobile numbers must be of 10 digits.
next if number.to_s.starts_with?(*invalid_starts)
"('#{remove_special_chars(contact['name'])}',
'#{number}',
#{user_id})"
end.compact.join(', ')
return unless query.present? # do not proceed if no valid mobile numbers found.
# insert data in contacts
<<-QUERY
INSERT INTO contacts (name, phone_number, user_id)
VALUES #{query}
ON CONFLICT (user_id, phone_number) WHERE user_id > 0 -- uniqueness contraint.
DO NOTHING;
QUERY
end
def remove_special_chars(string_literal)
string_literal.to_s.gsub(/[^0-9 A-Za-z]/, ' ').strip
end
def parse_integers(string_literal)
string_literal.to_s.gsub(/[^0-9]/, '').chars.last(10).join
end
end
## specs
# frozen_string_literal: true
require 'rails_helper'
describe ContactStorageWorker do
let!(:user) { create(:user) }
it 'Stores the contacts, while sanitizing the values for name and number' do
Sidekiq::Testing.inline!
params = [{ name: 'a', phone_number: 923_456_789 }, ## will be rejected because length is less than 10
{ name: 'b', phone_number: 9_234_567_890 },
{ name: 'c', phone_number: 9_234_567_899 },
{ name: 'd', phone_number: 92_345_678_992 }, # ignored, because last 10 digits start with 2
{ name: 'e', phone_number: 9_234_567_893 },
{ name: 'e2', phone_number: '0234567893' }, ## will be rejected because starts with 0
{ name: 'e2', phone_number: 1_234_567_893 }, ## will be rejected because starts with 1
{ name: 'e2', phone_number: 2_234_567_893 }, ## will be rejected because starts with 2
{ name: 'e2', phone_number: 3_234_567_893 }, ## will be rejected because starts with 3
{ name: 'e2', phone_number: 4_234_567_893 }, ## will be rejected because starts with 4
{ name: 'e2', phone_number: 5_234_567_893 }, ## will be rejected because starts with 5
{ name: 'e2', phone_number: 923_456_789 }, ## will be rejected because length is less than 10
{ name: '', phone_number: 9_234_567_899 }, # will be rejected due to no name
{ name: 'g', phone_number: 92_345_678 }] ## will be rejected because length is less than 10
ContactStorageWorker.perform_async(params, user.id)
expect(user.contacts.count).to eq(3)
end
it "Doesn't do anything on number conflict" do
contacts = [{ name: 'a', phone_number: 923_456_789 }, ## will be rejected because length is less than 10
{ name: 'b', phone_number: 9_234_567_890 },
{ name: 'c', phone_number: 9_234_567_899 },
{ name: 'd', phone_number: 92_345_678_992 },
{ name: 'e', phone_number: 9_234_567_893 },
{ name: 'f', phone_number: 92_345_678 }]
user.contacts.create(contacts)
params = [{ name: 'g', phone_number: 923_456_789 }, # already as 'a'
{ name: 'h', phone_number: 9_234_567_890 }, # already as 'b'
{ name: 'i', phone_number: 9_234_567_899 }, # already as 'c'
{ name: 'k', phone_number: 9_234_567_893 }, # already as 'e'
{ name: 'l', phone_number: 92_999_678_999_292 }, # will be the new entry
{ name: 'm', phone_number: 92_345_678 }, # already as f
{ name: '_.$#!@%^&*( n ){}[', phone_number: 129_874_561_230 }] # new entry, as n, will take last 10 digits only
Sidekiq::Testing.inline!
ContactStorageWorker.perform_async(params, user.id)
# expect(user.contacts.count).to eq(6)
expect(user.contacts.pluck(:name)).to contain_exactly('a', 'b', 'c', 'd', 'e', 'f', 'l', 'n')
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment