purview 1.5.0 → 1.6.0

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
  SHA1:
3
- metadata.gz: 1e7d924c2525271d6ebf479f498241505bbac3e8
4
- data.tar.gz: 34f49f218bf0268b3801d715a73aa34a5c6847b0
3
+ metadata.gz: ba79aba1227a4d2427c31df3f0915e4ca579cc2f
4
+ data.tar.gz: 8c1bc2ce35e5f9d96dbfcc6460856fc5c9725c98
5
5
  SHA512:
6
- metadata.gz: d4f941aeccb17386c82742f3ab4259321ca6d9da026a7a6da3ae1b202125f638153b33c19b5fcededd713287073f913f221b15560a7384403241c0f740721928
7
- data.tar.gz: 8761615f2d7bfa444bf9b0f6249801a68edd96f3ed65a286c5abe9f9a6b3143004b2672fd33ab53dfeee652d565152f533c93125272779434e8f7d58f4dd0104
6
+ metadata.gz: f0f4f52d8dd55a5d59f73e7022c6007fcfaa4b2c66506cb3f73982ade552e3d9fdaa45a00987965056a20a646f78c0f3c9def2aade3820025a6bf782a0b5cab3
7
+ data.tar.gz: 43dd4c3d045d9cd242cd046768cc98d384ba8ad76706640143ebc55d581c132e774653cecdeb18a935a11ebfd1d9c98d4899372fa0618309af7a5f6a8ac9c6d5
data/.gitignore CHANGED
@@ -1,5 +1,3 @@
1
- *.gem
2
- *.rbc
3
1
  /.config
4
2
  /InstalledFiles
5
3
  /coverage/
@@ -9,7 +7,11 @@
9
7
  /test/tmp/
10
8
  /test/version_tmp/
11
9
  /tmp/
10
+
11
+ *.gem
12
+ *.rbc
12
13
  tags
14
+ tags.*
13
15
 
14
16
  ## Specific to RubyMotion:
15
17
  .dat*
data/.travis.yml CHANGED
@@ -5,14 +5,8 @@ before_install:
5
5
  - sudo apt-get install -q freetds-dev
6
6
 
7
7
  rvm:
8
- - 1.9.3
9
8
  - 2.0.0
10
- - 2.1.0
11
- - 2.1.1
12
- - 2.1.2
13
- - 2.1.3
14
- - 2.1.4
15
- - 2.1.5
16
- - 2.2.0
17
- - jruby-19mode
18
- - rbx-2
9
+ - 2.1.9
10
+ - 2.2.6
11
+ - 2.3.3
12
+ - 2.4.0
data/Gemfile CHANGED
@@ -2,13 +2,15 @@ source 'https://rubygems.org'
2
2
 
3
3
  group :development do
4
4
  if defined?(JRUBY_VERSION)
5
- gem 'jdbc-jtds', '~> 1.3'
6
- gem 'jdbc-mysql', '~> 5.1'
7
- gem 'jdbc-postgres', '~> 9.4'
5
+ gem 'jdbc-jtds', '~> 1.0'
6
+ gem 'jdbc-mysql', '~> 5.0'
7
+ gem 'jdbc-postgres', '~> 9.0'
8
+ gem 'jdbc-sqlite3', '~> 3.0'
8
9
  else
9
- gem 'mysql2', '~> 0.3'
10
- gem 'pg', '~> 0.18'
11
- gem 'tiny_tds', '~> 0.6'
10
+ gem 'mysql2', '~> 0.4'
11
+ gem 'pg', '~> 0.20'
12
+ gem 'sqlite3', '~> 1.0'
13
+ gem 'tiny_tds', '~> 1.0'
12
14
  end
13
15
  end
14
16
 
data/README.md CHANGED
@@ -21,7 +21,7 @@ Or install it yourself as:
21
21
 
22
22
  ## Usage
23
23
 
