Module: Timet::DatabaseSyncer
- Included in:
- DatabaseSyncHelper
- Defined in:
- lib/timet/database_syncer.rb
Overview
Module responsible for synchronizing local and remote databases
Constant Summary collapse
- ITEM_FIELDS =
%w[start end tag notes pomodoro updated_at created_at deleted].freeze
Class Method Summary collapse
- .extract_timestamp(item) ⇒ Object
- .format_status_message(id, item, source) ⇒ Object
- .log_local_only(id) ⇒ Object
- .report_sync_error(error) ⇒ Object
- .upload_local_database(remote_storage, bucket, local_db_path) ⇒ Object
Instance Method Summary collapse
- #add_remote_item(local_db, id, remote_item) ⇒ Object
- #get_insert_values(item) ⇒ Object
- #get_item_values(item, include_id_at_start: false) ⇒ Object
- #get_update_values(item) ⇒ Object
- #handle_database_differences(*args) ⇒ Object
- #handle_sync_error(error, *args) ⇒ Object
- #insert_item_from_hash(db, item) ⇒ Object
- #items_to_hash(items) ⇒ Object
- #log_local_wins(id, local_item) ⇒ Object
- #merge_item(*args) ⇒ Object
- #open_remote_database(remote_path) ⇒ Object
- #process_database_items(local_db, remote_db) ⇒ Object
- #process_existing_item(id, local_item, remote_item, local_db) ⇒ Object
- #remote_wins?(remote_item, remote_time, local_time) ⇒ Boolean
- #resolve_remote_wins(local_db, id, remote_item) ⇒ Object
- #sync_databases(*args) ⇒ Object
- #sync_items_by_id(local_db, local_items_by_id, remote_items_by_id) ⇒ Object
- #sync_single_item(*args) ⇒ Object
- #sync_with_remote_database(*args) ⇒ Object
- #update_item_from_hash(db, item) ⇒ Object
Class Method Details
.extract_timestamp(item) ⇒ Object
141 142 143 |
# File 'lib/timet/database_syncer.rb', line 141 def (item) item['updated_at'].to_i end |
.format_status_message(id, item, source) ⇒ Object
155 156 157 158 |
# File 'lib/timet/database_syncer.rb', line 155 def (id, item, source) deleted = item['deleted'].to_i == 1 ? ' and deleted' : '' "#{source} item #{id} is newer#{deleted} - #{source == 'Remote' ? 'updating local' : 'will be uploaded'}" end |
.log_local_only(id) ⇒ Object
89 90 91 |
# File 'lib/timet/database_syncer.rb', line 89 def log_local_only(id) puts "Local item #{id} will be uploaded" end |
.report_sync_error(error) ⇒ Object
30 31 32 33 |
# File 'lib/timet/database_syncer.rb', line 30 def report_sync_error(error) puts "Error opening remote database: #{error.message}" puts 'Uploading local database to replace corrupted remote database' end |
.upload_local_database(remote_storage, bucket, local_db_path) ⇒ Object
36 37 38 |
# File 'lib/timet/database_syncer.rb', line 36 def upload_local_database(remote_storage, bucket, local_db_path) remote_storage.upload_file(bucket, local_db_path, 'timet.db') end |
Instance Method Details
#add_remote_item(local_db, id, remote_item) ⇒ Object
94 95 96 97 |
# File 'lib/timet/database_syncer.rb', line 94 def add_remote_item(local_db, id, remote_item) puts "Adding remote item #{id} to local" insert_item_from_hash(local_db, remote_item) end |
#get_insert_values(item) ⇒ Object
161 162 163 164 165 |
# File 'lib/timet/database_syncer.rb', line 161 def get_insert_values(item) @database_fields ||= ITEM_FIELDS values = @database_fields.map { |field| item[field] } [item['id'], *values] end |
#get_item_values(item, include_id_at_start: false) ⇒ Object
172 173 174 |
# File 'lib/timet/database_syncer.rb', line 172 def get_item_values(item, include_id_at_start: false) include_id_at_start ? get_insert_values(item) : get_update_values(item) end |
#get_update_values(item) ⇒ Object
167 168 169 170 |
# File 'lib/timet/database_syncer.rb', line 167 def get_update_values(item) @database_fields ||= ITEM_FIELDS @database_fields.map { |field| item[field] } end |
#handle_database_differences(*args) ⇒ Object
8 9 10 11 12 13 14 15 16 |
# File 'lib/timet/database_syncer.rb', line 8 def handle_database_differences(*args) local_db, remote_storage, bucket, local_db_path, remote_path = args puts 'Differences detected between local and remote databases' begin sync_with_remote_database(local_db, remote_path, remote_storage, bucket, local_db_path) rescue SQLite3::Exception => e handle_sync_error(e, remote_storage: remote_storage, bucket: bucket, local_db_path: local_db_path) end end |
#handle_sync_error(error, *args) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/timet/database_syncer.rb', line 18 def handle_sync_error(error, *args) first_arg = args.first if first_arg.is_a?(Hash) = first_arg remote_storage, bucket, local_db_path = .values_at(:remote_storage, :bucket, :local_db_path) else remote_storage, bucket, local_db_path = args end report_sync_error(error) upload_local_database(remote_storage, bucket, local_db_path) end |
#insert_item_from_hash(db, item) ⇒ Object
124 125 126 127 128 129 130 131 |
# File 'lib/timet/database_syncer.rb', line 124 def insert_item_from_hash(db, item) fields = ['id', *ITEM_FIELDS].join(', ') placeholders = Array.new(ITEM_FIELDS.length + 1, '?').join(', ') db.execute_sql( "INSERT INTO items (#{fields}) VALUES (#{placeholders})", get_insert_values(item) ) end |
#items_to_hash(items) ⇒ Object
146 147 148 |
# File 'lib/timet/database_syncer.rb', line 146 def items_to_hash(items) items.to_h { |item| [item['id'], item] } end |
#log_local_wins(id, local_item) ⇒ Object
119 120 121 122 |
# File 'lib/timet/database_syncer.rb', line 119 def log_local_wins(id, local_item) puts (id, local_item, 'Local') :remote_update end |
#merge_item(*args) ⇒ Object
103 104 105 106 107 108 109 110 111 |
# File 'lib/timet/database_syncer.rb', line 103 def merge_item(*args) local_db, id, local_item, remote_item = args local_time = (local_item) remote_time = (remote_item) return resolve_remote_wins(local_db, id, remote_item) if remote_wins?(remote_item, remote_time, local_time) log_local_wins(id, local_item) end |
#open_remote_database(remote_path) ⇒ Object
49 50 51 52 53 54 |
# File 'lib/timet/database_syncer.rb', line 49 def open_remote_database(remote_path) db_remote = SQLite3::Database.new(remote_path) raise 'Failed to initialize remote database' unless db_remote db_remote end |
#process_database_items(local_db, remote_db) ⇒ Object
63 64 65 66 67 68 |
# File 'lib/timet/database_syncer.rb', line 63 def process_database_items(local_db, remote_db) remote_items = remote_db.execute('SELECT * FROM items ORDER BY updated_at DESC') local_items = local_db.execute_sql('SELECT * FROM items ORDER BY updated_at DESC') sync_items_by_id(local_db, items_to_hash(local_items), items_to_hash(remote_items)) end |
#process_existing_item(id, local_item, remote_item, local_db) ⇒ Object
99 100 101 |
# File 'lib/timet/database_syncer.rb', line 99 def process_existing_item(id, local_item, remote_item, local_db) merge_item(local_db, id, local_item, remote_item) end |
#remote_wins?(remote_item, remote_time, local_time) ⇒ Boolean
150 151 152 153 |
# File 'lib/timet/database_syncer.rb', line 150 def remote_wins?(remote_item, remote_time, local_time) time_diff = remote_time > local_time time_diff && (remote_item['deleted'].to_i == 1 || time_diff) end |
#resolve_remote_wins(local_db, id, remote_item) ⇒ Object
113 114 115 116 117 |
# File 'lib/timet/database_syncer.rb', line 113 def resolve_remote_wins(local_db, id, remote_item) puts (id, remote_item, 'Remote') update_item_from_hash(local_db, remote_item) :local_update end |
#sync_databases(*args) ⇒ Object
56 57 58 59 60 61 |
# File 'lib/timet/database_syncer.rb', line 56 def sync_databases(*args) local_db, remote_db, remote_storage, bucket, local_db_path = args process_database_items(local_db, remote_db) remote_storage.upload_file(bucket, local_db_path, 'timet.db') puts 'Database sync completed' end |
#sync_items_by_id(local_db, local_items_by_id, remote_items_by_id) ⇒ Object
70 71 72 73 |
# File 'lib/timet/database_syncer.rb', line 70 def sync_items_by_id(local_db, local_items_by_id, remote_items_by_id) all_item_ids = (remote_items_by_id.keys + local_items_by_id.keys).uniq all_item_ids.each { |id| sync_single_item(local_db, id, local_items_by_id, remote_items_by_id) } end |
#sync_single_item(*args) ⇒ Object
75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/timet/database_syncer.rb', line 75 def sync_single_item(*args) local_db, id, local_items_by_id, remote_items_by_id = args remote_item = remote_items_by_id[id] local_item = local_items_by_id[id] if !remote_item log_local_only(id) elsif !local_item add_remote_item(local_db, id, remote_item) else merge_item(local_db, id, local_item, remote_item) end end |
#sync_with_remote_database(*args) ⇒ Object
41 42 43 44 45 46 47 |
# File 'lib/timet/database_syncer.rb', line 41 def sync_with_remote_database(*args) local_db, remote_path, remote_storage, bucket, local_db_path = args db_remote = open_remote_database(remote_path) db_remote.results_as_hash = true local_db.instance_variable_get(:@db).results_as_hash = true sync_databases(local_db, db_remote, remote_storage, bucket, local_db_path) end |
#update_item_from_hash(db, item) ⇒ Object
133 134 135 136 137 138 139 |
# File 'lib/timet/database_syncer.rb', line 133 def update_item_from_hash(db, item) fields = "#{ITEM_FIELDS.join(' = ?, ')} = ?" db.execute_sql( "UPDATE items SET #{fields} WHERE id = ?", get_update_values(item) ) end |