From 92b54d5a9dbfc7b8a36b6910c5fd265e747f421b Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 13:17:20 +0200 Subject: [PATCH] feat(orm): add Prism and Orm --- lib/prism/orm/habtm_collection.rb | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lib/prism/orm/habtm_collection.rb diff --git a/lib/prism/orm/habtm_collection.rb b/lib/prism/orm/habtm_collection.rb new file mode 100644 index 0000000..61e219b --- /dev/null +++ b/lib/prism/orm/habtm_collection.rb @@ -0,0 +1,73 @@ +module Prism + module Orm + # Many-to-many collection proxy for has_and_belongs_to_many, backed by a + # plain join table (id, left_key, right_key) with no model of its own. + class HabtmCollection + include Enumerable + include CollectionSerialization + + def initialize(owner, target:, join_table:, left_key:, right_key:) + @owner = owner + @target = target + @join_table = join_table + @left_key = left_key + @right_key = right_key + end + + def to_a + ids = target_ids + ids.empty? ? [] : @target.where(id: ids).to_a + end + + def each + return enum_for(:each) unless block_given? + to_a.each { |record| yield record } + end + + def ids + target_ids + end + + def count + target_ids.size + end + + def include?(record) + target_ids.include?(record.id) + end + + def <<(record) + return self if include?(record) + store.insert(@join_table, @left_key => @owner.id, @right_key => record.id) + self + end + alias_method :push, :<< + + def delete(record) + row = join_rows.find { |r| r[@right_key] == record.id } + store.delete(@join_table, row['id']) if row + self + end + + def replace(records) + join_rows.each { |row| store.delete(@join_table, row['id']) } + records.each { |record| self << record } + self + end + + private + + def store + @owner.class.store + end + + def join_rows + store.all(@join_table).select { |row| row[@left_key] == @owner.id } + end + + def target_ids + join_rows.map { |row| row[@right_key] } + end + end + end +end