lib/yapper/db.rb in motion-yapper-0.0.1 vs lib/yapper/db.rb in motion-yapper-0.0.2

- old
+ new

@@ -31,61 +31,78 @@ def configure(&block) block.call(db) end - def execute(&block) + def execute(notifications={}, &block) + Notifications.track(notifications) + create_indexes! - exception = nil; result = nil - unless self.txn - txn_proc = proc do |_txn| - self.txn = _txn - begin - result = block.call(txn) - rescue Exception => e - self.txn.rollback - exception = e - ensure - self.txn = nil - end + result = nil + unless self.transaction + self.transaction = Transaction.new(self) + begin + result = transaction.run(&block) + ensure + self.transaction = nil end - connection.readWriteWithBlock(txn_proc) - + Notifications.trigger else - result = block.call(self.txn) + result = block.call(self.transaction.txn) end - raise exception if exception result end def purge - create_indexes!(true) + Yapper::Settings.purge + @index_creation_required = true + create_indexes! execute { |txn| txn.removeAllObjectsInAllCollections } end - def txn=(txn) - Thread.current[:yapper_txn] = txn + def transaction=(transaction) + Thread.current[:yapper_transaction] = transaction end - def txn - Thread.current[:yapper_txn] + def transaction + Thread.current[:yapper_transaction] end - def index(collection, field, type) - @indexes[collection] ||= {} - @indexes[collection][field] = { :type => type } + def index(model, args=[]) + options = args.extract_options! + + @index_creation_required = true + @indexes[model._type] ||= {} + + args.each do |field| + options = model.fields[field]; raise "#{self._type}:#{field} not defined" unless options + type = options[:type]; raise "#{self._type}:#{field} must define type as its indexed" if type.nil? + + @indexes[model._type][field] = { :type => type } + end end + def connection + Dispatch.once { @connection ||= db.newConnection } + @connection + end + + def db + Dispatch.once { @db ||= YapDatabase.alloc.initWithPath(document_path) } + @db + end + + private - def create_indexes!(force=false) - return if @indexes_created && !force + def create_indexes! + return unless @index_creation_required @@queue.sync do - return if @indexes_created && !force + return unless @index_creation_required @indexes.each do |collection, fields| setup = YapDatabaseSecondaryIndexSetup.alloc.init fields.each do |field, options| @@ -94,10 +111,12 @@ YapDatabaseSecondaryIndexTypeText when 'Integer' YapDatabaseSecondaryIndexTypeInteger when 'Time' YapDatabaseSecondaryIndexTypeInteger + when 'Boolean' + YapDatabaseSecondaryIndexTypeInteger else raise "Invalid type #{type}" end setup.addColumn(field, withType: type) @@ -109,43 +128,89 @@ field = field.to_s if _collection == collection value = case options[:type].to_s when 'Time' _attrs[field].to_i + when 'Boolean' + _attrs[field] ? 1 : 0 unless _attrs[field].nil? else _attrs[field] end value = NSNull if value.nil? _dict.setObject(value, forKey: field) end end end end - index_block = YapDatabaseSecondaryIndex.alloc.initWithSetup(setup, objectBlock: block) + unless Yapper::Settings.get("#{collection}_idx_defn") == @indexes[collection].to_canonical + Yapper::Settings.set("#{collection}_idx_defn", @indexes[collection].to_canonical) + configure do|yap| + yap.unregisterExtension("#{collection}_IDX") if yap.registeredExtension("#{collection}_IDX") + end + end + + index_block = YapDatabaseSecondaryIndex.alloc.initWithSetup(setup, objectBlock: block, version: 1) configure do |yap| yap.registerExtension(index_block, withName: "#{collection}_IDX") end end - @indexes_created = true + @index_creation_required = false end end - def connection - Dispatch.once { @connection ||= db.newConnection } - @connection + def version + Yapper::Settings.db_version || 0 end - def db - Dispatch.once { @db ||= YapDatabase.alloc.initWithPath(document_path) } - @db + def document_path + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0] + "/yapper.#{version}.db" end - def version - Yapper::Config.db_version || 0 + class Transaction + attr_accessor :txn + + def initialize(db) + @db = db + end + + def run(&block) + result = nil + txn_proc = proc do |_txn| + @txn = _txn + begin + result = block.call(@txn) + rescue Exception => e + @txn.rollback + result = e + end + end + @db.connection.readWriteWithBlock(txn_proc) + + raise result if result.is_a?(Exception) + result + end end - def document_path - NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0] + "/yapper.#{version}.db" + class Notifications + def self.track(notifications) + Thread.current[:yapper_notifications] ||= {}.with_indifferent_access + notifications.each do |namespace, instance| + Thread.current[:yapper_notifications][namespace] ||= [] + Thread.current[:yapper_notifications][namespace] << instance + end + end + + def self.trigger + notifications = Thread.current[:yapper_notifications] + Thread.current[:yapper_notifications] = nil + notifications.each { |namespace, instances| notify(namespace, instances) } + end + + private + + def self.notify(namespace, instances) + NSNotificationCenter.defaultCenter.postNotificationName("yapper:#{namespace}", object: instances , userInfo: nil) + end end end