purview 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +33 -0
- data/.travis.yml +18 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +143 -0
- data/Rakefile +11 -0
- data/TODO +81 -0
- data/lib/purview/columns/base.rb +65 -0
- data/lib/purview/columns/boolean.rb +11 -0
- data/lib/purview/columns/created_timestamp.rb +11 -0
- data/lib/purview/columns/date.rb +11 -0
- data/lib/purview/columns/float.rb +11 -0
- data/lib/purview/columns/id.rb +11 -0
- data/lib/purview/columns/integer.rb +11 -0
- data/lib/purview/columns/money.rb +11 -0
- data/lib/purview/columns/string.rb +11 -0
- data/lib/purview/columns/text.rb +11 -0
- data/lib/purview/columns/time.rb +11 -0
- data/lib/purview/columns/timestamp.rb +11 -0
- data/lib/purview/columns/updated_timestamp.rb +11 -0
- data/lib/purview/columns/uuid.rb +11 -0
- data/lib/purview/columns.rb +14 -0
- data/lib/purview/connections/base.rb +55 -0
- data/lib/purview/connections/mysql.rb +39 -0
- data/lib/purview/connections/postgresql.rb +27 -0
- data/lib/purview/connections.rb +3 -0
- data/lib/purview/databases/base.rb +559 -0
- data/lib/purview/databases/mysql.rb +207 -0
- data/lib/purview/databases/postgresql.rb +210 -0
- data/lib/purview/databases.rb +3 -0
- data/lib/purview/exceptions/base.rb +5 -0
- data/lib/purview/exceptions/could_not_acquire_lock.rb +9 -0
- data/lib/purview/exceptions/lock_already_released.rb +9 -0
- data/lib/purview/exceptions/no_table.rb +9 -0
- data/lib/purview/exceptions/no_window.rb +9 -0
- data/lib/purview/exceptions/rows_outside_window.rb +18 -0
- data/lib/purview/exceptions/table.rb +13 -0
- data/lib/purview/exceptions.rb +7 -0
- data/lib/purview/loaders/base.rb +154 -0
- data/lib/purview/loaders/mysql.rb +81 -0
- data/lib/purview/loaders/postgresql.rb +81 -0
- data/lib/purview/loaders.rb +3 -0
- data/lib/purview/loggers/base.rb +99 -0
- data/lib/purview/loggers/console.rb +11 -0
- data/lib/purview/loggers.rb +2 -0
- data/lib/purview/mixins/helpers.rb +21 -0
- data/lib/purview/mixins/logger.rb +21 -0
- data/lib/purview/mixins.rb +2 -0
- data/lib/purview/parsers/base.rb +39 -0
- data/lib/purview/parsers/csv.rb +49 -0
- data/lib/purview/parsers/tsv.rb +11 -0
- data/lib/purview/parsers.rb +3 -0
- data/lib/purview/pullers/base.rb +19 -0
- data/lib/purview/pullers/uri.rb +66 -0
- data/lib/purview/pullers.rb +2 -0
- data/lib/purview/refinements/object.rb +5 -0
- data/lib/purview/refinements/time.rb +5 -0
- data/lib/purview/refinements.rb +2 -0
- data/lib/purview/structs/base.rb +10 -0
- data/lib/purview/structs/result.rb +7 -0
- data/lib/purview/structs/window.rb +7 -0
- data/lib/purview/structs.rb +3 -0
- data/lib/purview/tables/base.rb +140 -0
- data/lib/purview/tables/raw.rb +13 -0
- data/lib/purview/tables.rb +2 -0
- data/lib/purview/types/base.rb +9 -0
- data/lib/purview/types/boolean.rb +9 -0
- data/lib/purview/types/date.rb +9 -0
- data/lib/purview/types/float.rb +9 -0
- data/lib/purview/types/integer.rb +9 -0
- data/lib/purview/types/money.rb +9 -0
- data/lib/purview/types/string.rb +9 -0
- data/lib/purview/types/text.rb +9 -0
- data/lib/purview/types/time.rb +9 -0
- data/lib/purview/types/timestamp.rb +9 -0
- data/lib/purview/types/uuid.rb +9 -0
- data/lib/purview/types.rb +11 -0
- data/lib/purview/version.rb +3 -0
- data/lib/purview.rb +27 -0
- data/purview.gemspec +29 -0
- data/spec/spec_helper.rb +5 -0
- metadata +210 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
module Purview
|
2
|
+
module Connections
|
3
|
+
class PostgreSQL < Base
|
4
|
+
def with_transaction
|
5
|
+
connection.transaction { yield }
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def execute_sql(sql)
|
11
|
+
connection.exec(sql)
|
12
|
+
end
|
13
|
+
|
14
|
+
def extract_rows(result)
|
15
|
+
result && result.to_a
|
16
|
+
end
|
17
|
+
|
18
|
+
def extract_rows_affected(result)
|
19
|
+
result && result.cmd_tuples
|
20
|
+
end
|
21
|
+
|
22
|
+
def new_connection
|
23
|
+
PG.connect(opts)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,559 @@
|
|
1
|
+
module Purview
|
2
|
+
module Databases
|
3
|
+
class Base
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
def initialize(name, opts={})
|
7
|
+
@name = name
|
8
|
+
@opts = opts
|
9
|
+
@tables = Set.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_table(table)
|
13
|
+
@tables << table
|
14
|
+
end
|
15
|
+
|
16
|
+
def connect
|
17
|
+
connection.connect
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_index(connection, table, columns, opts={})
|
21
|
+
table_opts = extract_table_options(opts)
|
22
|
+
table_name = table_name(table, table_opts)
|
23
|
+
index_opts = extract_index_options(opts)
|
24
|
+
index_name(
|
25
|
+
table_name,
|
26
|
+
columns,
|
27
|
+
index_opts
|
28
|
+
).tap do |index_name|
|
29
|
+
connection.execute(
|
30
|
+
create_index_sql(
|
31
|
+
table_name,
|
32
|
+
index_name,
|
33
|
+
table,
|
34
|
+
columns,
|
35
|
+
index_opts
|
36
|
+
)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def create_table(connection, table, opts={})
|
42
|
+
table_opts = extract_table_options(opts)
|
43
|
+
table_name(table, table_opts).tap do |table_name|
|
44
|
+
connection.execute(
|
45
|
+
create_table_sql(
|
46
|
+
table_name,
|
47
|
+
table,
|
48
|
+
table_opts
|
49
|
+
)
|
50
|
+
)
|
51
|
+
if table_opts[:create_indices]
|
52
|
+
table.indexed_columns.each do |columns|
|
53
|
+
create_index(
|
54
|
+
connection,
|
55
|
+
table,
|
56
|
+
columns,
|
57
|
+
:table => { :name => table_name }
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def create_temporary_table(connection, table, opts={})
|
65
|
+
table_opts = extract_table_options(opts)
|
66
|
+
table_name(table, table_opts).tap do |table_name|
|
67
|
+
connection.execute(
|
68
|
+
create_temporary_table_sql(
|
69
|
+
table_name,
|
70
|
+
table,
|
71
|
+
table_opts
|
72
|
+
)
|
73
|
+
)
|
74
|
+
if table_opts[:create_indices]
|
75
|
+
table.indexed_columns.each do |columns|
|
76
|
+
create_index(
|
77
|
+
connection,
|
78
|
+
table,
|
79
|
+
columns,
|
80
|
+
:table => { :name => table_name }
|
81
|
+
)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def disable_table(table)
|
88
|
+
with_context_logging("`disable_table` for: #{table_name(table)}") do
|
89
|
+
with_new_connection do |connection|
|
90
|
+
set_enabled_for_table(
|
91
|
+
connection,
|
92
|
+
table,
|
93
|
+
false_value
|
94
|
+
)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def drop_table(connection, table, opts={})
|
100
|
+
table_opts = extract_table_options(opts)
|
101
|
+
table_name(table, table_opts).tap do |table_name|
|
102
|
+
connection.execute(
|
103
|
+
drop_table_sql(
|
104
|
+
table_name,
|
105
|
+
table,
|
106
|
+
table_opts
|
107
|
+
)
|
108
|
+
)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def drop_index(connection, table, columns, opts={})
|
113
|
+
table_opts = extract_table_options(opts)
|
114
|
+
table_name = table_name(table, table_opts)
|
115
|
+
index_opts = extract_index_options(opts)
|
116
|
+
index_name(
|
117
|
+
table_name,
|
118
|
+
columns,
|
119
|
+
index_opts
|
120
|
+
).tap do |index_name|
|
121
|
+
connection.execute(
|
122
|
+
drop_index_sql(
|
123
|
+
table_name,
|
124
|
+
index_name,
|
125
|
+
table,
|
126
|
+
columns,
|
127
|
+
index_opts
|
128
|
+
)
|
129
|
+
)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def enable_table(table)
|
134
|
+
with_context_logging("`enable_table` for: #{table_name(table)}") do
|
135
|
+
with_new_connection do |connection|
|
136
|
+
set_enabled_for_table(
|
137
|
+
connection,
|
138
|
+
table,
|
139
|
+
true_value
|
140
|
+
)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def false_value
|
146
|
+
raise %{All "#{Base}(s)" must override the "false_value" method}
|
147
|
+
end
|
148
|
+
|
149
|
+
def lock_table(table, timestamp)
|
150
|
+
with_context_logging("`lock_table` for: #{table_name(table)}") do
|
151
|
+
with_new_connection do |connection|
|
152
|
+
rows_affected = \
|
153
|
+
connection.execute(lock_table_sql(table, timestamp)).rows_affected
|
154
|
+
raise Purview::Exceptions::CouldNotAcquireLock.new(table) \
|
155
|
+
if zero?(rows_affected)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def null_value
|
161
|
+
raise %{All "#{Base}(s)" must override the "null_value" method}
|
162
|
+
end
|
163
|
+
|
164
|
+
def quoted(value)
|
165
|
+
value.nil? ? null_value : value.quoted
|
166
|
+
end
|
167
|
+
|
168
|
+
def sync
|
169
|
+
with_new_connection do |connection|
|
170
|
+
with_transaction(connection) do |timestamp|
|
171
|
+
with_next_table(connection, timestamp) do |table|
|
172
|
+
with_next_window(
|
173
|
+
connection,
|
174
|
+
table,
|
175
|
+
timestamp
|
176
|
+
) do |window|
|
177
|
+
with_table_locked(table, timestamp) do
|
178
|
+
table.sync(connection, window)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def true_value
|
187
|
+
raise %{All "#{Base}(s)" must override the "true_value" method}
|
188
|
+
end
|
189
|
+
|
190
|
+
def unlock_table(table)
|
191
|
+
with_context_logging("`unlock_table` for: #{table_name(table)}") do
|
192
|
+
with_new_connection do |connection|
|
193
|
+
rows_affected = \
|
194
|
+
connection.execute(unlock_table_sql(table)).rows_affected
|
195
|
+
raise Purview::Exceptions::LockAlreadyReleased.new(table) \
|
196
|
+
if zero?(rows_affected)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
include Purview::Mixins::Helpers
|
204
|
+
include Purview::Mixins::Logger
|
205
|
+
|
206
|
+
attr_reader :opts, :tables
|
207
|
+
|
208
|
+
def column_names(columns)
|
209
|
+
columns.map(&:name)
|
210
|
+
end
|
211
|
+
|
212
|
+
def column_definition(column)
|
213
|
+
column.name.to_s.tap do |column_definition|
|
214
|
+
type = type(column)
|
215
|
+
column_definition << " #{type}"
|
216
|
+
limit = limit(column)
|
217
|
+
column_definition << "(#{limit})" if limit
|
218
|
+
primary_key = primary_key?(column)
|
219
|
+
column_definition << ' PRIMARY KEY' if primary_key
|
220
|
+
nullable = nullable?(column)
|
221
|
+
column_definition << " #{nullable ? 'NULL' : 'NOT NULL'}"
|
222
|
+
default = default(column)
|
223
|
+
column_definition << " DEFAULT #{default}" if default
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def column_definitions(table)
|
228
|
+
[].tap do |results|
|
229
|
+
results << column_definition(table.id_column)
|
230
|
+
results << column_definition(table.created_timestamp_column)
|
231
|
+
results << column_definition(table.updated_timestamp_column)
|
232
|
+
table.data_columns.each do |column|
|
233
|
+
results << column_definition(column)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def connection
|
239
|
+
connection_type.new(connection_opts)
|
240
|
+
end
|
241
|
+
|
242
|
+
def connection_opts
|
243
|
+
{}
|
244
|
+
end
|
245
|
+
|
246
|
+
def connection_type
|
247
|
+
raise %{All "#{Base}(s)" must override the "connection_type" method}
|
248
|
+
end
|
249
|
+
|
250
|
+
def create_index_sql(table_name, index_name, table, columns, index_opts={})
|
251
|
+
raise %{All "#{Base}(s)" must override the "create_index_sql" method}
|
252
|
+
end
|
253
|
+
|
254
|
+
def create_table_sql(table_name, table, table_opts={})
|
255
|
+
raise %{All "#{Base}(s)" must override the "create_table_sql" method}
|
256
|
+
end
|
257
|
+
|
258
|
+
def create_temporary_table_sql(table_name, table, table_opts={})
|
259
|
+
raise %{All "#{Base}(s)" must override the "create_temporary_table_sql" method}
|
260
|
+
end
|
261
|
+
|
262
|
+
def default(column)
|
263
|
+
column.default || default_map[column.type]
|
264
|
+
end
|
265
|
+
|
266
|
+
def default_map
|
267
|
+
{}
|
268
|
+
end
|
269
|
+
|
270
|
+
def drop_index_sql(table_name, index_name, table, columns, index_opts={})
|
271
|
+
raise %{All "#{Base}(s)" must override the "drop_index_sql" method}
|
272
|
+
end
|
273
|
+
|
274
|
+
def drop_table_sql(table_name, table, table_opts={})
|
275
|
+
raise %{All "#{Base}(s)" must override the "drop_table_sql" method}
|
276
|
+
end
|
277
|
+
|
278
|
+
def ensure_table_metadata_table_exists
|
279
|
+
with_new_connection do |connection|
|
280
|
+
connection.execute(ensure_table_metadata_table_exists_sql)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def ensure_table_metadata_exists_for_table_sql(table)
|
285
|
+
raise %{All "#{Base}(s)" must override the "ensure_table_metadata_exists_for_table_sql" method}
|
286
|
+
end
|
287
|
+
|
288
|
+
def ensure_table_metadata_table_exists_sql
|
289
|
+
raise %{All "#{Base}(s)" must override the "ensure_table_metadata_table_exists_sql" method}
|
290
|
+
end
|
291
|
+
|
292
|
+
def ensure_table_metadata_exists_for_tables
|
293
|
+
with_new_connection do |connection|
|
294
|
+
tables.each do |table|
|
295
|
+
connection.execute(ensure_table_metadata_exists_for_table_sql(table))
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def extract_index_options(opts)
|
301
|
+
opts[:index] || {}
|
302
|
+
end
|
303
|
+
|
304
|
+
def extract_table_options(opts)
|
305
|
+
opts[:table] || { :create_indices => true }
|
306
|
+
end
|
307
|
+
|
308
|
+
def get_enabled_for_table(connection, table)
|
309
|
+
row = connection.execute(get_last_pulled_at_for_table_sql(table)).rows[0]
|
310
|
+
enabled = row[table_metadata_enabled_column_name]
|
311
|
+
!!(enabled =~ /\A(true|t|yes|y|1)\z/i)
|
312
|
+
end
|
313
|
+
|
314
|
+
def get_enabled_for_table_sql(table)
|
315
|
+
raise %{All "#{Base}(s)" must override the "get_enabled_for_table_sql" method}
|
316
|
+
end
|
317
|
+
|
318
|
+
def get_last_pulled_at_for_table(connection, table)
|
319
|
+
row = connection.execute(get_last_pulled_at_for_table_sql(table)).rows[0]
|
320
|
+
timestamp = row[table_metadata_last_pulled_at_column_name]
|
321
|
+
timestamp ? Time.parse(timestamp) : nil
|
322
|
+
end
|
323
|
+
|
324
|
+
def get_last_pulled_at_for_table_sql(table)
|
325
|
+
raise %{All "#{Base}(s)" must override the "get_last_pulled_at_for_table_sql" method}
|
326
|
+
end
|
327
|
+
|
328
|
+
def get_locked_at_for_table(connection, table)
|
329
|
+
row = connection.execute(get_locked_at_for_table_sql(table)).rows[0]
|
330
|
+
timestamp = row[table_metadata_locked_at_column_name]
|
331
|
+
timestamp ? Time.parse(timestamp) : nil
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_locked_at_for_table_sql(table)
|
335
|
+
raise %{All "#{Base}(s)" must override the "get_locked_at_for_table_sql" method}
|
336
|
+
end
|
337
|
+
|
338
|
+
def get_max_timestamp_pulled_for_table(connection, table)
|
339
|
+
row = connection.execute(get_max_timestamp_pulled_for_table_sql(table)).rows[0]
|
340
|
+
timestamp = row[table_metadata_max_timestamp_pulled_column_name]
|
341
|
+
timestamp ? Time.parse(timestamp) : table.starting_timestamp
|
342
|
+
end
|
343
|
+
|
344
|
+
def get_max_timestamp_pulled_for_table_sql(table)
|
345
|
+
raise %{All "#{Base}(s)" must override the "get_max_timestamp_pulled_for_table_sql" method}
|
346
|
+
end
|
347
|
+
|
348
|
+
def index_name(table_name, columns, index_opts={})
|
349
|
+
index_opts[:name] || 'index_%s_on_%s' % [
|
350
|
+
table_name,
|
351
|
+
column_names(columns).join('_and_'),
|
352
|
+
]
|
353
|
+
end
|
354
|
+
|
355
|
+
def limit(column)
|
356
|
+
return nil if limitless_types.include?(column.type)
|
357
|
+
column.limit || limit_map[column.type]
|
358
|
+
end
|
359
|
+
|
360
|
+
def limit_map
|
361
|
+
{}
|
362
|
+
end
|
363
|
+
|
364
|
+
def limitless_types
|
365
|
+
[]
|
366
|
+
end
|
367
|
+
|
368
|
+
def lock_table_sql(table, timestamp)
|
369
|
+
raise %{All "#{Base}(s)" must override the "lock_table_sql" method}
|
370
|
+
end
|
371
|
+
|
372
|
+
def next_table(connection, timestamp)
|
373
|
+
ensure_table_metadata_table_exists
|
374
|
+
ensure_table_metadata_exists_for_tables
|
375
|
+
row = connection.execute(next_table_sql(timestamp)).rows[0]
|
376
|
+
table_name = row && row[table_metadata_table_name_column_name]
|
377
|
+
table_name ? tables_by_name[table_name] : nil
|
378
|
+
end
|
379
|
+
|
380
|
+
def next_table_sql(timestamp)
|
381
|
+
raise %{All "#{Base}(s)" must override the "next_table_sql" method}
|
382
|
+
end
|
383
|
+
|
384
|
+
def next_window(connection, table, timestamp)
|
385
|
+
min = get_max_timestamp_pulled_for_table(connection, table)
|
386
|
+
max = min + table.window_size
|
387
|
+
now = timestamp
|
388
|
+
return nil if min > now
|
389
|
+
max = now if max > now
|
390
|
+
Purview::Structs::Window.new(:min => min, :max => max)
|
391
|
+
end
|
392
|
+
|
393
|
+
def nullable?(column)
|
394
|
+
column.nullable?
|
395
|
+
end
|
396
|
+
|
397
|
+
def primary_key?(column)
|
398
|
+
column.primary_key?
|
399
|
+
end
|
400
|
+
|
401
|
+
def set_enabled_for_table(connection, table, enabled)
|
402
|
+
connection.execute(set_enabled_for_table_sql(table, enabled))
|
403
|
+
end
|
404
|
+
|
405
|
+
def set_enabled_for_table_sql(table, enabled)
|
406
|
+
raise %{All "#{Base}(s)" must override the "set_enabled_for_table_sql" method}
|
407
|
+
end
|
408
|
+
|
409
|
+
def set_last_pulled_at_for_table(connection, table, timestamp)
|
410
|
+
connection.execute(set_last_pulled_at_for_table_sql(table, timestamp))
|
411
|
+
end
|
412
|
+
|
413
|
+
def set_last_pulled_at_for_table_sql(table, timestamp)
|
414
|
+
raise %{All "#{Base}(s)" must override the "set_last_pulled_at_for_table_sql" method}
|
415
|
+
end
|
416
|
+
|
417
|
+
def set_locked_at_for_table(connection, table, timestamp)
|
418
|
+
connection.execute(set_locked_at_for_table_sql(table, timestamp))
|
419
|
+
end
|
420
|
+
|
421
|
+
def set_locked_at_for_table_sql(table, timestamp)
|
422
|
+
raise %{All "#{Base}(s)" must override the "set_locked_at_for_table_sql" method}
|
423
|
+
end
|
424
|
+
|
425
|
+
def set_max_timestamp_pulled_for_table(connection, table, timestamp)
|
426
|
+
connection.execute(set_max_timestamp_pulled_for_table_sql(table, timestamp))
|
427
|
+
end
|
428
|
+
|
429
|
+
def set_max_timestamp_pulled_for_table_sql(table, timestamp)
|
430
|
+
raise %{All "#{Base}(s)" must override the "set_max_timestamp_pulled_for_table_sql" method}
|
431
|
+
end
|
432
|
+
|
433
|
+
def table_metadata_enabled_column_definition
|
434
|
+
column = Purview::Columns::Boolean.new(table_metadata_enabled_column_name)
|
435
|
+
column_definition(column)
|
436
|
+
end
|
437
|
+
|
438
|
+
def table_metadata_enabled_column_name
|
439
|
+
'enabled'
|
440
|
+
end
|
441
|
+
|
442
|
+
def table_metadata_last_pulled_at_column_definition
|
443
|
+
column = Purview::Columns::Timestamp.new(table_metadata_last_pulled_at_column_name)
|
444
|
+
column_definition(column)
|
445
|
+
end
|
446
|
+
|
447
|
+
def table_metadata_last_pulled_at_column_name
|
448
|
+
'last_pulled_at'
|
449
|
+
end
|
450
|
+
|
451
|
+
def table_metadata_locked_at_column_definition
|
452
|
+
column = Purview::Columns::Timestamp.new(table_metadata_locked_at_column_name)
|
453
|
+
column_definition(column)
|
454
|
+
end
|
455
|
+
|
456
|
+
def table_metadata_locked_at_column_name
|
457
|
+
'locked_at'
|
458
|
+
end
|
459
|
+
|
460
|
+
def table_metadata_max_timestamp_pulled_column_definition
|
461
|
+
column = Purview::Columns::Timestamp.new(table_metadata_max_timestamp_pulled_column_name)
|
462
|
+
column_definition(column)
|
463
|
+
end
|
464
|
+
|
465
|
+
def table_metadata_max_timestamp_pulled_column_name
|
466
|
+
'max_timestamp_pulled'
|
467
|
+
end
|
468
|
+
|
469
|
+
def table_metadata_table_name
|
470
|
+
'table_metadata'
|
471
|
+
end
|
472
|
+
|
473
|
+
def table_metadata_table_name_column_definition
|
474
|
+
column = Purview::Columns::String.new(table_metadata_table_name_column_name)
|
475
|
+
column_definition(column)
|
476
|
+
end
|
477
|
+
|
478
|
+
def table_metadata_table_name_column_name
|
479
|
+
'table_name'
|
480
|
+
end
|
481
|
+
|
482
|
+
def tables_by_name
|
483
|
+
{}.tap do |result|
|
484
|
+
tables.each do |table|
|
485
|
+
result[table.name] = table
|
486
|
+
end
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
def table_name(table, table_opts={})
|
491
|
+
table_opts[:name] || table.name
|
492
|
+
end
|
493
|
+
|
494
|
+
def type(column)
|
495
|
+
type_map[column.type]
|
496
|
+
end
|
497
|
+
|
498
|
+
def type_map
|
499
|
+
{
|
500
|
+
Purview::Types::Boolean => 'boolean',
|
501
|
+
Purview::Types::Date => 'date',
|
502
|
+
Purview::Types::Float => 'float',
|
503
|
+
Purview::Types::Integer => 'integer',
|
504
|
+
Purview::Types::String => 'varchar',
|
505
|
+
Purview::Types::Text => 'text',
|
506
|
+
Purview::Types::Time => 'time',
|
507
|
+
Purview::Types::Timestamp => 'timestamp',
|
508
|
+
}
|
509
|
+
end
|
510
|
+
|
511
|
+
def unlock_table_sql(table)
|
512
|
+
raise %{All "#{Base}(s)" must override the "unlock_table_sql" method}
|
513
|
+
end
|
514
|
+
|
515
|
+
def with_new_connection
|
516
|
+
yield connection = connect
|
517
|
+
ensure
|
518
|
+
connection.disconnect if connection
|
519
|
+
end
|
520
|
+
|
521
|
+
def with_next_table(connection, timestamp)
|
522
|
+
table = next_table(connection, timestamp)
|
523
|
+
raise Purview::Exceptions::NoTable.new unless table
|
524
|
+
yield table
|
525
|
+
set_last_pulled_at_for_table(
|
526
|
+
connection,
|
527
|
+
table,
|
528
|
+
timestamp
|
529
|
+
)
|
530
|
+
end
|
531
|
+
|
532
|
+
def with_next_window(connection, table, timestamp)
|
533
|
+
window = next_window(
|
534
|
+
connection,
|
535
|
+
table,
|
536
|
+
timestamp
|
537
|
+
)
|
538
|
+
raise Purview::Exceptions::NoWindow.new(table) unless window
|
539
|
+
yield window
|
540
|
+
set_max_timestamp_pulled_for_table(
|
541
|
+
connection,
|
542
|
+
table,
|
543
|
+
window.max
|
544
|
+
)
|
545
|
+
end
|
546
|
+
|
547
|
+
def with_table_locked(table, timestamp)
|
548
|
+
lock_table(table, timestamp)
|
549
|
+
yield
|
550
|
+
ensure
|
551
|
+
unlock_table(table)
|
552
|
+
end
|
553
|
+
|
554
|
+
def with_transaction(connection)
|
555
|
+
connection.with_transaction { yield Time.now.utc }
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|