24
- Load the `MySQL` client (for `MSSQL` simple change 'mysql2' to 'tiny_tds'; for
24
+ Load the `MySQL` client (for `MSSQL` simply change 'mysql2' to 'tiny_tds'; for
25
25
  `PostgreSQL` simply change 'mysql2' to 'pg' -- when using this gem in a JRuby
26
26
  environment the 'jdbc/jtds', 'jdbc/mysql' and/or 'jdbc/postgres'library must be
27
27
  installed/available)
@@ -39,11 +39,11 @@ Define the `Column(s)` (available column-types: `Boolean`, `CreatedTimestamp`,
39
39
  `UpdatedTimestamp` & `UUID` -- the `Id`, `CreatedTimestamp` & `UpdatedTimestamp`
40
40
  columns are required for all `BaseSyncable` tables)
41
41
  ```ruby
42
- id_column = Purview::Columns::Id.new(:id),
43
- name_column = Purview::Columns::String.new(:name, :nullable => false),
44
- email_column = Purview::Columns::String.new(:email, :nullable => false, :limit => 100),
45
- created_at_column = Purview::Columns::CreatedTimestamp.new(:created_at),
46
- updated_at_column = Purview::Columns::UpdatedTimestamp.new(:updated_at),
42
+ id_column = Purview::Columns::Id.new(:id)
43
+ name_column = Purview::Columns::String.new(:name, :nullable => false)
44
+ email_column = Purview::Columns::String.new(:email, :nullable => false, :limit => 100)
45
+ created_at_column = Purview::Columns::CreatedTimestamp.new(:created_at)
46
+ updated_at_column = Purview::Columns::UpdatedTimestamp.new(:updated_at)
47
47
 
48
48
  columns = [
49
49
  id_column,
@@ -58,32 +58,24 @@ Define the `Indices` (availble index-types: `Composite` & `Simple`). By default
58
58
  `Indices` will be added for the required column-types (`CreatedTimestamp` &
59
59
  `UpdatedTimestamp`)
60
60
  ```ruby
61
- indices = [
62
- Purview::Indices::Simple.new(email_column, :unique => true),
63
- ]
61
+ indices = [Purview::Indices::Simple.new(email_column, :unique => true)]
64
62
  ```
65
63
 
66
64
  Configure the `Puller` (available puller-types: `MSSQL`, `MySQL`, `PostgreSQL` &
67
65
  `URI`)
68
66
  ```ruby
69
- puller_opts = {
70
- :type => Purview::Pullers::URI,
71
- :uri => 'http://feed.test.com/users',
72
- }
67
+ puller_opts = {:type => Purview::Pullers::URI, :uri => 'http://feed.test.com/users'}
73
68
  ```
74
69
 
75
70
  Configure the `Parser` (available parser-types: `CSV`, `SQL` & `TSV`)
76
71
  ```ruby
77
- parser_opts = {
78
- :type => Purview::Parsers::TSV,
79
- }
72
+ parser_opts = {:type => Purview::Parsers::TSV}
80
73
  ```
81
74
 
82
- Configure the `Loader` (for `PostgreSQL` simply change `MySQL` to `PostgreSQL`)
75
+ Configure the `Loader` (for a different loader type simply change `MySQL` to
76
+ `MSSQL`, `PostgreSQL` or `SQLite`)
83
77
  ```ruby
84
- loader_opts = {
85
- :type => Purview::Loaders::MySQL,
86
- }
78
+ loader_opts = {:type => Purview::Loaders::MySQL}
87
79
  ```
88
80
 
89
81
  Combine all the configuration options and instantiate the `Table`
@@ -96,10 +88,7 @@ table_opts = {
96
88
  :puller => puller_opts,
97
89
  }
98
90
 
99
- table = Purview::Tables::Raw.new(
100
- table_name,
101
- table_opts
102
- )
91
+ table = Purview::Tables::Raw.new(table_name, table_opts)
103
92
  ```
104
93
 
105
94
  Set the database-name (this can be anything, but it must exist)
@@ -107,22 +96,19 @@ Set the database-name (this can be anything, but it must exist)
107
96
  database_name = :data_warehouse_raw
108
97
  ```
109
98
 
110
- Combine all the configuration options and instantiate the `Database` (for
111
- `PostgreSQL` simply change `MySQL` to `PostgreSQL`)
99
+ Combine all the configuration options and instantiate the `Database` (for a
100
+ different database engine simply change `MySQL` to `MSSQL`, `PostgreSQL` or
101
+ `SQLite`)
112
102
  ```ruby
113
- database_opts = {
114
- :tables => [table],
115
- }
103
+ database_opts = {:tables => [table]}
116
104
 
117
- database = Purview::Databases::MySQL.new(
118
- database_name,
119
- database_opts
120
- )
105
+ database = Purview::Databases::MySQL.new(database_name, database_opts)
121
106
  ```
122
107
 
123
108
  Create the `Table` (in the DB). Recommended for testing purposes *only*. For
124
109
  production environments you will likely want an external process to manage the
125
- schema (for `PostgreSQL` simply change `Mysql2::Error` to `PG::DuplicateTable`)
110
+ schema (for `PostgreSQL` simply change `Mysql2::Error` to `PG::DuplicateTable`,
111
+ for `SQLite` simply change `Mysql2::Error` to `SQLite3::SQLException`, etc.)
126
112
  ```ruby
127
113
  begin
128
114
  database.create_table(table)
@@ -135,9 +121,11 @@ Initialize the `Table` (in the DB). This process sets the `max_timestamp_pulled`
135
121
  value in the `table_metadata` table and is used by the candidate `Table`
136
122
  selection algorithm to determine which `Table` should be synchronized next (the
137
123
  least recently synchronized `Table` will be selected). This value is also used
138
- as the high-water mark for records pulled from its source
124
+ as the high-water mark for records pulled from its source. Unless a `timestamp`
125
+ is specified, as the second argument, the high-water mark will default to
126
+ `Time.now.utc`
139
127
  ```ruby
140
- database.initialize_table(table, timestamp)
128
+ database.initialize_table(table)
141
129
  ```
142
130
 
143
131
  Baseline the `Table`. This process will quickly get the state of the `Table` as
@@ -156,6 +144,15 @@ to determine the pool of `Table(s)` available for synchronization (to remove a
156
144
  database.enable_table(table)
157
145
  ```
158
146
 
147
+ Disable the `Table` (in the DB). This process clears the `enabled_at` value in
148
+ the `table_metadata` table which will remove the table from the candidate `Table`
149
+ selection algorithm used to determine the pool of `Table(s)` available for
150
+ synchronization (to add a `Table` back into the pool, simply execute
151
+ `enable_table`)
152
+ ```ruby
153
+ database.disable_table(table)
154
+ ```
155
+
159
156
  Sync the `Table`. This process will pull data from its [remote-]source and
160
157
  reconcile the new data against the main-table (e.g. perform 'INSERT', 'UPDATE'
161
158
  and 'DELETE' operations).
data/TODO CHANGED
@@ -1,89 +1,54 @@
1
- ... CLOSED TASKS ....
2
-
3
- * Handle blank values a bit more intelligently (all blanks -> nil)
4
- * Add support for INSERTs, UPDATEs and DELETEs (of table-data)
5
- * Deal w/ NULL values
6
- * Deal w/ BOOL values
7
- * Build out MVP for PostgreSQL loader
8
- * Create temporary table from table-metadata and load all of the parsed rows
9
- into it (build create, update and delete logic atop the temporary table)
10
- * Map [object-]types to database types (in the loader?)
11
- * Add windowing to pulls (simulate w/ 2 different data-files if necessary)
12
- * Store max-timestamp pulled (NULL or previous window + window size)
13
- * Add configuration to `Table` for window-size (in the future this can scale
14
- dynamically)
15
- * Include [window] timestamps in query-string for pull[er]
16
- * Figure out an intelligent way to solve the chicken <-> egg problem for
17
- `table_metadata`
18
- * Fail fast if there are no candidate tables (`next_table`)
19
- * Ensure that the puller does not try to go into the future (`next_window`)
20
- * Add in a primitive logging facility (can be temporary)
21
- * Enhance `next_table_sql`
22
- * Lock tables (feeds) during pull, parse and load
23
- * Verify table-locking mechanism behaves as expected
24
- * Ability to drop a table
25
- * Reorder args: "table, table_name" to: "table_name, table"
26
- * Reorder args: "table, index_name, *columns" to "index_name, table, *columns"
27
- * Ability to create an index
28
- * Ability to drop an index
29
- * Indices on `created_at` and `updated_at` columns
30
- * Gracefully handle table {,un}locking in case of error
31
- * Add debugging code
32
- * Raise no-window & no-table exceptions (making them catchable upstream)
33
- * Minimize race-condition around table-locking (use where on UPDATE, raise if
34
- zero rows are updated)
35
- * Log number of delete, inserts and updates in `loader`
36
- * `load_temporary_table` should bomb if there is data outside the window
37
- * Delete from outside window where id in temporary table
38
- * Rename `data` to `rows` in `execute`
39
- * Rename `Postgres` to `PostgreSQL`
40
- * Finish PostgreSQL support (requires `pg` gem)
41
- * Finish MySQL support (requires `mysql2` gem)
42
- * Usage/configuration examples in README.md
43
- * Create SQL-puller(s)
44
- * Introduce [SQL] dialect(s)
45
- * Fix JRuby bundle/build
46
- * Fall back to logged in user if no [database-]username is provided
47
- * Create class to encapulate `table_metadata` (in order to clean up the logic
48
- in the `Database` class(es))
49
- * Rename columns during pull/parse `source_name` & `target_name` perhaps? Maybe
50
- create a new type of column?
51
-
52
- ... ONGOING TASKS ...
53
-
54
- * Add tests
55
- * Add comments where appropriate
56
- * DRY/Refactor
57
-
58
- ... OPEN TASKS ....
59
-
60
- * Add COPY `def copy(sql)` support to PostgreSQL connection
61
- * Leverage COPY support for PostgreSQL pulls
62
- * Further encapsulate `Dialect` logic (in order to DRY `Database` classes)
63
- * Add support for MSSQL
64
-
65
- * Build out change-log tables
66
- * Build out canonical, fact and aggregate tables (and related transforms)
67
- * Configurable re-pull window (do this automatically once up to current?)
68
- * Add schema management capabilities (detect schema-deltas and suggestion
69
- modifications)
70
- * Consider refactoring mutator methods to be globally available (e.g. quoted ->
71
- Quote, etc.)
72
-
73
- ... CLOSED QUESTIONS ...
74
-
75
- * Where is the best place to create the connection?
76
- * Immediately? Then it's open during the pull, etc.
77
- * Lazily? Makes for connection logic all over the place
78
- * Perhaps it can be centralized entirely into the `Database` class?
79
- * Consider using ISO-8601 timestamps in query-string (not sure on this one, it
80
- is slightly more fragile because of URL-encoding, etc.)
81
-
82
- ... OPEN QUESTIONS ...
83
-
84
- * Parallel pulls from the same "source"? Can this be done in one request?
85
-
86
- ... INTEGRATION CONSIDERATIONS ...
87
-
88
- * Deployment
89
- * Scheduling (Daemon? CRON?)
1
+ a 1450000000 1450000000 Add COPY `def copy(sql)` support to PostgreSQL connection
2
+ a 1450000000 1450000000 Leverage COPY support for PostgreSQL pulls
3
+ a 1450000000 1450000000 Build out change-log tables
4
+ a 1450000000 1450000000 Build out canonical, fact and aggregate tables (and related transforms)
5
+ a 1450000000 1450000000 Configurable re-pull window (do this automatically once up to current?)
6
+ a 1450000000 1450000000 Add schema management capabilities (detect schema-deltas and suggestion modifications)
7
+ a 1450000000 1450000000 Consider refactoring mutator methods to be globally available (e.g. quoted -> Quote, etc.)
8
+ a 1450000000 1450000000 Support parallel pulls?
9
+ a 1450000000 1450000000 Come up w/ a deployment recommendation
10
+ r 1450000000 1450000000 Add support for MSSQL
11
+ r 1450000000 1495070870 Further encapsulate `Dialect` logic (in order to DRY `Database` classes)
12
+ d 1494850714 1495046648 Finish SQLite3 raw-connections
13
+ d 1495046665 1495046689 Fix JDBC driver configuration
14
+ d 1495051831 1495070248 Code-review recent changes and merge
15
+ d 1450000000 1450000000 Handle blank values a bit more intelligently (all blanks -> nil)
16
+ d 1450000000 1450000000 Deal w/ NULL values
17
+ d 1450000000 1450000000 Deal w/ BOOL values
18
+ d 1450000000 1450000000 Build out MVP for PostgreSQL loader
19
+ d 1450000000 1450000000 Add windowing to pulls (simulate w/ 2 different data-files if necessary)
20
+ d 1450000000 1450000000 Include [window] timestamps in query-string for pull[er]
21
+ d 1450000000 1450000000 Figure out an intelligent way to solve the chicken <-> egg problem for `table_metadata`
22
+ d 1450000000 1450000000 Fail fast if there are no candidate tables (`next_table`)
23
+ d 1450000000 1450000000 Ensure that the puller does not try to go into the future (`next_window`)
24
+ d 1450000000 1450000000 Add in a primitive logging facility (can be temporary)
25
+ d 1450000000 1450000000 Enhance `next_table_sql`
26
+ d 1450000000 1450000000 Lock tables (feeds) during pull, parse and load
27
+ d 1450000000 1450000000 Verify table-locking mechanism behaves as expected
28
+ d 1450000000 1450000000 Ability to drop a table
29
+ d 1450000000 1450000000 Reorder args: "table, table_name" to: "table_name, table"
30
+ d 1450000000 1450000000 Reorder args: "table, index_name, *columns" to "index_name, table, *columns"
31
+ d 1450000000 1450000000 Ability to create an index
32
+ d 1450000000 1450000000 Ability to drop an index
33
+ d 1450000000 1450000000 Indices on `created_at` and `updated_at` columns
34
+ d 1450000000 1450000000 Gracefully handle table {,un}locking in case of error
35
+ d 1450000000 1450000000 Add debugging code
36
+ d 1450000000 1450000000 Raise no-window & no-table exceptions (making them catchable upstream)
37
+ d 1450000000 1450000000 Minimize race-condition around table-locking (use where on UPDATE, raise if zero rows are updated)
38
+ d 1450000000 1450000000 Log number of delete, inserts and updates in `loader`
39
+ d 1450000000 1450000000 `load_temporary_table` should bomb if there is data outside the window
40
+ d 1450000000 1450000000 Delete from outside window where id in temporary table
41
+ d 1450000000 1450000000 Rename `data` to `rows` in `execute`
42
+ d 1450000000 1450000000 Rename `Postgres` to `PostgreSQL`
43
+ d 1450000000 1450000000 Finish PostgreSQL support (requires `pg` gem)
44
+ d 1450000000 1450000000 Finish MySQL support (requires `mysql2` gem)
45
+ d 1450000000 1450000000 Usage/configuration examples in README.md
46
+ d 1450000000 1450000000 Create SQL-puller(s)
47
+ d 1450000000 1450000000 Introduce [SQL] dialect(s)
48
+ d 1450000000 1450000000 Fix JRuby bundle/build
49
+ d 1450000000 1450000000 Fall back to logged in user if no [database-]username is provided
50
+ d 1450000000 1450000000 Create class to encapulate `table_metadata` (in order to clean up the logic in the `Database` class(es))
51
+ d 1450000000 1450000000 Rename columns during pull/parse `source_name` & `target_name` perhaps? Maybe create a new type of column?
52
+ d 1450000000 1495070826 Add support for SQLite3
53
+ d 1494850696 1495070857 Add TODOs from $HOME\purview-TODO
54
+ d 1495070065 1495072292 Finish MSSQL built-out
@@ -1,4 +1,6 @@
1
1
  require 'purview/connections/base'
2
+
2
3
  require 'purview/connections/mssql'
3
4
  require 'purview/connections/mysql'
4
5
  require 'purview/connections/postgresql'
6
+ require 'purview/connections/sqlite'
@@ -0,0 +1,11 @@
1
+ module Purview
2
+ module Connections
3
+ class SQLite < Base
4
+ private
5
+
6
+ def raw_connection_type
7
+ Purview::RawConnections::SQLite
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,6 @@
1
1
  require 'purview/databases/base'
2
2
 
3
+ require 'purview/databases/mssql'
3
4
  require 'purview/databases/mysql'
4
5
  require 'purview/databases/postgresql'
6
+ require 'purview/databases/sqlite'
@@ -13,7 +13,7 @@ module Purview
13
13
  end
14
14
  end
15
15
 
16
- def baseline_table(table)
16
+ def baseline_table(table, timestamp=Time.now.utc)
17
17
  ensure_table_valid_for_database(table)
18
18
  raise Purview::Exceptions::CouldNotBaselineTable.new(table) \
19
19
  unless table_initialized?(table)
@@ -84,7 +84,7 @@ module Purview
84
84
  table_name
85
85
  end
86
86
 
87
- def disable_table(table)
87
+ def disable_table(table, timestamp=Time.now.utc)
88
88
  ensure_table_valid_for_database(table)
89
89
  table_name = table_name(table)
90
90
  with_context_logging("`disable_table` for: #{table_name}") do
@@ -142,7 +142,7 @@ module Purview
142
142
  table_name
143
143
  end
144
144
 
145
- def enable_table(table, timestamp=timestamp)
145
+ def enable_table(table, timestamp=Time.now.utc)
146
146
  ensure_table_valid_for_database(table)
147
147
  table_name = table_name(table)
148
148
  with_context_logging("`enable_table` for: #{table_name}") do
@@ -156,7 +156,7 @@ module Purview
156
156
  table_name
157
157
  end
158
158
 
159
- def initialize_table(table, timestamp=timestamp)
159
+ def initialize_table(table, timestamp=Time.now.utc)
160
160
  ensure_table_valid_for_database(table)
161
161
  table_name = table_name(table)
162
162
  with_context_logging("`initialize_table` for: #{table_name}") do
@@ -170,7 +170,7 @@ module Purview
170
170
  table_name
171
171
  end
172
172
 
173
- def lock_table(table, timestamp=timestamp)
173
+ def lock_table(table, timestamp=Time.now.utc)
174
174
  ensure_table_valid_for_database(table)
175
175
  table_name = table_name(table)
176
176
  with_context_logging("`lock_table` for: #{table_name}") do
@@ -194,7 +194,7 @@ module Purview
194
194
  end
195
195
  end
196
196
 
197
- def sync_table(table)
197
+ def sync_table(table, timestamp=Time.now.utc)
198
198
  ensure_table_valid_for_database(table)
199
199
  raise Purview::Exceptions::CouldNotSyncTable.new(table) \
200
200
  unless table_initialized?(table) && table_enabled?(table)
@@ -211,7 +211,7 @@ module Purview
211
211
  table_name = table_name(table)
212
212
  with_context_logging("`table_metadata` for: #{table_name}") do
213
213
  with_new_connection do |connection|
214
- Purview::Structs::TableMetadata.new(
214
+ table_metadata = Purview::Structs::TableMetadata.new(
215
215
  table_metadata_table.columns.reduce({}) do |memo, column|
216
216
  memo[column.name] = get_table_metadata_value(
217
217
  connection,
@@ -0,0 +1,180 @@
1
+ module Purview
2
+ module Databases
3
+ class MSSQL < Base
4
+ private
5
+
6
+ def connection_type
7
+ Purview::Connections::MSSQL
8
+ end
9
+
10
+ def create_index_sql(table_name, index_name, index, index_opts={})
11
+ 'CREATE%sINDEX %s ON %s (%s)' % [
12
+ index.unique? ? ' UNIQUE ' : ' ',
13
+ index_name,
14
+ table_name,
15
+ column_names(index).join(', '),
16
+ ]
17
+ end
18
+
19
+ def create_table_sql(table_name, table, table_opts={})
20
+ 'CREATE TABLE %s (%s)' % [
21
+ table_name,
22
+ column_definitions(table).join(', '),
23
+ ]
24
+ end
25
+
26
+ def create_temporary_table_sql(table_name, table, table_opts={})
27
+ 'CREATE TEMPORARY TABLE %s (%s)' % [
28
+ table_name,
29
+ column_definitions(table).join(', '),
30
+ ]
31
+ end
32
+
33
+ def dialect_type
34
+ Purview::Dialects::MSSQL
35
+ end
36
+
37
+ def disable_table_sql(table)
38
+ 'UPDATE %s SET %s = %s WHERE %s = %s AND %s IS NOT NULL' % [
39
+ table_metadata_table.name,
40
+ table_metadata_table.enabled_at_column.name,
41
+ null_value,
42
+ table_metadata_table.table_name_column.name,
43
+ quoted(table.name),
44
+ table_metadata_table.enabled_at_column.name,
45
+ ]
46
+ end
47
+
48
+ def drop_index_sql(table_name, index_name, index, index_opts={})
49
+ 'DROP INDEX %s' % [
50
+ index_name,
51
+ ]
52
+ end
53
+
54
+ def drop_table_sql(table_name, table, table_opts={})
55
+ 'DROP TABLE %s' % [
56
+ table_name,
57
+ ]
58
+ end
59
+
60
+ def enable_table_sql(table, timestamp)
61
+ 'UPDATE %s SET %s = %s WHERE %s = %s AND %s IS NULL' % [
62
+ table_metadata_table.name,
63
+ table_metadata_table.enabled_at_column.name,
64
+ quoted(timestamp),
65
+ table_metadata_table.table_name_column.name,
66
+ quoted(table.name),
67
+ table_metadata_table.enabled_at_column.name,
68
+ ]
69
+ end
70
+
71
+ def ensure_table_metadata_absent_for_table_sql(table)
72
+ 'DELETE FROM %s WHERE %s = %s' % [
73
+ table_metadata_table.name,
74
+ table_metadata_table.table_name_column.name,
75
+ quoted(table.name),
76
+ ]
77
+ end
78
+
79
+ def ensure_table_metadata_exists_for_table_sql(table)
80
+ 'INSERT INTO %s (%s) SELECT %s WHERE NOT EXISTS (SELECT 1 FROM %s WHERE %s = %s)' % [
81
+ table_metadata_table.name,
82
+ table_metadata_table.table_name_column.name,
83
+ quoted(table.name),
84
+ table_metadata_table.name,
85
+ table_metadata_table.table_name_column.name,
86
+ quoted(table.name),
87
+ ]
88
+ end
89
+
90
+ def ensure_table_metadata_table_exists_sql
91
+ 'CREATE TABLE IF NOT EXISTS %s (%s)' % [
92
+ table_metadata_table.name,
93
+ column_definitions(table_metadata_table).join(', '),
94
+ ]
95
+ end
96
+
97
+ def initialize_table_sql(table, timestamp)
98
+ 'UPDATE %s SET %s = %s WHERE %s = %s AND %s IS NULL' % [
99
+ table_metadata_table.name,
100
+ table_metadata_table.max_timestamp_pulled_column.name,
101
+ quoted(timestamp),
102
+ table_metadata_table.table_name_column.name,
103
+ quoted(table.name),
104
+ table_metadata_table.max_timestamp_pulled_column.name,
105
+ ]
106
+ end
107
+
108
+ def get_table_metadata_value_sql(table, column)
109
+ 'SELECT %s FROM %s WHERE %s = %s' % [
110
+ column.name,
111
+ table_metadata_table.name,
112
+ table_metadata_table.table_name_column.name,
113
+ quoted(table.name),
114
+ ]
115
+ end
116
+
117
+ def limit_map
118
+ super.merge(Purview::Types::String => 255)
119
+ end
120
+
121
+ def limitless_types
122
+ super + [
123
+ Purview::Types::Money,
124
+ Purview::Types::UUID,
125
+ ]
126
+ end
127
+
128
+ def lock_table_sql(table, timestamp)
129
+ 'UPDATE %s SET %s = %s WHERE %s = %s AND %s IS NULL' % [
130
+ table_metadata_table.name,
131
+ table_metadata_table.locked_at_column.name,
132
+ quoted(timestamp),
133
+ table_metadata_table.table_name_column.name,
134
+ quoted(table.name),
135
+ table_metadata_table.locked_at_column.name,
136
+ ]
137
+ end
138
+
139
+ def next_table_sql(timestamp)
140
+ 'SELECT TOP 1 %s FROM %s WHERE %s IS NOT NULL AND %s IS NOT NULL AND %s IS NULL ORDER BY (CASE WHEN %s IS NULL THEN 0 ELSE 1 END), %s' % [
141
+ table_metadata_table.table_name_column.name,
142
+ table_metadata_table.name,
143
+ table_metadata_table.enabled_at_column.name,
144
+ table_metadata_table.max_timestamp_pulled_column.name,
145
+ table_metadata_table.locked_at_column.name,
146
+ table_metadata_table.last_pulled_at_column.name,
147
+ table_metadata_table.last_pulled_at_column.name,
148
+ ]
149
+ end
150
+
151
+ def set_table_metadata_value_sql(table, column, value)
152
+ 'UPDATE %s SET %s = %s WHERE %s = %s' % [
153
+ table_metadata_table.name,
154
+ column.name,
155
+ quoted(value),
156
+ table_metadata_table.table_name_column.name,
157
+ quoted(table.name),
158
+ ]
159
+ end
160
+
161
+ def type_map
162
+ super.merge(
163
+ Purview::Types::Money => 'money',
164
+ Purview::Types::UUID => 'uniqueidentifier',
165
+ )
166
+ end
167
+
168
+ def unlock_table_sql(table)
169
+ 'UPDATE %s SET %s = %s WHERE %s = %s AND %s IS NOT NULL' % [
170
+ table_metadata_table.name,
171
+ table_metadata_table.locked_at_column.name,
172
+ null_value,
173
+ table_metadata_table.table_name_column.name,
174
+ quoted(table.name),
175
+ table_metadata_table.locked_at_column.name,
176
+ ]
177
+ end
178
+ end
179
+ end
180
+ end