Repository: Altinn/altinn-authorization-tmp
Pull request #511: Added view version, Fix delete query, fix IN query bug
Author: login: Thuen
Created: 2025-03-25T13:32:24Z | Merged: 2025-03-25T13:51:36Z

## Description
- Added view version
- Fix delete query
- Fix IN query bug


Diff:
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinition.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinition.cs
index c9a5d44c4..80ab906b1 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinition.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinition.cs
@@ -42,6 +42,11 @@ public class DbDefinition(Type type)
     /// </summary>
     public bool IsView { get; set; }
 
+    /// <summary>
+    /// Version of view script
+    /// </summary>
+    public int ViewVersion { get; set; } = 1;
+
     /// <summary>
     /// The SQL query used in the view.
     /// </summary>
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs
index 6ed030b56..021f8d079 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs
@@ -31,10 +31,11 @@ public DbDefinition Build()
         /// </summary>
         /// <param name="value">Default: true</param>
         /// <returns></returns>
-        public DbDefinitionBuilder<T> IsView(bool value = true)
+        public DbDefinitionBuilder<T> IsView(bool value = true, int version = 1)
         {
             // Add view script??
             DbDefinition.IsView = value;
+            DbDefinition.ViewVersion = version;
             return this;
         }
 
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
index 809ddb5c4..2b3b92316 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
@@ -47,6 +47,11 @@ public GenericFilterBuilder<T> Equal<TProperty>(Expression<Func<T, TProperty>> p
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new ArgumentException("Must have values in IN query");
+        }
+
         foreach (var value in values)
         {
             Add(property, value, FilterComparer.Equals);
@@ -64,6 +69,11 @@ public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> prop
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> NotIn<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new ArgumentException("Must have values in IN query");
+        }
+
         foreach (var value in values)
         {
             Add(property, value, FilterComparer.NotEqual);
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/QueryBuilders/PostgresQueryBuilder.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/QueryBuilders/PostgresQueryBuilder.cs
index a730a4726..30f26031d 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/QueryBuilders/PostgresQueryBuilder.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/QueryBuilders/PostgresQueryBuilder.cs
@@ -501,7 +501,7 @@ public DbMigrationScriptCollection GetMigrationScripts()
 
         if (_definition.IsView)
         {
-            scriptCollection.AddScripts(CreateView());
+            scriptCollection.AddScripts(CreateView(_definition.ViewVersion));
             foreach (var dep in _definition.ViewDependencies)
             {
                 scriptCollection.AddDependency(dep);
@@ -553,7 +553,7 @@ public DbMigrationScriptCollection GetMigrationScripts()
         return scriptCollection;
     }
 
-    private OrderedDictionary<string, string> CreateView()
+    private OrderedDictionary<string, string> CreateView(int version = 1)
     {
         var scripts = new OrderedDictionary<string, string>();
 
@@ -562,7 +562,7 @@ private OrderedDictionary<string, string> CreateView()
         {_definition.ViewQuery}
         """;
 
-        scripts.Add($"CREATE VIEW {GetTableName(includeAlias: false)}", query);
+        scripts.Add($"CREATE VIEW {GetTableName(includeAlias: false)} {version}", query);
 
         return scripts;
     }
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Services/BasicRepository.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Services/BasicRepository.cs
index a5ded1e8f..deae84f27 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Services/BasicRepository.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Services/BasicRepository.cs
@@ -169,24 +169,30 @@ protected List<GenericParameter> BuildFilterParameters(IEnumerable<GenericFilter
             parameters.Add(new GenericParameter(filter.PropertyName, value));
         }
 
-        foreach (var m in multiple)
+        if (multiple != null && multiple.Any())
         {
-            int a = 1;
-            foreach (var filter in filters.Where(t => t.PropertyName == m))
+            foreach (var m in multiple)
             {
-                parameters.Add(new GenericParameter($"@{m}_{a}", filter.Value));
-                a++;
+                int a = 1;
+                foreach (var filter in filters.Where(t => t.PropertyName == m))
+                {
+                    parameters.Add(new GenericParameter($"@{m}_{a}", filter.Value));
+                    a++;
+                }
             }
         }
 
-        if (options.Language != null)
+        if (options != null)
         {
-            parameters.Add(new GenericParameter("Language", options.Language));
-        }
+            if (options.Language != null)
+            {
+                parameters.Add(new GenericParameter("Language", options.Language));
+            }
 
-        if (options.AsOf.HasValue)
-        {
-            parameters.Add(new GenericParameter("_AsOf", options.AsOf.Value));
+            if (options.AsOf.HasValue)
+            {
+                parameters.Add(new GenericParameter("_AsOf", options.AsOf.Value));
+            }
         }
 
         return parameters;
diff --git a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence/Definitions/ConnectionDefinition.cs b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence/Definitions/ConnectionDefinition.cs
index 178a9547b..be3d95db7 100644
--- a/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence/Definitions/ConnectionDefinition.cs
+++ b/src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence/Definitions/ConnectionDefinition.cs
@@ -18,7 +18,7 @@ public void Define()
     {
         definitionRegistry.Define<Connection>(def =>
         {
-            def.IsView();
+            def.IsView(version: 2);
 
             def.RegisterProperty(t => t.Id);
             def.RegisterProperty(t => t.FromId);


Reviews:
user: login: jonkjetiloye
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T13:40:52Z
user: login: jonkjetiloye
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T13:40:57Z
user: login: jonkjetiloye
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-25T13:41:40Z
user: login: jonkjetiloye
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T13:41:45Z
user: login: Thuen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T13:42:38Z
user: login: Thuen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T13:42:42Z
user: login: Thuen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T13:44:04Z

Review comments:
diff_hunk: @@ -47,6 +47,11 @@ public GenericFilterBuilder<T> Equal<TProperty>(Expression<Func<T, TProperty>> p
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new Exception("Must have values in IN query");
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
user: login: jonkjetiloye
body: argument exception?
created_at: 2025-03-25T13:40:52Z
author_association: MEMBER
diff_hunk: @@ -64,6 +69,11 @@ public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> prop
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> NotIn<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new Exception("Must have values in IN query");
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
user: login: jonkjetiloye
body: argument exception?
created_at: 2025-03-25T13:40:57Z
author_association: MEMBER
diff_hunk: @@ -31,10 +31,11 @@ public DbDefinition Build()
         /// </summary>
         /// <param name="value">Default: true</param>
         /// <returns></returns>
-        public DbDefinitionBuilder<T> IsView(bool value = true)
+        public DbDefinitionBuilder<T> IsView(bool value = true, int version = 1)
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs
user: login: jonkjetiloye
body: mangler param doc
created_at: 2025-03-25T13:41:39Z
author_association: MEMBER
diff_hunk: @@ -47,6 +47,11 @@ public GenericFilterBuilder<T> Equal<TProperty>(Expression<Func<T, TProperty>> p
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new Exception("Must have values in IN query");
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
user: login: Thuen
body: Sant. Fixed.
created_at: 2025-03-25T13:42:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,6 +69,11 @@ public GenericFilterBuilder<T> In<TProperty>(Expression<Func<T, TProperty>> prop
     /// <returns>The current instance of <see cref="GenericFilterBuilder{T}"/>, enabling a fluent API.</returns>
     public GenericFilterBuilder<T> NotIn<TProperty>(Expression<Func<T, TProperty>> property, IEnumerable<TProperty> values)
     {
+        if (values == null || !values.Any())
+        {
+            throw new Exception("Must have values in IN query");
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Helpers/GenericFilterBuilder.cs
user: login: Thuen
body: Sant. Fixed.
created_at: 2025-03-25T13:42:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,10 +31,11 @@ public DbDefinition Build()
         /// </summary>
         /// <param name="value">Default: true</param>
         /// <returns></returns>
-        public DbDefinitionBuilder<T> IsView(bool value = true)
+        public DbDefinitionBuilder<T> IsView(bool value = true, int version = 1)
path: src/apps/Altinn.AccessManagement/src/Altinn.AccessMgmt.Persistence.Core/Definitions/DbDefinitionBuilder.cs
user: login: Thuen
body: fixed
created_at: 2025-03-25T13:44:03Z
author_association: CONTRIBUTOR

PR comments:
user: login: sonarqubecloud[bot]
created_at: 2025-03-25T13:47:51Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Authorization_Register&pullRequest=511) **Quality Gate passed for 'Authorization_Register'**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Authorization_Register&pullRequest=511&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Authorization_Register&pullRequest=511&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Authorization_Register&pullRequest=511&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Authorization_Register&pullRequest=511&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Authorization_Register&pullRequest=511&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Authorization_Register&pullRequest=511)


author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-25T13:49:43Z
body: ## [![Quality Gate Failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-failed-20px.png 'Quality Gate Failed')](https://sonarcloud.io/dashboard?id=Authorization_AccessManagement&pullRequest=511) **Quality Gate failed for 'Authorization_AccessManagement'**  
Failed conditions  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/failed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Authorization_AccessManagement&pullRequest=511&metric=new_coverage&view=list) (required ≥ 65%)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Authorization_AccessManagement&pullRequest=511)


author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-25T13:50:14Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Authorization_Authorization&pullRequest=511) **Quality Gate passed for 'Authorization_Authorization'**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=Authorization_Authorization&pullRequest=511&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Authorization_Authorization&pullRequest=511&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Authorization_Authorization&pullRequest=511&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Authorization_Authorization&pullRequest=511&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Authorization_Authorization&pullRequest=511&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Authorization_Authorization&pullRequest=511)


author_association: NONE