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

Chore/1876 rebase pending revisions #1882

Merged
merged 51 commits into from
Apr 8, 2024

Conversation

mikevespi
Copy link
Contributor

Adding the backend work for handling concurrent revisions.

@mikevespi mikevespi force-pushed the chore/1876-rebase-pending-revisions branch from 41104a7 to 7d30a53 Compare November 22, 2023 18:23
@mikevespi mikevespi marked this pull request as ready for review November 28, 2023 19:36
@pbastia
Copy link
Contributor

pbastia commented Feb 29, 2024

Needs rebase. I'll have a look early next week!

@mikevespi mikevespi force-pushed the chore/1876-rebase-pending-revisions branch from 218964e to e649d35 Compare March 6, 2024 23:08
Copy link
Contributor

@pbastia pbastia left a comment

Choose a reason for hiding this comment

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

Great work!
There's a few things we need to adjust I think, but the logic is sound and it seems like it'll work. Also it looks like we're missing some tests at the end?

A note about postgres count() function, not that it matters in this case since we have at most a few rows to count, but count(expression) is less performant than count(*) since the postgres query planner recognizes this as "count everything without evaluating the expression every row"

@@ -1,10 +1,17 @@
-- Deploy cif:mutations/commit_form_change to pg
begin;

create or replace function cif_private.commit_form_change_internal(fc cif.form_change)
-- We need to explicitly drop the old function here since we're changing the signature.
Copy link
Contributor

Choose a reason for hiding this comment

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

if
  if
    if ...

Add a comment in here and a tech debt card to refactor this in a more OOP way

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done!

(select row(form_change.*)::cif.form_change from cif.form_change where id = row_id),
(select id from cif.project_revision
where project_id=(select project_id from cif.project_revision where id = form_change_patch.project_revision_id)
and change_status = 'pending' and id != form_change_patch.project_revision_id limit 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

limit 1

As a thought, what if there were more than one? Should we log something? Report an error? flag something for Sentry?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These constraints should prevent multiple from being possible, but what would we do when we log? Prevent the revision from being commit?

Copy link
Contributor

Choose a reason for hiding this comment

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

Since we have those constraints I don't think we even need to say limit 1 then. Maybe just a comment that we have unique indices would be good?

project_revision_id => pending_project_revision_id,
json_schema_name => fc.json_schema_name,
new_form_data => (fc.new_form_data || format('{"contactIndex": %s}',
(select max(new_form_data ->> 'contactIndex')::int from cif.form_change
Copy link
Contributor

Choose a reason for hiding this comment

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

max(text value) uses alphabetical order so we'd have an index of '3' ranking above '11' or '25', the cast needs to happen inside the call

Suggested change
(select max(new_form_data ->> 'contactIndex')::int from cif.form_change
(select max((new_form_data ->> 'contactIndex')::int) from cif.form_change

project_revision_id => pending_project_revision_id,
json_schema_name => fc.json_schema_name,
new_form_data => (fc.new_form_data || format('{"reportingRequirementIndex": %s}',
(select max(new_form_data ->> 'reportingRequirementIndex')::int from cif.form_change
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(select max(new_form_data ->> 'reportingRequirementIndex')::int from cif.form_change
(select max((new_form_data ->> 'reportingRequirementIndex')::int) from cif.form_change

project_revision_id => pending_project_revision_id,
json_schema_name => fc.json_schema_name,
new_form_data => (fc.new_form_data || format('{"reportingRequirementIndex": %s}',
(select max(new_form_data ->> 'reportingRequirementIndex')::int from cif.form_change
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
(select max(new_form_data ->> 'reportingRequirementIndex')::int from cif.form_change
(select max((new_form_data ->> 'reportingRequirementIndex')::int) from cif.form_change

select is(
(select * from cif.jsonb_minus('{"a": 1, "b": 0, "c": 1, "d": null}'::jsonb, '{"a": 0, "b": 0}'::jsonb)),
'{"a": 1, "c": 1, "d": null}'::jsonb,
'Added fields are included in the retuen value, including when their value is null'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Added fields are included in the retuen value, including when their value is null'
'Added fields are included in the return value, including when their value is null'

'{"a": 1, "c": 1, "d": null}'::jsonb,
'Added fields are included in the retuen value, including when their value is null'
);

Copy link
Contributor

Choose a reason for hiding this comment

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

missing a test to make sure extra fields in the second param (subtrahend, boy what a word) are not added:

select is(
  (select * from cif.jsonb_minus('{"a": 1, "b": 0}'::jsonb, '{"a": 1, "b": 2, "d": "test value"}'::jsonb)),
  '{"b": 0}'::jsonb,
  'Extra fields in the subtrahend are properly ignored'
);

-- This behaviour fits our needs at the time of writing this, so the additional complexity of handling the other cases is not needed.


create or replace function cif.jsonb_minus(minuend jsonb, subtrahend jsonb)
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be fun for this one (but just fun, not that we have to do it here) to declare the - operator for the jsonb type with this function
https://www.postgresql.org/docs/current/sql-createoperator.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It would! This is cool I didn't know that you could add them like this

-- project_manager projectManagerLabelId 1 is update and 2 is created in pending
-- reporting_requirement should be 3 total with 1,2,3 for reportingRequirementIndex
-- milestone should be 3 total with 1,2,3 for reportingRequirementIndex
-- attachment
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like we're missing some assertions?

@@ -68,7 +68,7 @@ select results_eq(
null::int,
'pending'::varchar,
'reporting_requirement'::varchar,
'["hazErrors"]'::jsonb
'[]'::jsonb
Copy link
Contributor

Choose a reason for hiding this comment

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

any reason why we removed the errors?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These came out to try to determine why this doesn't throw an error.

if fc.validation_errors != '[]' then
    raise exception 'Cannot commit change with validation errors: %', fc.validation_errors;
  end if;

In commit_form_change_internal that clause right inside of the do block should be throwing when it sees those errors, but does not, it simply commits the form change which the rest of the tests confirm. I might be missing something, this was from the original tests so maybe behaviour elsewhere has changed that affected this

Comment on lines +248 to +264
*/
if pending_minus_pendings_parent is not null then
update cif.form_change set
operation = 'create'::cif.form_change_operation,
form_data_record_id = null,
previous_form_change_id = null
where id = pending_form_change.id;

else
/*
If pending has not made changes to the form data, the pending record can be deleted as it never would have been made
*/
delete from cif.form_change
where project_revision_id = pending_project_revision_id
and form_data_table_name = fc.form_data_table_name
and form_data_record_id = fc.form_data_record_id;
end if;
Copy link
Contributor

Choose a reason for hiding this comment

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

👌 👌

(select (new_form_data ->> 'provinceSharePercentage')::int from cif.form_change where project_revision_id = 2 and json_schema_name = 'funding_parameter_EP'),
1,
'When committing and pending have both created a funding parameter form, pending maintains its form values'
);
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a tricky one. If a value is not set by the amendment in the funding parameter form, but set in the general revision, would a user expect that to be reflected in the amendment?
This is probably a rare edge case where there might be the impression that data was lost. This can probably be resolved with some training.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a very good question. I leaned towards "the amendment is right" when I wasn't sure but I'd love to know where Business Area sit on the specific cases.

Copy link
Contributor

Choose a reason for hiding this comment

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

Probably careful examination of the changes before submitting an amendment or a revision would do the trick

Copy link
Contributor

@pbastia pbastia left a comment

Choose a reason for hiding this comment

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

Fantastic job with the testing especially!! :shipit:

mikevespi added 22 commits April 2, 2024 15:36
mikevespi added 22 commits April 2, 2024 15:37
…ange pendings operation to create and null the record id and previous form change
…and pending form changes create the same contact index
@mikevespi mikevespi force-pushed the chore/1876-rebase-pending-revisions branch from 70040ea to 1a2ac24 Compare April 2, 2024 22:37
@mikevespi mikevespi merged commit 00bf683 into develop Apr 8, 2024
17 checks passed
@mikevespi mikevespi deleted the chore/1876-rebase-pending-revisions branch April 8, 2024 17:06
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.

2 participants