module Groovy class Vector include Enumerable REMOVE_MISSING = true.freeze def initialize(obj, key) @obj, @key = obj, key end def size return 0 unless obj.record records.count # items.count # so we filter out removed ones end def inspect "#<#{obj.class}->#{key.capitalize} size:#{size}>" end def as_json(options = {}) Array.new.tap do |arr| each { |record| arr.push(record.as_json(options)) } end end alias_method :count, :size # we redefine first and last to avoid having to perform a full query def first if obj = records.first Model.initialize_from_record(obj) end end def last if obj = records.last Model.initialize_from_record(obj) end end def each(&block) items.each { |r| block.call(r) } end def clear set([]) end def set(new_items) check_parent! obj.record[key] = new_items end def has?(item) return false unless item.record obj.record[key].find { |r| r == item.record } end def push(item) raise "Invalid item type: #{item.class}" unless item.is_a?(Model) check_parent! raise "Already in list!" if has?(item) item.save unless item.record push_record(item.record) end def remove(item) check_parent! raise "Item not saved: #{record}" unless item.record remove_record(item.record) end alias_method :<<, :push private attr_reader :obj, :key def remove_record(rec) recs = obj.record[key].delete_if { |r| r == rec } obj.record[key] = recs end def push_record(rec) obj.record[key] = obj.record[key].concat([rec]) end def check_parent! raise "Please save parent record first" unless obj.record end def items return [] unless obj.record records.map do |r| if !exists?(r) remove_record(r) if REMOVE_MISSING nil else Model.initialize_from_record(r) end end.compact end def exists?(rec) rec.table.exist?(rec._id) end def records obj.record[key] end end end