Skip to content
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
4 changes: 2 additions & 2 deletions integrations/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ gem "ruby-odbc", git: "https://github.com/Multiwoven/ruby-odbc.git"

gem "webmock", "~> 3.0"

gem "activesupport"
gem "activesupport", ">= 7.2.3.1"

gem "google-apis-sheets_v4"

Expand All @@ -39,7 +39,7 @@ gem "slack-ruby-client"

gem "async-websocket", "~> 0.8.0"

gem "git"
gem "git", ">= 2.0.1"

gem "hubspot-api-client", "~> 17.2.0"

Expand Down
68 changes: 53 additions & 15 deletions integrations/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ GIT
PATH
remote: .
specs:
<<<<<<< HEAD
multiwoven-integrations (0.35.0)
=======
multiwoven-integrations (0.35.2)
>>>>>>> 951017ad4 (fix(CE): added fix for duplicate primary key in case of insert (#1795))
MailchimpMarketing
activesupport
async-websocket
Expand Down Expand Up @@ -50,18 +54,21 @@ GEM
MailchimpMarketing (3.0.80)
excon (>= 0.76.0, < 1)
json (~> 2.1, >= 2.1.0)
activesupport (7.1.3.3)
activesupport (8.1.3)
base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
json
logger (>= 1.4.2)
minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
addressable (2.8.9)
public_suffix (>= 2.0.2, < 8.0)
afm (1.0.0)
ast (2.4.2)
async (2.11.0)
Expand Down Expand Up @@ -111,12 +118,21 @@ GEM
aws-sigv4 (~> 1.1)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
<<<<<<< HEAD
base64 (0.2.0)
bigdecimal (3.1.9)
builder (3.3.0)
byebug (11.1.3)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
=======
base64 (0.3.0)
bigdecimal (3.3.1)
builder (3.3.0)
byebug (11.1.3)
concurrent-ruby (1.3.6)
connection_pool (3.0.2)
>>>>>>> 951017ad4 (fix(CE): added fix for duplicate primary key in case of insert (#1795))
console (1.25.2)
fiber-annotation
fiber-local (~> 1.1)
Expand All @@ -128,9 +144,15 @@ GEM
declarative (0.0.20)
diff-lcs (1.5.1)
docile (1.4.0)
<<<<<<< HEAD
drb (2.2.1)
dry-configurable (1.1.0)
dry-core (~> 1.0, < 2)
=======
drb (2.2.3)
dry-configurable (1.3.0)
dry-core (~> 1.1)
>>>>>>> 951017ad4 (fix(CE): added fix for duplicate primary key in case of insert (#1795))
zeitwerk (~> 2.6)
dry-core (1.0.1)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -200,11 +222,11 @@ GEM
googleapis-common-protos-types (~> 1.15)
googleauth (~> 1.11)
grpc (~> 1.65)
git (2.0.0)
git (4.3.2)
activesupport (>= 5.0)
addressable (~> 2.8)
process_executer (~> 1.1)
rchardet (~> 1.8)
process_executer (~> 4.0)
rchardet (~> 1.9)
gli (2.21.1)
google-apis-bigquery_v2 (0.70.0)
google-apis-core (>= 0.15.0, < 2.a)
Expand Down Expand Up @@ -307,7 +329,7 @@ GEM
hubspot-api-client (17.2.0)
json (~> 2.1, >= 2.1.0)
typhoeus (~> 1.4.0)
i18n (1.14.5)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
inflection (1.0.0)
Expand All @@ -328,12 +350,13 @@ GEM
language_server-protocol (3.17.0.3)
logger (1.7.0)
mini_mime (1.1.5)
minitest (5.23.0)
minitest (6.0.3)
drb (~> 2.0)
prism (~> 1.5)
multi_json (1.15.0)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
multipart-post (2.4.1)
mutex_m (0.2.0)
mysql2 (0.5.6)
net-sftp (4.0.0)
net-ssh (>= 5.0.0, < 8.0.0)
Expand All @@ -359,16 +382,28 @@ GEM
ttfunk
pg (1.5.6)
pg (1.5.6-x64-mingw-ucrt)
<<<<<<< HEAD
pinecone (1.1.0)
dry-struct (~> 1.6.0)
dry-validation (~> 1.10.0)
httparty (~> 0.22.0)
process_executer (1.1.0)
public_suffix (5.0.5)
racc (1.8.0)
=======
pinecone (1.2.2)
dry-struct (~> 1.6)
dry-validation (~> 1.10)
httparty (>= 0.22.0)
prism (1.9.0)
process_executer (4.0.2)
track_open_instances (~> 0.1)
public_suffix (7.0.5)
racc (1.8.1)
>>>>>>> 951017ad4 (fix(CE): added fix for duplicate primary key in case of insert (#1795))
rainbow (3.1.1)
rake (13.2.1)
rchardet (1.8.0)
rchardet (1.10.0)
regexp_parser (2.9.2)
representable (3.2.0)
declarative (< 0.1.0)
Expand Down Expand Up @@ -417,6 +452,7 @@ GEM
ruby-rc4 (0.1.5)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
securerandom (0.4.1)
sequel (5.80.0)
bigdecimal
signet (0.19.0)
Expand All @@ -441,6 +477,7 @@ GEM
timers (4.3.5)
tiny_tds (2.1.7)
tiny_tds (2.1.7-x64-mingw-ucrt)
track_open_instances (0.1.15)
trailblazer-option (0.1.2)
ttfunk (1.8.0)
bigdecimal (~> 3.1)
Expand All @@ -450,6 +487,7 @@ GEM
concurrent-ruby (~> 1.0)
uber (0.1.0)
unicode-display_width (2.5.0)
uri (1.1.1)
weaviate-ruby (0.9.2)
faraday (>= 2.0.1, < 3.0)
graphlient (>= 0.7.0, < 0.9.0)
Expand Down Expand Up @@ -482,7 +520,7 @@ PLATFORMS

DEPENDENCIES
MailchimpMarketing
activesupport
activesupport (>= 7.2.3.1)
async-websocket (~> 0.8.0)
aws-sdk-athena
aws-sdk-bedrockruntime
Expand All @@ -499,7 +537,7 @@ DEPENDENCIES
dry-types
duckdb
faraday
git
git (>= 2.0.1)
google-apis-drive_v3 (~> 0.67.0)
google-apis-sheets_v4
google-cloud-ai_platform-v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,15 +106,19 @@ def bulk_write(db, table_name, records, primary_key, action)
end

sql = "INSERT INTO #{table_name} (#{col_list}) VALUES #{values_clauses.join(", ")}"
sql += build_upsert_clause(columns, primary_key) if action.to_s == "destination_update"
if primary_key.present?
sql += action.to_s == "destination_insert" ? build_safe_insert_clause(primary_key) : build_upsert_clause(columns, primary_key)
end
db.exec(sql)
end

def build_upsert_clause(columns, primary_key)
return "" unless primary_key.present?
def build_safe_insert_clause(primary_key)
" ON CONFLICT (#{quote_ident(primary_key)}) DO NOTHING"
end

def build_upsert_clause(columns, primary_key)
update_cols = columns.reject { |c| c.to_s == primary_key.to_s }
return " ON CONFLICT (#{quote_ident(primary_key)}) DO NOTHING" if update_cols.empty?
return build_safe_insert_clause(primary_key) if update_cols.empty?

set_clause = update_cols.map { |c| "#{quote_ident(c)} = EXCLUDED.#{quote_ident(c)}" }.join(", ")
" ON CONFLICT (#{quote_ident(primary_key)}) DO UPDATE SET #{set_clause}"
Expand Down
4 changes: 4 additions & 0 deletions integrations/lib/multiwoven/integrations/rollout.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

module Multiwoven
module Integrations
<<<<<<< HEAD
VERSION = "0.35.0"
=======
VERSION = "0.35.2"
>>>>>>> 951017ad4 (fix(CE): added fix for duplicate primary key in case of insert (#1795))

ENABLED_SOURCES = %w[
Snowflake
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require "ostruct"

RSpec.describe Multiwoven::Integrations::Destination::MicrosoftDynamics::Client do
include WebMock::API

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,30 @@
expect(tracking.success).to eql(2)
expect(tracking.failed).to eql(0)
end

it "generates ON CONFLICT DO NOTHING for destination_insert when primary key is present" do
expect(pg_connection).to receive(:exec).with(
a_string_matching(/ON CONFLICT.*DO NOTHING/)
).once.and_return(true)

tracking = subject.write(s_config, batch_records, "destination_insert").tracking
expect(tracking.success).to eql(2)
expect(tracking.failed).to eql(0)
end

it "generates plain INSERT without ON CONFLICT when primary key is absent" do
config_without_pk = sync_config.deep_merge(model: { primary_key: "" })
s_config_no_pk = Multiwoven::Integrations::Protocol::SyncConfig.from_json(config_without_pk.to_json)
s_config_no_pk.sync_run_id = "50"

expect(pg_connection).to receive(:exec).with(
satisfy { |sql| sql.include?("INSERT INTO") && !sql.include?("ON CONFLICT") }
).once.and_return(true)

tracking = subject.write(s_config_no_pk, batch_records, "destination_insert").tracking
expect(tracking.success).to eql(2)
expect(tracking.failed).to eql(0)
end
end

context "bulk upsert" do
Expand Down Expand Up @@ -371,5 +395,9 @@
it "defines a private #query method" do
expect(described_class.private_instance_methods).to include(:query)
end

it "defines a private #build_safe_insert_clause method" do
expect(described_class.private_instance_methods).to include(:build_safe_insert_clause)
end
end
end
Loading