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

Should the changes be available in after-update? #129

Open
Tracked by #36911
camsaul opened this issue Feb 13, 2023 · 3 comments
Open
Tracked by #36911

Should the changes be available in after-update? #129

camsaul opened this issue Feb 13, 2023 · 3 comments
Labels
medium priority tools.after-* and tools.before-* under consideration Possible ideas that may be implemented in the future

Comments

@camsaul
Copy link
Owner

camsaul commented Feb 13, 2023

Use case: to log all the changes that were made to rows in the application database.

If there were some way to make the changes made available, or at least the ones made by Toucan -- probably ok to ignore ones done by DB triggers like ON UPDATE SET updated_at = now(), that could be useful. Could these be made available by a &changes anaphor in the after-update method? Or should after-update just see an instance with the t2/changes? Need to think about this.

@camsaul camsaul added under consideration Possible ideas that may be implemented in the future medium priority tools.after-* and tools.before-* labels Feb 13, 2023
@tsmacdonald
Copy link
Contributor

This would be helpful to me. I have logic that I want to fire when a particular column has changed. If I do it in before-update, there's always a chance that the save could fail, so I want to do it in after-update.

I don't have strong feelings about whether I get them via t2/changes or &changes. t2/changes doesn't really make sense since the record would have already changed and I suppose there's a perverse case where there are additional changes that have happened since the update. But it would still be useful.

@camsaul
Copy link
Owner Author

camsaul commented Apr 24, 2024

So this does seem to work sometimes (as proven by #171) but in other situations it doesn't... in Metabase for example something with the :model/User model prevents it from working correctly

(toucan2.core/define-after-update :model/User
  [user]
  (println "ORIGINAL =>" (select-keys (toucan2.core/original user) [:is_superuser]))
  (println "NEW =>"      (select-keys user [:is_superuser]))
  (println "CHANGES =>"  (select-keys (toucan2.core/changes user) [:is_superuser]))
  user)

(defn x []
  (let [user         (toucan2.core/select-one :model/User)
        _            (println "USER =>" (select-keys user [:is_superuser]))
        updates      {:is_superuser (not (:is_superuser user))}
        _            (println "UPDATES =>" updates)
        rows-updated (toucan2.core/update! :model/User (:id user) updates)]
    (printf "Updated %d rows.\n" rows-updated)))

(x)
USER => {:is_superuser true}
UPDATES => {:is_superuser false}
ORIGINAL => {:is_superuser false}
NEW => {:is_superuser false}
CHANGES => {}
Updated 1 rows.

vs. a new model, which works correctly

(methodical.core/defmethod toucan2.core/table-name ::FakeUser
  [_model]
  "core_user")

(toucan2.core/define-after-update ::FakeUser
  [user]
  (println "ORIGINAL =>" (select-keys (toucan2.core/original user) [:is_superuser]))
  (println "NEW =>"      (select-keys user [:is_superuser]))
  (println "CHANGES =>"  (select-keys (toucan2.core/changes user) [:is_superuser]))
  user)

(defn x []
  (let [user         (toucan2.core/select-one ::FakeUser)
        _            (println "USER =>" (select-keys user [:is_superuser]))
        updates      {:is_superuser (not (:is_superuser user))}
        _            (println "UPDATES =>" updates)
        rows-updated (toucan2.core/update! ::FakeUser (:id user) updates)]
    (printf "Updated %d rows.\n" rows-updated)))

(x)
USER => {:is_superuser false}
UPDATES => {:is_superuser true}
ORIGINAL => {}
NEW => {:is_superuser true}
CHANGES => {:is_superuser true}
Updated 1 rows.

Not sure why :model/User doesn't work, maybe after-select or something is inadvertently discarding the changes... either way I think after-update should probably reset changes before calling the method to ensure the method sees the correct value

@tsmacdonald
Copy link
Contributor

Seems like an underlying issue is that ORIGINAL is wrong: in your example it should be true and not false. I thought for sure it was something weird in before-update, but in a fresh REPL with no before-update I get the same behavior. Will look into this more tomorrow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
medium priority tools.after-* and tools.before-* under consideration Possible ideas that may be implemented in the future
Projects
None yet
Development

No branches or pull requests

2 participants