-
Notifications
You must be signed in to change notification settings - Fork 64
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
[WIP] Operation Refactor Sandbox #369
Conversation
…o be easier to find, and understand. A few specs are passing, but still need to port over SaveOperation to the new structure
… callbacks to take a block form.
…rting to pass now. needs now works on operation
…ze_of overload to account for integers
…s are still passing.
…ystal currently borks with Invalid Memory access error.
…ating duplicate modules. This also makes it easier to see at a glance what is being used soley for operations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't gotten the chance to look through it all yet but I hope this is a useful thought
src/avram/callbacks.cr
Outdated
def after_save(_record : T) forall T | ||
end | ||
|
||
def after_commit(_record : T) forall T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see this module is included in Avram::Operation
and I'm thinking that these callbacks don't make sense outside of database operations. Could this module be refactored to allow declaring life cycle events that be subscribed to? Then, Avram::Operation
could declare before and after run events and Avram::SaveOperation
could declare the others. Something like:
module Avram::Callbacks
macro register_life_cycle_event(event_name, *args)
macro {{ event_name.id }}(method_name)
def {{ event_name.id }}(
{% for param in args %}
{{ param.id }},
{% end %}
)
\{% if @type.methods.map(&.name).includes?(:before_run.id) %}
previous_def
\{% else %}
super
\{% end %}
\{{ method_name.id }}
end
end
end
end
And then in the operations:
abstract class Avram::Operation
include Avram::Callbacks
register_life_cycle_event :before_run
register_life_cycle_event :after_run, object
end
abstract class Avram::SaveOperation(T) < Avram::Operation
register_life_cycle_event :before_save
register_life_cycle_event :after_save, record : T
register_life_cycle_event :after_commit, record : T
end
I have no idea if this actually works but this allows Avram::Callbacks
to be a generic utility and not add methods to Avram::Operation
that shouldn't be there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a repo with a somewhat working example of my thoughts https://github.com/matthewmcgarvey/crystal-callbacks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the idea of subscribing to events. Right now there's quite a bit of duplication which I hope to cleanup before this PR is fully done. The one thing I'm unclear on is how we would differentiate between when a method would be called before certain things, or after. Like, this would not stop someone from writing register_life_cycle_event :around_save
, but how would that work? I'll have to think on this more after I start to clean up some of the duplication. That might give me a little more clarity. Thanks for the suggestions!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jwoertink that repo linked above has been updated to work (kind of) as you are wanting. Base classes will call register_event :run
and then there will be macro methods for before_run
, after_run
, and around_run
. The macros got quite hairy 🙈
I referenced Rails' callback system for this https://api.rubyonrails.org/classes/ActiveSupport/Callbacks.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet! I'll take a look. Now that I have all these specs passing, I need to start looking at cleaning up some of my duplication and adding in the new bits for this. It's about to get pretty crazy! 😂
… avoid methods like initialize being defined on Operation that shouldn't be defined on SaveOperation. SaveOperations now have attributes with passing specs
…me callbacks. May integrate them again if I figure out a cleaner way to register which callbacks an operation gets
* Separating SaveOperation from Operation. This is part of a series of commits related to #369 * Added missing specs for Operation attributes to ensure Operation can use both attribute and file_attribute * Update src/avram/needy_initializer.cr Co-authored-by: Matthew McGarvey <matthewmcgarvey14@gmail.com> * added some docs and updated Operation to ensure the FailedOperation is called * Refactor callbacks to remove some of the duplication. * Refactor run method to clean up some duplication. Also having the run bang method return the value instead of the operation to be consistent with SaveOperation bang methods * ran ameba Co-authored-by: Matthew McGarvey <matthewmcgarvey14@gmail.com>
Will there need to be updates to the guides on the main website? |
@wontruefree yup luckyframework/website#444 got the issue already. I'm still making some changes to the operations, so even though I'm merging in stuff, I'm trying things out and going back to redo a few things as it gets a little more clear as to how this all should work. |
@jwoertink You think we can close out this PR? I have no idea how much of this has been implemented and if there are any issues that can be closed out that are listed. |
Ok, I don't think I need this anymore. Closing it out! |
Overrides #363
This will just be a saving sandbox for me to try out some refactors. The actual PRs will be broken out in to smaller ones with less commits allowing them to be easily digested.
The end goal will be:
needs
, and callbacksyield
blocksCurrently in WIP state, so these goals could change, or increase as I get further along in this.
Here's a list of issues that I would like to take a stab at fixing along with this. I can't guarantee all of them, but I want a single place to reference them as I go along.
valid?
on nested operation if parent is invalid #276