multiwoven-integrations 0.34.19 → 0.34.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fc1a7c208f3183e532a2eb7d7e71db0a19fe1fc8c559d27036f9d6bf147eaf10
|
|
4
|
+
data.tar.gz: e5ebf0e7895beaf61fe4cfaa4d41b414e9315c0c26725c3cb4a91cb4c1cad3eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3abb6be05b20a2d7bbdbcff69a59fb29e62129286f8473552080fbcff421b12f720ce089831b4a8c218c4003b788de49982207d2dc86d7c2ee8b7cdc8764588e
|
|
7
|
+
data.tar.gz: 7c3d59f96b267950075467c07228e2ed157eabc2a5365e584ad5a7fbd2a6057a58be2f82a64ac6d760f2735a21b0f59bdba1489106ab86fad3c9977f560ff29b
|
|
@@ -6,6 +6,8 @@ module Multiwoven::Integrations::Destination
|
|
|
6
6
|
module Postgresql
|
|
7
7
|
include Multiwoven::Integrations::Core
|
|
8
8
|
class Client < DestinationConnector
|
|
9
|
+
MAX_CHUNK_SIZE = 10_000
|
|
10
|
+
|
|
9
11
|
def check_connection(connection_config)
|
|
10
12
|
connection_config = connection_config.with_indifferent_access
|
|
11
13
|
create_connection(connection_config)
|
|
@@ -50,30 +52,34 @@ module Multiwoven::Integrations::Destination
|
|
|
50
52
|
raw_table = sync_config.stream.name
|
|
51
53
|
table_name = qualify_table(connection_config[:schema], raw_table)
|
|
52
54
|
primary_key = sync_config.model.primary_key
|
|
53
|
-
log_message_array = []
|
|
54
55
|
db = create_connection(connection_config)
|
|
55
56
|
|
|
56
57
|
write_success = 0
|
|
57
58
|
write_failure = 0
|
|
59
|
+
log_message_array = []
|
|
58
60
|
|
|
59
|
-
records.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
records.each_slice(MAX_CHUNK_SIZE) do |chunk|
|
|
62
|
+
bulk_write(db, table_name, chunk, primary_key, action)
|
|
63
|
+
write_success += chunk.size
|
|
64
|
+
log_message_array << log_request_response("info", "bulk_#{action}", "#{chunk.size} rows")
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
logger.warn("POSTGRESQL:BULK_WRITE:FALLBACK chunk_size=#{chunk.size} error=#{e.message}")
|
|
67
|
+
chunk.each do |record|
|
|
68
|
+
response = bulk_write(db, table_name, [record], primary_key, action)
|
|
64
69
|
write_success += 1
|
|
65
|
-
log_message_array << log_request_response("info",
|
|
66
|
-
rescue StandardError =>
|
|
67
|
-
handle_exception(
|
|
70
|
+
log_message_array << log_request_response("info", "fallback_#{action}", response)
|
|
71
|
+
rescue StandardError => individual_error
|
|
72
|
+
handle_exception(individual_error, {
|
|
68
73
|
context: "POSTGRESQL:RECORD:WRITE:EXCEPTION",
|
|
69
74
|
type: "error",
|
|
70
75
|
sync_id: sync_config.sync_id,
|
|
71
76
|
sync_run_id: sync_config.sync_run_id
|
|
72
77
|
})
|
|
73
78
|
write_failure += 1
|
|
74
|
-
log_message_array << log_request_response("error",
|
|
79
|
+
log_message_array << log_request_response("error", "fallback_#{action}", individual_error.message)
|
|
75
80
|
end
|
|
76
81
|
end
|
|
82
|
+
|
|
77
83
|
tracking_message(write_success, write_failure, log_message_array)
|
|
78
84
|
rescue StandardError => e
|
|
79
85
|
handle_exception(e, {
|
|
@@ -82,10 +88,48 @@ module Multiwoven::Integrations::Destination
|
|
|
82
88
|
sync_id: sync_config.sync_id,
|
|
83
89
|
sync_run_id: sync_config.sync_run_id
|
|
84
90
|
})
|
|
91
|
+
ensure
|
|
92
|
+
db&.close
|
|
85
93
|
end
|
|
86
94
|
|
|
87
95
|
private
|
|
88
96
|
|
|
97
|
+
def bulk_write(db, table_name, records, primary_key, action)
|
|
98
|
+
return if records.empty?
|
|
99
|
+
|
|
100
|
+
columns = records.flat_map(&:keys).uniq
|
|
101
|
+
col_list = columns.map { |c| quote_ident(c) }.join(", ")
|
|
102
|
+
|
|
103
|
+
values_clauses = records.map do |record|
|
|
104
|
+
vals = columns.map { |col| escape_value(db, record[col]) }
|
|
105
|
+
"(#{vals.join(", ")})"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
sql = "INSERT INTO #{table_name} (#{col_list}) VALUES #{values_clauses.join(", ")}"
|
|
109
|
+
sql += build_upsert_clause(columns, primary_key) if action.to_s == "destination_update"
|
|
110
|
+
db.exec(sql)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def build_upsert_clause(columns, primary_key)
|
|
114
|
+
return "" unless primary_key.present?
|
|
115
|
+
|
|
116
|
+
update_cols = columns.reject { |c| c.to_s == primary_key.to_s }
|
|
117
|
+
return " ON CONFLICT (#{quote_ident(primary_key)}) DO NOTHING" if update_cols.empty?
|
|
118
|
+
|
|
119
|
+
set_clause = update_cols.map { |c| "#{quote_ident(c)} = EXCLUDED.#{quote_ident(c)}" }.join(", ")
|
|
120
|
+
" ON CONFLICT (#{quote_ident(primary_key)}) DO UPDATE SET #{set_clause}"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def escape_value(db, value)
|
|
124
|
+
return "NULL" if value.nil?
|
|
125
|
+
|
|
126
|
+
"'#{db.escape_string(value.to_s)}'"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def quote_ident(name)
|
|
130
|
+
PG::Connection.quote_ident(name.to_s)
|
|
131
|
+
end
|
|
132
|
+
|
|
89
133
|
def query(connection, query)
|
|
90
134
|
connection.exec(query) do |result|
|
|
91
135
|
result.map do |row|
|
|
@@ -108,7 +152,13 @@ module Multiwoven::Integrations::Destination
|
|
|
108
152
|
|
|
109
153
|
def create_streams(records)
|
|
110
154
|
group_by_table(records).map do |r|
|
|
111
|
-
Multiwoven::Integrations::Protocol::Stream.new(
|
|
155
|
+
Multiwoven::Integrations::Protocol::Stream.new(
|
|
156
|
+
name: r[:tablename],
|
|
157
|
+
action: StreamAction["fetch"],
|
|
158
|
+
json_schema: convert_to_json_schema(r[:columns]),
|
|
159
|
+
batch_support: true,
|
|
160
|
+
batch_size: MAX_CHUNK_SIZE
|
|
161
|
+
)
|
|
112
162
|
end
|
|
113
163
|
end
|
|
114
164
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multiwoven-integrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.34.
|
|
4
|
+
version: 0.34.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Subin T P
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-03-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|