lib/dbox/database.rb in dbox-0.5.0 vs lib/dbox/database.rb in dbox-0.5.1

- old
+ new

@@ -9,19 +9,21 @@ def self.create(remote_path, local_path) db = new(local_path) if db.bootstrapped? raise DatabaseError, "Database already initialized -- please use 'dbox pull' or 'dbox push'." end - db.bootstrap(remote_path, local_path) + db.bootstrap(remote_path) + db.migrate() db end def self.load(local_path) db = new(local_path) unless db.bootstrapped? raise DatabaseError, "Database not initialized -- please run 'dbox create' or 'dbox clone'." end + db.migrate() db end def self.exists?(local_path) File.exists?(File.join(local_path, DB_FILENAME)) @@ -31,14 +33,17 @@ new_db = create(old_db.remote_path, old_db.local_path) new_db.delete_entry_by_path("") # clear out root record new_db.migrate_entry_from_old_db_format(old_db.root) end + attr_reader :local_path + # IMPORTANT: Database.new is private. Please use Database.create # or Database.load as the entry point. private_class_method :new def initialize(local_path) + @local_path = local_path FileUtils.mkdir_p(local_path) @db = SQLite3::Database.new(File.join(local_path, DB_FILENAME)) @db.trace {|sql| log.debug sql.strip } @db.execute("PRAGMA foreign_keys = ON;") ensure_schema_exists @@ -46,11 +51,10 @@ def ensure_schema_exists @db.execute_batch(%{ CREATE TABLE IF NOT EXISTS metadata ( id integer PRIMARY KEY AUTOINCREMENT NOT NULL, - local_path varchar(255) NOT NULL, remote_path varchar(255) NOT NULL, version integer NOT NULL ); CREATE TABLE IF NOT EXISTS entries ( id integer PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -63,17 +67,26 @@ ); CREATE INDEX IF NOT EXISTS entry_parent_ids ON entries(parent_id); }) end - METADATA_COLS = [ :local_path, :remote_path, :version ] # don't need to return id + def migrate + if metadata[:version] < 2 + @db.execute_batch(%{ + ALTER TABLE metadata DROP COLUMN local_path; + UPDATE_TABLE metadata SET version = 2; + }) + end + end + + METADATA_COLS = [ :remote_path, :version ] # don't need to return id ENTRY_COLS = [ :id, :path, :is_dir, :parent_id, :hash, :modified, :revision ] - def bootstrap(remote_path, local_path) + def bootstrap(remote_path) @db.execute(%{ - INSERT INTO metadata (local_path, remote_path, version) VALUES (?, ?, ?); - }, local_path, remote_path, 1) + INSERT INTO metadata (remote_path, version) VALUES (?, ?); + }, remote_path, 2) @db.execute(%{ INSERT INTO entries (path, is_dir) VALUES (?, ?) }, "", 1) end @@ -87,11 +100,13 @@ def metadata cols = METADATA_COLS res = @db.get_first_row(%{ SELECT #{cols.join(',')} FROM metadata LIMIT 1; }) - make_fields(cols, res) if res + out = { :local_path => local_path } + out.merge!(make_fields(cols, res)) if res + out end def update_metadata(fields) set_str = fields.keys.map {|k| "#{k}=?" }.join(",") @db.execute(%{ @@ -126,11 +141,20 @@ raise(ArgumentError, "path cannot be null") unless path update_entry(["WHERE path=?", path], fields) end def delete_entry_by_path(path) - raise(ArgumentError, "path cannot be null") unless path - delete_entry("WHERE path=?", path) + delete_entry_by_entry(find_by_path(path)) + end + + def delete_entry_by_entry(entry) + raise(ArgumentError, "entry cannot be null") unless entry + + # cascade delete children, if any + contents(entry[:id]).each {|child| delete_entry_by_entry(child) } + + # delete main entry + delete_entry("WHERE id=?", entry[:id]) end def migrate_entry_from_old_db_format(entry, parent = nil) # insert entry into sqlite db add_entry(entry.path, entry.dir?, (parent ? parent[:id] : nil), entry.modified_at, entry.revision, nil)