On Mon, Oct 18, 2021 at 6:05 PM Sterling Brim-DeForest < s.brimdefor...@gmail.com> wrote:
> I'm running into issues using the lazy_attributes plugin with the > class_table_inheritance plugin and am hoping to get some help with it. > > The parent table has a column that I want to lazily load. If I add the > lazy_attributes plugin to the parent class I run into errors related to the > lazy loaded column being missing. When I add it to the subclass then I lose > typecasting for all columns when setting them through the subclass. > > I used postgres because sqlite is not very strict with typing and I wanted > to use the same setup for both examples. > > setup: > > DB = Sequel.connect "postgres://user:password@host:port/database_name" > > DB.create_table :employees do > primary_key :id > column :kind, :text > column :active, :boolean > column :bio, :text > end > > DB.create_table :managers do > foreign_key :id, :employees, null: false > primary_key [:id] > end > > The base case without adding lazy_attributes manually works as expected > > class Employee < Sequel::Model > plugin :class_table_inheritance, key: :kind > end > > class Manager < Employee > end > > employee = Employee.create active: 0, bio: "Superclass bio" > puts "employee's biography: #{employee.bio}" > puts "Employee 'active' was typecast -> #{employee.active}" > > manager = Manager.create active: 0, bio: "Subclass bio" > puts "manager's biography: #{manager.bio}" > puts "Manager 'active' was typecast -> #{manager.active}" > > > Adding lazy_attributes on bio to the parent class causes reading bio to > raise an error: PG::UndefinedColumn: ERROR: column employees.bio does > not exist. > > class Employee < Sequel::Model > plugin :lazy_attributes, :bio > plugin :class_table_inheritance, key: :kind > end > > class Manager < Employee > end > > employee = Employee.create active: 0, bio: "Superclass bio" > # superclass works > puts "Employee 'active' was typecast -> #{employee.active}" > puts "employee's biography: #{employee.bio}" > > manager = Manager.create active: 0, bio: "Subclass bio" > puts "Manager 'active' was typecast -> #{manager.active}" > # subclass breaks reading bio from DB > puts "manager's biography: #{manager.bio}" # <- error raised here > > > Adding it to the subclass instead means active won't be typecast on set > for instances of the subclass (it raises PG::DatatypeMismatch: ERROR: > column "active" is of type boolean but expression is of type integer) > > class Employee < Sequel::Model > plugin :class_table_inheritance, key: :kind > end > > class Manager < Employee > plugin :lazy_attributes, :bio > end > > # Typecasting works on parent > employee = Employee.create active: 0, bio: "Superclass bio" > puts "employee's biography: #{employee.bio}" > puts "Employee 'active' was typecast -> #{employee.active}" > > # Typecasting doesn't work on subclass > manager = Manager.create active: 0, bio: "Subclass bio" # <- error raised > here > puts "manager's biography: #{manager.bio}" > puts "Manager 'active' was typecast -> #{manager.active}" > > > I'm not sure if this is a bug or user error. Any help would be much > appreciated! > You cannot lazy load in the CTI subclass if you load the lazy_attributes plugin the parent class, because the CTI subclass uses a subquery. This isn't a bug, it's a result of how SQL works, in that you cannot select a column that doesn't exist in what you are selecting from, and that with the class_table_inheritance/lazy_attributes combination plugin, the subclass selects from a subquery that doesn't include the column. You should be able to work around this with the following code: class Manager < Employee old_from = dataset.opts[:from][0] set_dataset dataset.from(old_from.expression.select_append{employees[:bio]}.as(old_from.alias)) lazy_attributes :bio end This works around the issue by re-adding the lazy load column to the subquery SELECT, but still not including it in the main query SELECT. The SQL for the Manager dataset ends up being: SELECT `employees`.`id` AS 'id', `employees`.`kind` AS 'kind', `employees`.`active` AS 'active' FROM ( SELECT `employees`.`id`, `employees`.`kind`, `employees`.`active`, `employees`.`bio` FROM `employees` INNER JOIN `managers` ON (`managers`.`id` = `employees`.`id`) ) AS 'employees' Hopefully that works for you. If not, please post back. Thanks, Jeremy -- You received this message because you are subscribed to the Google Groups "sequel-talk" group. To unsubscribe from this group and stop receiving emails from it, send an email to sequel-talk+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/sequel-talk/CADGZSScOC155s5Mox85ge_%2B4xzUXeY1DYPyMq2apWuQP0ji_2w%40mail.gmail.com.