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

Added support for non-serial pField mutation #39

Merged
merged 9 commits into from
Nov 9, 2021

Conversation

talkanbaev-artur
Copy link
Contributor

Yet this implementation does not protect from accidental mutation of pk, it assumes the possibility of explicit, non-serial PK mutation in the changeset.

Probably this mutation should only occur during the insertion, however, the Mutator interface does not specify the action, unlike in Ecto, and I did not find a way to deduce the action from Apply method.

Closes #38

Yet this implememnation gidoes not protect from accidental mutation of pk
@codecov
Copy link

codecov bot commented Nov 8, 2021

Codecov Report

Merging #39 (c6d7308) into master (1c208e7) will not change coverage.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff            @@
##            master       #39   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           31        31           
  Lines          883       884    +1     
=========================================
+ Hits           883       884    +1     
Impacted Files Coverage Δ
changeset.go 100.00% <100.00%> (ø)
convert.go 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1c208e7...c6d7308. Read the comment docs.

Removed unnecessary break
changeset.go Outdated Show resolved Hide resolved
changeset.go Outdated
@@ -87,9 +97,14 @@ func (c *Changeset) Apply(doc *rel.Document, mut *rel.Mutation) {
c.applyAssocMany(doc, field, mut, v)
}
default:
if field != pField && scannable(c.types[field]) {
if pField != field && scannable(c.types[field]) { //if not PK - try to set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only change to this is enough?

if (pField != field || pField == field && !c.ignorePrimary) && scannable(c.types[field]) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and after that we maybe we don't need mutablePField?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds reasonable, however, mutable serial and bigserial PK does not make sense. Hence, the mutable PK is here to ensure that PK is something other than that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mutable serial and bigserial PK does not make sense

sorry I don't understand this part

if what you mean is to allow non autogenerated id only for field other than integer (or bigint), then you won't be able to accommodate user that use library like snowflake (go version: https://github.com/sony/sonyflake)
so it's perfectly fine to accept any type as primary, no need to think about whether it's autogenerated or not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. Actually, what do think about this change in general? Maybe, it worth to just enforce users to set the PK using explicit rel.Set than to introduce such complicated logic? Or suggested changes are valid from perspective of library's idea?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the suggested change is not complicated at all 🤔 :

  1. add ignorePrimaryField to Changeset struct
  2. set ignorePrimaryField to true when Convert is used
  3. Update Apply to use if (pField != field || pField == field && !c.ignorePrimary) && scannable(c.types[field]) { condition

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok then. In general it would be nice to revisit the changeset logic, because it does not allow for composite PK, and maybe some rules about it's mutation should be introduced - again I think that PK can be inserted, but not updated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure why composite pk is not allowed, but feel free to open other issue if it still happening after this pr merged

convert.go Show resolved Hide resolved
change.go Outdated Show resolved Hide resolved
changeset.go Outdated
@@ -87,9 +97,14 @@ func (c *Changeset) Apply(doc *rel.Document, mut *rel.Mutation) {
c.applyAssocMany(doc, field, mut, v)
}
default:
if field != pField && scannable(c.types[field]) {
if pField != field && scannable(c.types[field]) { //if not PK - try to set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and after that we maybe we don't need mutablePField?

@talkanbaev-artur
Copy link
Contributor Author

talkanbaev-artur commented Nov 9, 2021

I wonder if we can deduce the primary key in the PutChange method - this would extremely simply the logic. Because the mutation of PK should only occur if PK is not set (that how I see it). Maybe it would be possible to update the Cast method.

Suppose we have a PK, which can be muted. That induces that it is not SERIAL or BIGSERIAL - maybe UUID or a natural PK. Then it would only be logical to set it during the INSERT statement. This assumption makes the PK immutable in general sense - it can be set once and never be updated. So this is kind of behaviour I expect to resolve the #38.

@@ -206,3 +215,110 @@ func TestChangesetApply_constraint(t *testing.T) {
UpdatedAt: now,
}, user)
}

func TestChangesetApply_MutablePK(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for the name case, the convention in this repo is to start with lower case

Suggested change
func TestChangesetApply_MutablePK(t *testing.T) {
func TestChangesetApply_mutablePK(t *testing.T) {

maybe mutablePK can be changed as well since we are not using that variable anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests are updated

changeset.go Outdated
@@ -87,7 +88,7 @@ func (c *Changeset) Apply(doc *rel.Document, mut *rel.Mutation) {
c.applyAssocMany(doc, field, mut, v)
}
default:
if field != pField && scannable(c.types[field]) {
if (pField != field || pField == field && !c.ignorePrimary) && scannable(c.types[field]) { //if not PK - try to set
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe comment can be removed or updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is removed

Copy link
Member

@Fs02 Fs02 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, Thank you!!

@Fs02 Fs02 merged commit ba0464b into go-rel:master Nov 9, 2021
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

Successfully merging this pull request may close these issues.

Changeset apply function ignores non-serial primary field during insertion
2 participants