Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derived Column Values #58

Closed
IbottaBaier opened this issue Apr 4, 2017 · 4 comments
Closed

Derived Column Values #58

IbottaBaier opened this issue Apr 4, 2017 · 4 comments

Comments

@IbottaBaier
Copy link

Question: is there a good way to have columns whose values are derived from other columns and to have those values be correctly populate for all interfaces? For example:

class MyRecord
  include Aws::Record

  integer_attr :pid, hash_key: true
  integer_attr :shd, derived_from: :pid { |pid| pid % 100 }

Derived from would take an array of fields and would execute the block when any referenced column is changed, passing their values to the block either separately or as a hash.

Then one would expect:

record = MyRecord.new(pid: 1234)
record.shd #=> 34

My work-around for this was along the lines of:

def pid=(value)
  set_attribute(:pid, value) # copied from Aws::Record generated method since 'super' doesn't exist.
  self.shd = pid % 100
  value
end

Which works for the simple create/save case:

MyRecord.new(pid: 1234).save!
record = MyRecord.find(pid: 1234)
record.shd #=> 34

But, as I just discovered, does not work for updates (because no instance is ever involved):

MyRecord.update(pid: 3456) # upserts a new record
record = MyRecord.find(pid: 3456)
record.shd #=> nil

Would love to see a generalized way of doing this; seems pertinent for dynamically generating GSIs and having everything play nicely...

Current work around will be (though now I need a base record class rather than module so super will actually work):

def update(opts)
  inject_default_opts!(opts)
  super(opts)
end
@awood45
Copy link
Member

awood45 commented Apr 4, 2017

I think at first pass that a derived_from option feels too specific, that writing the logic into the class would be better. Is the issue that you want better hooks?

I'll have to think on this for a bit - I see the problem you're getting at, would like to think of a way to solve in a generalized manner.

@IbottaBaier
Copy link
Author

Yes, sort of like ActiveRecord's before_commit hook.

Update poses a different problem (posting a second issue to discuss because my solution is copy pasting your code).

@IbottaBaier
Copy link
Author

IbottaBaier commented Apr 4, 2017

Though an after_commit hook would imply it only happens once a save operation actually occurs, I would really want an after_change for any attr, i.e.:

integer_attr :partition, hash_key: true
integer_attr :shard
after_change :partition do |record|
  record.shard = record.partition % 100
end
# OR without specifying the column to listen to
after_change do |record|
  record.shard = record.partition % 100
end

This is nice because I can read back values before saving:

record = MyRecord.new(partition: 123123)
record.shard #=> 23

@mullermp
Copy link
Contributor

Apologies for the late response on this. We agree that this should be behavior that you define on the class. The code samples provided will already accomplish this! Though there appears to be a minor bug in the sample. If you use @data.set_attribute(:shd, value % 100) in your pid=(value) method, it will correctly set shd even on update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants