Skip to content

Remove a duplicate member from an enum #835

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Ahmed-Ghanam
Copy link
Contributor

@Ahmed-Ghanam Ahmed-Ghanam commented May 7, 2025

Description

These changes aim to remove a single member from an enumeration used in the database.

Related Issue(s)

Verification

  • Your code builds clean without any errors or warnings
  • Manual testing done (required)
  • Relevant automated test added (if you find this hard, leave it and we'll help out)
  • All tests run green

Documentation

  • User documentation is updated with a separate linked PR in altinn-studio-docs. (if applicable)

Summary by CodeRabbit

  • New Features

    • Introduced advanced functions and procedures for managing notification orders, recipients, statuses, summaries, metrics, and tracking within the notifications system.
    • Enhanced support for order cancellation, recipient retrieval, status updates, detailed summaries, metrics aggregation, and shipment tracking.
    • Added new procedures for inserting and updating notification records.
  • Bug Fixes

    • Resolved duplicate enum values in SMS notification result types to ensure data consistency.

Copy link
Contributor

coderabbitai bot commented May 7, 2025

📝 Walkthrough

Walkthrough

This update introduces a migration script to correct duplicate enum values in the PostgreSQL smsnotificationresulttype type and adds a comprehensive set of PostgreSQL functions and procedures for managing notification orders, emails, SMS notifications, and their statuses. No application-level exported or public entity signatures are changed.

Changes

Files Change Summary
src/Altinn.Notifications.Persistence/Migration/v0.43/01-alter-types.sql Migration script to correct the smsnotificationresulttype enum by removing duplicate values, normalizing casing, updating dependent columns, refreshing dependent views and functions, and renaming the new enum type to the original name. Ensures data consistency and updates all dependencies.
src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql Adds multiple PostgreSQL functions and procedures for notification management: order cancellation, recipient retrieval, status updates, summaries, metrics aggregation, order chain tracking, order processing updates, shipment tracking, notification and order insertion, and status updates. All functions are implemented in PL/pgSQL with detailed comments and error handling.

Possibly related PRs

Suggested reviewers

  • SandGrainOne

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (14)
src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (14)

1-7: Clarify autogenerated source
The header warns “Do not edit manually.” It would be helpful to reference the DbTools configuration or a README so future maintainers know how to regenerate or adjust these functions.


3-64: Streamline empty-result logic in cancelorder
Mixing RETURN; and RETURN QUERY can be confusing. Instead, for the “no order” and “already cancelled” branches, you can use a single RETURN QUERY with a WHERE FALSE or SELECT … LIMIT 0 to uniformly return an empty set or a default set.


68-85: Cache resource-limit lookup for performance
getemails_statusnew_updatestatus fetches emaillimittimeout each invocation. If this function is invoked at high frequency, consider caching the latest timestamp in a lightweight table or materialized view to reduce repeated scans of resourcelimitlog.


143-170: Clarify “no rows” handling in summary functions
Both getemailsummary_v2 and getsmssummary_v2 use RETURN QUERY then IF NOT FOUND …. While correct, it relies on FOUND being set by the preceding RETURN QUERY. For readability, you might explicitly PERFORM a lookup and branch:

PERFORM 1
  FROM notifications.emailnotifications n
  JOIN notifications.orders o ON …;
IF NOT FOUND THEN
  RETURN QUERY SELECT … DEFAULT ROW …;
ELSE
  RETURN QUERY SELECT … ACTUAL ROWS …;
END IF;

175-204: Consolidate metric-aggregation logic
getmetrics and the counting logic in getorder_includestatus_v4 both compute counts of sent/succeeded notifications. Extract this into a helper view or function (e.g., notifications.notification_counts(orderid)) to avoid duplication and keep metrics consistent.


286-345: Guard JSONB parsing in get_orders_chain_tracking
You check for array-ness on Reminders, but the nested SELECT jsonb_array_elements(...) can still error if the JSON is malformed. Pre-validate with:

IF jsonb_typeof(orders_chain.orderchain->'Reminders') = 'array' THEN
  -- safe to unnest
ELSE
  -- return empty array
END IF;

This prevents runtime exceptions in edge cases.


369-385: Parameterize batch size in status update
getorders_pastsendtime_updatestatus uses a hard-coded LIMIT 50. To make the migration more flexible, expose this as a function argument (e.g., _batch_size integer) with a default, so you can tune without code changes.


388-452: Abstract multi-channel tracking
get_shipment_tracking unions order, email, and SMS tracking. If more channels (e.g., push, in-app) are added, this function will grow unwieldy. Consider a table-driven “channel registry” or view-per-channel pattern to automatically assemble tracking rows.


465-483: Unify naming in SMS recipient fetch
In getsmsrecipients_v2, you take a parameter named _orderid but then alias it to __orderid. For consistency with getemailrecipients_v2, consider naming the input _alternateid and the internal _orderid.


485-510: Schedule deprecation for backward-compat function
The comment on getsms_statusnew_updatestatus() notes future removal, but no timeline is given. Add a target version or date to the comment so teams know when to migrate to the new function.


512-554: DRY up SMS status update overloads
The two variants of GETSMS_STATUSNEW_UPDATESTATUS share mostly the same logic. Move the shared query into a private helper function and have both overloads call it, passing the policy parameter.


594-642: Handle unique-key conflicts on inserts
insertemailnotification (and analogously for SMS) unconditionally inserts a new row. If the same _alternateid is retried, it will error. Consider adding an ON CONFLICT (alternateid) DO NOTHING or an explicit check to avoid runtime exceptions.


654-694: Unify insertorder overloads via default args
PostgreSQL 14+ supports default values on function parameters. You can define a single insertorder function with _sendingtimepolicy integer DEFAULT NULL to avoid duplication.


778-787: Consider logging or auditing status updates
updateemailstatus silently updates the emailnotifications table. For operational observability, you may want to emit a RAISE NOTICE or insert into an audit table when important statuses change.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b41881 and 531b028.

📒 Files selected for processing (2)
  • src/Altinn.Notifications.Persistence/Migration/v0.43/01-alter-types.sql (1 hunks)
  • src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Analyze (csharp)
  • GitHub Check: Build, test & analyze
🔇 Additional comments (6)
src/Altinn.Notifications.Persistence/Migration/v0.43/01-alter-types.sql (3)

9-29: Ensure correct enum namespace and idempotency
The script checks for smsnotificationresulttype_new in the public namespace but your production type may reside elsewhere (e.g., in notifications). Confirm that smsnotificationresulttype lives in public. To avoid collisions with identically named types in other schemas, include a namespace filter when querying pg_type:

WHERE typname = 'smsnotificationresulttype_new'
  AND typnamespace = 'public'::regnamespace

33-43: Minimize locking and hard-code safety in data migration
An ACCESS EXCLUSIVE lock will block all DML on notifications.smsnotifications. Validate that this maintenance window is acceptable. Also, the USING clause only catches one specific casing. To guard against any case variation, consider normalizing with LOWER:

- WHEN result::text = 'Failed_Recipientreserved' THEN 'Failed_RecipientReserved'
+ WHEN LOWER(result::text) = 'failed_recipientreserved' THEN 'Failed_RecipientReserved'

82-89: Validate drop/rename ordering and residual types
After dropping the old type and renaming the new one, confirm that no stray types with _new suffix remain. You can add a verification step:

-- Ensure no lingering "_new" types
SELECT n.nspname, t.typname
FROM pg_type t
JOIN pg_namespace n ON t.typnamespace = n.oid
WHERE t.typname LIKE '%_new';

This guards against orphaned types before you proceed with downstream deployments.

src/Altinn.Notifications.Persistence/Migration/v0.43/01-functions-and-procedures.sql (3)

697-726: Revisit PROCEDURE vs FUNCTION choice
You're mixing PROCEDUREs (no return) and FUNCTIONs. If you ever need to compose the inserts into larger SELECT statements, FUNCTIONs are required. Confirm this split is intentional.


728-775: Ensure SMS insert aligns with updated enum values
insertsmsnotification casts _result::smsnotificationresulttype. Any mismatch between the incoming _result string and your new enum will fail. Confirm your application layer only supplies valid enum labels.


562-593:

❓ Verification inconclusive

Verify enum-cast compatibility post-migration
Several functions cast to smsnotificationresulttype or smsnotificationresulttype_new. After running your migration, ensure that PostgreSQL correctly resolves the casts without errors. You can automate a quick check:


🏁 Script executed:

#!/bin/bash
psql -d mydb -c "SELECT pg_typeof('New'::smsnotificationresulttype);"

Length of output: 172


Verify enum-cast compatibility post-migration
After applying your SQL migration, please confirm that PostgreSQL can resolve casts to both the old and new enum types without errors. In your target database environment, run:

psql -d <your_database> -c "SELECT pg_typeof('New'::smsnotificationresulttype);"
psql -d <your_database> -c "SELECT pg_typeof('New'::smsnotificationresulttype_new);"

If either command fails, update the enum definitions or migration scripts accordingly to ensure downstream functions (e.g., getsmssummary_v2) cast cleanly.

Comment on lines +45 to +80
DO $$
DECLARE
rec RECORD;
def TEXT;
BEGIN
FOR rec IN
SELECT n.nspname, c.relname, c.relkind
FROM pg_depend d
JOIN pg_type t ON d.objid = t.oid
JOIN pg_class c ON d.refobjid = c.oid
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE t.typname = 'smsnotificationresulttype' AND c.relkind IN ('v','m')
LOOP
def := pg_get_viewdef(format('%I.%I', rec.nspname, rec.relname), true);
IF rec.relkind = 'v' THEN
EXECUTE format('CREATE OR REPLACE VIEW %I.%I AS %s', rec.nspname, rec.relname, def);
ELSE
EXECUTE format('CREATE OR REPLACE MATERIALIZED VIEW %I.%I AS %s', rec.nspname, rec.relname, def);
EXECUTE format('REFRESH MATERIALIZED VIEW %I.%I', rec.nspname, rec.relname);
END IF;
END LOOP;

FOR rec IN
SELECT n.nspname, p.proname, p.oid
FROM pg_depend d
JOIN pg_type t ON d.objid = t.oid
JOIN pg_proc p ON d.refobjid = p.oid
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE t.typname = 'smsnotificationresulttype'
LOOP
def := pg_get_functiondef(rec.oid);
def := regexp_replace(def, '\m smsnotificationresulttype \M', 'smsnotificationresulttype_new', 'g');
EXECUTE def;
END LOOP;
END
$$;
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden dependent-object recreation and regex replacement

  1. The regex '\m smsnotificationresulttype \M' may miss schema-qualified names (e.g. public.smsnotificationresulttype).
  2. To catch both unqualified and qualified references, use:
- def := regexp_replace(def, '\m smsnotificationresulttype \M', 'smsnotificationresulttype_new', 'g');
+ def := regexp_replace(def,
+   '\m(\w+\.)?smsnotificationresulttype\M',
+   'public.smsnotificationresulttype_new',
+   'g');
  1. Consider filtering pg_depend on t.typnamespace to only rebuild objects in the intended schema.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DO $$
DECLARE
rec RECORD;
def TEXT;
BEGIN
FOR rec IN
SELECT n.nspname, c.relname, c.relkind
FROM pg_depend d
JOIN pg_type t ON d.objid = t.oid
JOIN pg_class c ON d.refobjid = c.oid
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE t.typname = 'smsnotificationresulttype' AND c.relkind IN ('v','m')
LOOP
def := pg_get_viewdef(format('%I.%I', rec.nspname, rec.relname), true);
IF rec.relkind = 'v' THEN
EXECUTE format('CREATE OR REPLACE VIEW %I.%I AS %s', rec.nspname, rec.relname, def);
ELSE
EXECUTE format('CREATE OR REPLACE MATERIALIZED VIEW %I.%I AS %s', rec.nspname, rec.relname, def);
EXECUTE format('REFRESH MATERIALIZED VIEW %I.%I', rec.nspname, rec.relname);
END IF;
END LOOP;
FOR rec IN
SELECT n.nspname, p.proname, p.oid
FROM pg_depend d
JOIN pg_type t ON d.objid = t.oid
JOIN pg_proc p ON d.refobjid = p.oid
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE t.typname = 'smsnotificationresulttype'
LOOP
def := pg_get_functiondef(rec.oid);
def := regexp_replace(def, '\m smsnotificationresulttype \M', 'smsnotificationresulttype_new', 'g');
EXECUTE def;
END LOOP;
END
$$;
FOR rec IN
SELECT n.nspname, p.proname, p.oid
FROM pg_depend d
JOIN pg_type t ON d.objid = t.oid
JOIN pg_proc p ON d.refobjid = p.oid
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE t.typname = 'smsnotificationresulttype'
LOOP
def := pg_get_functiondef(rec.oid);
- def := regexp_replace(def, '\m smsnotificationresulttype \M', 'smsnotificationresulttype_new', 'g');
+ def := regexp_replace(def,
+ '\m(\w+\.)?smsnotificationresulttype\M',
+ 'public.smsnotificationresulttype_new',
+ 'g');
EXECUTE def;
END LOOP;
🤖 Prompt for AI Agents (early access)
In src/Altinn.Notifications.Persistence/Migration/v0.43/01-alter-types.sql
around lines 45 to 80, the regex used to replace 'smsnotificationresulttype' in
function definitions does not account for schema-qualified names, which can
cause missed replacements. Update the regex to match both unqualified and
schema-qualified references of the type name. Additionally, refine the pg_depend
queries by filtering on t.typnamespace to restrict dependent object recreation
to the intended schema only, preventing unintended object modifications outside
the target schema.

Copy link

sonarqubecloud bot commented May 7, 2025

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.

1 participant