Repository: squashql/squashql
Pull request #314 (2024-04-22 11:15:05)

Add an option to compute hierachical measures with filters
Fixes #268 


Patch:
diff --git a/core/src/main/java/io/squashql/query/ComparisonMeasureGrandTotal.java b/core/src/main/java/io/squashql/query/ComparisonMeasureGrandTotal.java
index 1b04062..7550754 100644
--- a/core/src/main/java/io/squashql/query/ComparisonMeasureGrandTotal.java
+++ b/core/src/main/java/io/squashql/query/ComparisonMeasureGrandTotal.java
@@ -14,15 +14,14 @@ public class ComparisonMeasureGrandTotal implements Measure {
   public String expression;
   @Getter
   public ComparisonMethod comparisonMethod;
+  public boolean clearFilters;
   @Getter
   public Measure measure;
 
   public ComparisonMeasureGrandTotal(@NonNull String alias,
                                      @NonNull ComparisonMethod comparisonMethod,
                                      @NonNull Measure measure) {
-    this.alias = alias;
-    this.comparisonMethod = comparisonMethod;
-    this.measure = measure;
+    this(alias, null, comparisonMethod, true, measure);
   }
 
   @Override
diff --git a/core/src/main/java/io/squashql/query/ComparisonMeasureReferencePosition.java b/core/src/main/java/io/squashql/query/ComparisonMeasureReferencePosition.java
index 6545965..7b432cb 100644
--- a/core/src/main/java/io/squashql/query/ComparisonMeasureReferencePosition.java
+++ b/core/src/main/java/io/squashql/query/ComparisonMeasureReferencePosition.java
@@ -20,6 +20,7 @@ public class ComparisonMeasureReferencePosition implements Measure {
   @Getter
   public ComparisonMethod comparisonMethod;
   public BiFunction<Object, Object, Object> comparisonOperator;
+  public boolean clearFilters;
   @Getter
   public Measure measure;
   public ColumnSetKey columnSetKey;
@@ -34,7 +35,7 @@ public class ComparisonMeasureReferencePosition implements Measure {
                                             @NonNull Measure measure,
                                             @NonNull Map<Field, String> referencePosition,
                                             @NonNull Period period) {
-    this(alias, comparisonMethod, null, measure, referencePosition, period, null, null, null, false);
+    this(alias, comparisonMethod, null, true, measure, referencePosition, period, null, null, null, false);
   }
 
   public ComparisonMeasureReferencePosition(@NonNull String alias,
@@ -42,14 +43,14 @@ public class ComparisonMeasureReferencePosition implements Measure {
                                             @NonNull Measure measure,
                                             @NonNull Map<Field, String> referencePosition,
                                             @NonNull ColumnSetKey columnSetKey) {
-    this(alias, comparisonMethod, null, measure, referencePosition, null, columnSetKey, null, null, false);
+    this(alias, comparisonMethod, null, true, measure, referencePosition, null, columnSetKey, null, null, false);
   }
 
   public ComparisonMeasureReferencePosition(@NonNull String alias,
                                             @NonNull ComparisonMethod comparisonMethod,
                                             @NonNull Measure measure,
                                             @NonNull Map<Field, String> referencePosition) {
-    this(alias, comparisonMethod, null, measure, referencePosition, null, null, null, null, false);
+    this(alias, comparisonMethod, null, true, measure, referencePosition, null, null, null, null, false);
   }
 
   public ComparisonMeasureReferencePosition(@NonNull String alias,
@@ -57,14 +58,14 @@ public class ComparisonMeasureReferencePosition implements Measure {
                                             @NonNull Measure measure,
                                             @NonNull Map<Field, String> referencePosition,
                                             @NonNull List<?> elements) {
-    this(alias, comparisonMethod, null, measure, referencePosition, null, null, elements, null, false);
+    this(alias, comparisonMethod, null, true, measure, referencePosition, null, null, elements, null, false);
   }
 
   public ComparisonMeasureReferencePosition(@NonNull String alias,
                                             @NonNull ComparisonMethod comparisonMethod,
                                             @NonNull Measure measure,
                                             @NonNull List<Field> ancestors) {
-    this(alias, comparisonMethod, null, measure, null, null, null, null, ancestors, false);
+    this(alias, comparisonMethod, null, true, measure, null, null, null, null, ancestors, false);
   }
 
   public ComparisonMeasureReferencePosition(@NonNull String alias,
@@ -72,7 +73,7 @@ public class ComparisonMeasureReferencePosition implements Measure {
                                             @NonNull Measure measure,
                                             @NonNull List<Field> ancestors,
                                             boolean grandTotalAlongAncestors) {
-    this(alias, comparisonMethod, null, measure, null, null, null, null, ancestors, grandTotalAlongAncestors);
+    this(alias, comparisonMethod, null, true, measure, null, null, null, null, ancestors, grandTotalAlongAncestors);
   }
 
   /**
@@ -82,12 +83,13 @@ public class ComparisonMeasureReferencePosition implements Measure {
                                             @NonNull BiFunction<Object, Object, Object> comparisonOperator,
                                             @NonNull Measure measure,
                                             @NonNull List<Field> ancestors) {
-    this(alias, null, comparisonOperator, measure, null, null, null, null, ancestors, false);
+    this(alias, null, comparisonOperator, false, measure, null, null, null, null, ancestors, false);
   }
 
   private ComparisonMeasureReferencePosition(String alias,
                                              ComparisonMethod comparisonMethod,
                                              BiFunction<Object, Object, Object> comparisonOperator,
+                                             boolean clearFilters,
                                              Measure measure,
                                              Map<Field, String> referencePosition,
                                              Period period,
@@ -98,6 +100,7 @@ public class ComparisonMeasureReferencePosition implements Measure {
     this.alias = alias;
     this.comparisonMethod = comparisonMethod;
     this.comparisonOperator = comparisonOperator;
+    this.clearFilters = clearFilters;
     this.measure = measure;
     this.referencePosition = referencePosition;
     this.period = period;
diff --git a/core/src/main/java/io/squashql/query/Functions.java b/core/src/main/java/io/squashql/query/Functions.java
index 072a1e5..a9b1c83 100644
--- a/core/src/main/java/io/squashql/query/Functions.java
+++ b/core/src/main/java/io/squashql/query/Functions.java
@@ -263,17 +263,17 @@ public class Functions {
 
   // COMPARISONS
 
-  public static Measure comparisonMeasureWithParentOfAxis(String alias,
+  public static PartialHierarchicalComparisonMeasure comparisonMeasureWithParentOfAxis(String alias,
                                                           ComparisonMethod comparisonMethod,
                                                           Measure underlyingMeasure,
                                                           Axis axis) {
-    return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, underlyingMeasure, axis, false);
+    return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, true, underlyingMeasure, axis, false);
   }
 
-  public static Measure comparisonMeasureWithTotalOfAxis(String alias,
+  public static PartialHierarchicalComparisonMeasure comparisonMeasureWithTotalOfAxis(String alias,
                                                          ComparisonMethod comparisonMethod,
                                                          Measure underlyingMeasure,
                                                          Axis axis) {
-    return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, underlyingMeasure, axis, true);
+    return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, true, underlyingMeasure, axis, true);
   }
 }
diff --git a/core/src/main/java/io/squashql/query/MeasureUtils.java b/core/src/main/java/io/squashql/query/MeasureUtils.java
index 62254aa..2f0a489 100644
--- a/core/src/main/java/io/squashql/query/MeasureUtils.java
+++ b/core/src/main/java/io/squashql/query/MeasureUtils.java
@@ -12,6 +12,7 @@ import lombok.NoArgsConstructor;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
+import java.util.function.Function;
 
 @NoArgsConstructor
 public final class MeasureUtils {
@@ -83,7 +84,7 @@ public final class MeasureUtils {
           CompiledComparisonMeasureReferencePosition cm,
           QueryScope queryScope) {
     AtomicReference<CompiledCriteria> copy = new AtomicReference<>(queryScope.whereCriteria() == null ? null : CompiledCriteria.deepCopy(queryScope.whereCriteria()));
-    Consumer<TypedField> criteriaRemover = field -> copy.set(removeCriteriaOnField(field, copy.get()));
+    Consumer<TypedField> criteriaRemover = cm.clearFilters() ? field -> copy.set(removeCriteriaOnField(field, copy.get())) : Function.identity()::apply;
     groupColumns.forEach(criteriaRemover);
     Optional.ofNullable(cm.referencePosition())
             // to handle ComparisonMeasure with no GroupColumn => previous member, first member...
diff --git a/core/src/main/java/io/squashql/query/PartialHierarchicalComparisonMeasure.java b/core/src/main/java/io/squashql/query/PartialHierarchicalComparisonMeasure.java
index b41db07..b61e495 100644
--- a/core/src/main/java/io/squashql/query/PartialHierarchicalComparisonMeasure.java
+++ b/core/src/main/java/io/squashql/query/PartialHierarchicalComparisonMeasure.java
@@ -14,6 +14,7 @@ public class PartialHierarchicalComparisonMeasure implements Measure {
   public String expression;
   @Getter
   public ComparisonMethod comparisonMethod;
+  public boolean clearFilters;
   @Getter
   public Measure measure;
   public Axis axis;
@@ -21,11 +22,13 @@ public class PartialHierarchicalComparisonMeasure implements Measure {
 
   public PartialHierarchicalComparisonMeasure(String alias,
                                               ComparisonMethod comparisonMethod,
+                                              boolean clearFilters,
                                               Measure measure,
                                               Axis axis,
                                               boolean grandTotalAlongAncestors) {
     this.alias = alias;
     this.comparisonMethod = comparisonMethod;
+    this.clearFilters = clearFilters;
     this.measure = measure;
     this.axis = axis;
     this.grandTotalAlongAncestors = grandTotalAlongAncestors;
diff --git a/core/src/main/java/io/squashql/query/QueryResolver.java b/core/src/main/java/io/squashql/query/QueryResolver.java
index 157a56c..2f5efee 100644
--- a/core/src/main/java/io/squashql/query/QueryResolver.java
+++ b/core/src/main/java/io/squashql/query/QueryResolver.java
@@ -355,6 +355,7 @@ public class QueryResolver {
             m.alias,
             m.comparisonMethod,
             m.comparisonOperator,
+            m.clearFilters,
             compileMeasure(m.measure, topMeasure),
             m.referencePosition == null ? null : m.referencePosition.entrySet().stream().collect(Collectors.toMap(e -> resolveField(e.getKey()), Map.Entry::getValue)),
             compilePeriod(m.period),
diff --git a/core/src/main/java/io/squashql/query/compiled/CompiledComparisonMeasureReferencePosition.java b/core/src/main/java/io/squashql/query/compiled/CompiledComparisonMeasureReferencePosition.java
index b7b52c9..cdad3a8 100644
--- a/core/src/main/java/io/squashql/query/compiled/CompiledComparisonMeasureReferencePosition.java
+++ b/core/src/main/java/io/squashql/query/compiled/CompiledComparisonMeasureReferencePosition.java
@@ -12,6 +12,7 @@ import java.util.function.BiFunction;
 public record CompiledComparisonMeasureReferencePosition(String alias,
                                                          ComparisonMethod comparisonMethod,
                                                          BiFunction<Object, Object, Object> comparisonOperator,
+                                                         boolean clearFilters,
                                                          CompiledMeasure measure,
                                                          Map<TypedField, String> referencePosition,
                                                          CompiledPeriod period,
diff --git a/core/src/main/java/io/squashql/query/measure/visitor/PartialMeasureVisitor.java b/core/src/main/java/io/squashql/query/measure/visitor/PartialMeasureVisitor.java
index a0f947f..fca1ef7 100644
--- a/core/src/main/java/io/squashql/query/measure/visitor/PartialMeasureVisitor.java
+++ b/core/src/main/java/io/squashql/query/measure/visitor/PartialMeasureVisitor.java
@@ -37,6 +37,7 @@ public record PartialMeasureVisitor(
             measure.expression,
             measure.comparisonMethod,
             measure.comparisonOperator,
+            measure.clearFilters,
             measure.measure.accept(this),
             measure.columnSetKey,
             measure.elements,
@@ -52,6 +53,7 @@ public record PartialMeasureVisitor(
             measure.alias,
             measure.expression,
             measure.comparisonMethod,
+            measure.clearFilters,
             measure.measure.accept(this));
   }
 
@@ -93,20 +95,21 @@ public record PartialMeasureVisitor(
   @Override
   public Measure visit(PartialHierarchicalComparisonMeasure measure) {
     List<Field> ancestors = getAncestors(measure.axis);
-    return new ComparisonMeasureReferencePosition(
+    ComparisonMeasureReferencePosition cmrp = new ComparisonMeasureReferencePosition(
             measure.alias,
             measure.comparisonMethod,
             measure.measure.accept(this),
             ancestors,
             measure.grandTotalAlongAncestors
     );
+    cmrp.clearFilters = measure.clearFilters;
+    return cmrp;
   }
 
   private List<Field> getAncestors(Axis axis) {
-    List<Field> ancestors = axis != null ? switch (axis) {
+    return axis != null ? switch (axis) {
       case ROW -> this.pivotTableContext.cleansedColumns;
       case COLUMN -> this.pivotTableContext.cleansedRows;
     } : this.pivotTableContext.cleansedColumns;
-    return ancestors;
   }
 }
diff --git a/documentation/QUERY.md b/documentation/QUERY.md
index 5fb1dc4..b1601f3 100644
--- a/documentation/QUERY.md
+++ b/documentation/QUERY.md
@@ -1045,6 +1045,18 @@ comparisonMeasureWithParentOfAxis("parent", DIVIDE, value, ROW)
 | germany | berlin | 7/7   | 4/7   | 3/7   |
 | germany | munich | 5/5   | 3/5   | 2/5   |
 
+Note that query filters on ancestors are ignored when computing a hierarchical measure. Using the following measure
+```typescript
+comparisonMeasureWithParentOfAxis("parent", DIVIDE, value, COLUMN)
+```
+with `where(criterion(city, eq("lyon"))` would lead to:
+
+|         |        | total | 2023  | 2024  |
+|---------|--------|-------|-------|-------|
+| total   | total  | 44/44 | 23/23 | 21/21 |
+| france  | total  | 31/44 | 15/23 | 16/21 |
+| france  | lyon   | 9/31  | 5/15  | 4/16  |
+
 ##### Group comparison - ColumnSet
 
 This type of comparison is mainly used for what-if comparison but not limited to it. It involves the creation of a new
diff --git a/js/typescript-library/src/measure.ts b/js/typescript-library/src/measure.ts
index 7c60282..d5c9edc 100644
--- a/js/typescript-library/src/measure.ts
+++ b/js/typescript-library/src/measure.ts
@@ -89,6 +89,7 @@ export class ComparisonMeasureReferencePosition implements Measure {
 
   constructor(readonly alias: string,
               readonly comparisonMethod: ComparisonMethod,
+              public clearFilters: boolean,
               readonly measure: Measure,
               readonly referencePosition?: Map<Field, string>,
               readonly columnSetKey?: ColumnSetKey,
@@ -103,6 +104,7 @@ export class ComparisonMeasureReferencePosition implements Measure {
       "@class": this.class,
       "alias": this.alias,
       "comparisonMethod": this.comparisonMethod,
+      "clearFilters": this.clearFilters,
       "measure": this.measure,
       "columnSetKey": this.columnSetKey,
       "elements": this.elements,
@@ -120,6 +122,7 @@ export class ComparisonMeasureGrandTotal implements Measure {
 
   constructor(readonly alias: string,
               readonly comparisonMethod: ComparisonMethod,
+              public clearFilters: boolean,
               readonly measure: Measure) {
   }
 
@@ -127,6 +130,7 @@ export class ComparisonMeasureGrandTotal implements Measure {
     return {
       "@class": this.class,
       "alias": this.alias,
+      "clearFilters": this.clearFilters,
       "comparisonMethod": this.comparisonMethod,
       "measure": this.measure,
     }
@@ -143,6 +147,7 @@ export class PartialHierarchicalComparisonMeasure implements Measure {
   readonly expression?: string
 
   constructor(readonly alias: string,
+              public clearFilters: boolean,
               readonly comparisonMethod: ComparisonMethod,
               readonly measure: Measure,
               readonly axis: Axis,
@@ -153,6 +158,7 @@ export class PartialHierarchicalComparisonMeasure implements Measure {
     return {
       "@class": this.class,
       "alias": this.alias,
+      "clearFilters": this.clearFilters,
       "comparisonMethod": this.comparisonMethod,
       "measure": this.measure,
       "axis": this.axis,
@@ -309,54 +315,54 @@ export function comparisonMeasureWithPeriod(alias: string,
                                             measure: Measure,
                                             referencePosition: Map<Field, string>,
                                             period: Period): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition, undefined, undefined, period)
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, true, measure, referencePosition, undefined, undefined, period)
 }
 
 export function comparisonMeasureWithinSameGroup(alias: string,
                                                  comparisonMethod: ComparisonMethod,
                                                  measure: Measure,
                                                  referencePosition: Map<Field, string>): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition)
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, true, measure, referencePosition)
 }
 
 export function comparisonMeasureWithinSameGroupInOrder(alias: string,
                                                         comparisonMethod: ComparisonMethod,
                                                         measure: Measure,
                                                         referencePosition: Map<Field, string>,
-                                                        elements: Array<any>): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, referencePosition, undefined, elements)
+                                                        elements: Array<any>): ComparisonMeasureReferencePosition {
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, true, measure, referencePosition, undefined, elements)
 }
 
 export function comparisonMeasureWithParent(alias: string,
                                             comparisonMethod: ComparisonMethod,
                                             measure: Measure,
-                                            ancestors: Array<Field>): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, undefined, undefined, undefined, undefined, ancestors, false)
+                                            ancestors: Array<Field>): ComparisonMeasureReferencePosition {
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, true, measure, undefined, undefined, undefined, undefined, ancestors, false)
 }
 
 export function comparisonMeasureWithGrandTotalAlongAncestors(alias: string,
                                                               comparisonMethod: ComparisonMethod,
                                                               measure: Measure,
-                                                              ancestors: Array<Field>): Measure {
-  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, measure, undefined, undefined, undefined, undefined, ancestors, true)
+                                                              ancestors: Array<Field>): ComparisonMeasureReferencePosition {
+  return new ComparisonMeasureReferencePosition(alias, comparisonMethod, true, measure, undefined, undefined, undefined, undefined, ancestors, true)
 }
 
 export function comparisonMeasureWithGrandTotal(alias: string,
                                                 comparisonMethod: ComparisonMethod,
-                                                measure: Measure): Measure {
-  return new ComparisonMeasureGrandTotal(alias, comparisonMethod, measure)
+                                                measure: Measure): ComparisonMeasureGrandTotal {
+  return new ComparisonMeasureGrandTotal(alias, comparisonMethod, true, measure)
 }
 
 export function comparisonMeasureWithParentOfAxis(alias: string,
                                                   comparisonMethod: ComparisonMethod,
                                                   measure: Measure,
-                                                  axis: Axis) {
-  return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, measure, axis, false)
+                                                  axis: Axis): PartialHierarchicalComparisonMeasure {
+  return new PartialHierarchicalComparisonMeasure(alias, true, comparisonMethod, measure, axis, false)
 }
 
 export function comparisonMeasureWithTotalOfAxis(alias: string,
                                                  comparisonMethod: ComparisonMethod,
                                                  measure: Measure,
-                                                 axis: Axis) {
-  return new PartialHierarchicalComparisonMeasure(alias, comparisonMethod, measure, axis, true)
+                                                 axis: Axis): PartialHierarchicalComparisonMeasure {
+  return new PartialHierarchicalComparisonMeasure(alias, true, comparisonMethod, measure, axis, true)
 }
diff --git a/js/typescript-library/src/util.ts b/js/typescript-library/src/util.ts
index df6a121..fa54459 100644
--- a/js/typescript-library/src/util.ts
+++ b/js/typescript-library/src/util.ts
@@ -52,6 +52,7 @@ function transformToObject(key: string, value: any, reviverFallback?: (key: stri
     return new ComparisonMeasureReferencePosition(
             value["alias"],
             value["comparisonMethod"],
+            value["clearFilters"],
             transformToObject("measure", value["measure"]),
             m.size == 0 ? undefined : m,
             value["columnSetKey"],
@@ -74,9 +75,10 @@ function transformToObject(key: string, value: any, reviverFallback?: (key: stri
     return new ComparisonMeasureGrandTotal(
             value["alias"],
             value["comparisonMethod"],
+            value["clearFilters"],
             transformToObject("measure", value["measure"]))
   } else if (clazz === PACKAGE + "PartialHierarchicalComparisonMeasure") {
-    return new PartialHierarchicalComparisonMeasure(value["alias"], value["comparisonMethod"], transformToObject("measure", value["measure"]), value["axis"], value["grandTotalAlongAncestors"])
+    return new PartialHierarchicalComparisonMeasure(value["alias"], value["clearFilters"], value["comparisonMethod"], transformToObject("measure", value["measure"]), value["axis"], value["grandTotalAlongAncestors"])
   } else if (clazz === PACKAGE + "ExpressionMeasure") {
     return new ExpressionMeasure(value["alias"], value["expression"])
   } else if (clazz === PACKAGE + "LongConstantMeasure") {


Test patch:
diff --git a/core/src/test/java/io/squashql/query/ATestGrandTotalComparison.java b/core/src/test/java/io/squashql/query/ATestGrandTotalComparison.java
index d4eb463..e0e7377 100644
--- a/core/src/test/java/io/squashql/query/ATestGrandTotalComparison.java
+++ b/core/src/test/java/io/squashql/query/ATestGrandTotalComparison.java
@@ -105,7 +105,7 @@ public abstract class ATestGrandTotalComparison extends ABaseTestQuery {
   }
 
   @Test
-  void testCrossjoinWithOtherColumnAnFilters() {
+  void testCrossjoinWithOtherColumnAndFilters() {
     // Filter on other category
     QueryDto query = Query
             .from(this.storeName)
@@ -136,4 +136,24 @@ public abstract class ATestGrandTotalComparison extends ABaseTestQuery {
             Arrays.asList("home", "eu", "france", "lyon", 2d, 2d / gt),
             Arrays.asList("home", "eu", "france", "paris", 2d, 2d / gt));
   }
+
+  @Test
+  void testFiltersNotCleared() {
+    ComparisonMeasureGrandTotal percentOfGT = new ComparisonMeasureGrandTotal("percentOfParent", ComparisonMethod.DIVIDE, this.amount);
+    percentOfGT.clearFilters = false;
+    List<Field> fields = tableFields(List.of("country", "city"));
+    QueryDto query = Query
+            .from(this.storeName)
+            .where(Functions.criterion(tableField("country"), Functions.eq("france")))
+            .select(fields, List.of(this.amount, percentOfGT))
+            .rollup(fields)
+            .build();
+
+    Table result = this.executor.executeQuery(query);
+    Assertions.assertThat(result).containsExactly(
+            Arrays.asList(GRAND_TOTAL, GRAND_TOTAL, 7.1d, 1d),
+            Arrays.asList("france", TOTAL, 7.1d, 1d),
+            Arrays.asList("france", "lyon", 3.1d, .4366197183098592d),
+            Arrays.asList("france", "paris", 4d, .5633802816901409d));
+  }
 }
diff --git a/core/src/test/java/io/squashql/query/ATestParentComparison.java b/core/src/test/java/io/squashql/query/ATestParentComparison.java
index 808f43b..5900bb2 100644
--- a/core/src/test/java/io/squashql/query/ATestParentComparison.java
+++ b/core/src/test/java/io/squashql/query/ATestParentComparison.java
@@ -135,6 +135,30 @@ public abstract class ATestParentComparison extends ABaseTestQuery {
             Arrays.asList("eu", null, "monaco", 1d));
   }
 
+  @Test
+  void testFiltersNotCleared() {
+    Measure pop = Functions.sum("population", this.population);
+    List<Field> fields = List.of(this.continent, this.country, this.city);
+    ComparisonMeasureReferencePosition pOp = new ComparisonMeasureReferencePosition("percentOfParent", DIVIDE, pop, fields);
+    pOp.clearFilters = false;
+
+    QueryDto query = Query
+            .from(this.storeName)
+            .where(criterion(this.country, eq("canada")))
+            .select(List.of(this.country, this.city), List.of(pOp))
+            .rollup(List.of(this.country, this.city))
+            .build(); // query only parent
+
+    Table result = this.executor.executeQuery(query);
+    Assertions.assertThat(result).containsExactly(
+            Arrays.asList(GRAND_TOTAL, GRAND_TOTAL, 1d),
+            Arrays.asList("canada", TOTAL, 1d),
+            Arrays.asList("canada", "montreal", .5833333333333334d),
+            Arrays.asList("canada", "otawa", .16666666666666666d),
+            Arrays.asList("canada", "toronto", 0.25d)
+    );
+  }
+
   @Test
   void testWithMissingAncestor() {
     Measure pop = Functions.sum("population", this.population);
diff --git a/core/src/test/java/io/squashql/query/ATestPartialHierarchicalMeasureComparison.java b/core/src/test/java/io/squashql/query/ATestPartialHierarchicalMeasureComparison.java
index 2e75e6c..91dc9d8 100644
--- a/core/src/test/java/io/squashql/query/ATestPartialHierarchicalMeasureComparison.java
+++ b/core/src/test/java/io/squashql/query/ATestPartialHierarchicalMeasureComparison.java
@@ -109,6 +109,49 @@ public abstract class ATestPartialHierarchicalMeasureComparison extends ABaseTes
             Arrays.asList("eu", "uk", "london", 10d, 10d / 21d, 2 * 10d / 21d));
   }
 
+  @Test
+  void testPercentOfTotalOfAxisClearFilters() {
+    Measure pop = Functions.sum("amount", this.amount);
+    List<Field> fields = List.of(this.continent, this.country, this.city);
+    Measure pOp = comparisonMeasureWithTotalOfAxis("percentOfParent", DIVIDE, pop, COLUMN);
+    QueryDto query = Query
+            .from(this.storeName)
+            .where(criterion(this.country, eq("france")))
+            .select(fields, List.of(pop, pOp))
+            .rollup(fields)
+            .build();
+
+    Table result = this.executor.executeQuery(query);
+    Assertions.assertThat(result).containsExactly(
+            Arrays.asList(GRAND_TOTAL, GRAND_TOTAL, GRAND_TOTAL, 11d, .5238095238095238d),
+            Arrays.asList("eu", TOTAL, TOTAL, 11d, 11d / 21d),
+            Arrays.asList("eu", "france", TOTAL, 11d, 11d / 21d),
+            Arrays.asList("eu", "france", "lyon", 4d, 4d / 21d),
+            Arrays.asList("eu", "france", "paris", 7d, 7d / 21d));
+  }
+
+  @Test
+  void testPercentOfTotalOfAxisFiltersNotCleared() {
+    Measure pop = Functions.sum("amount", this.amount);
+    List<Field> fields = List.of(this.continent, this.country, this.city);
+    PartialHierarchicalComparisonMeasure pOp = comparisonMeasureWithTotalOfAxis("percentOfParent", DIVIDE, pop, COLUMN);
+    pOp.clearFilters = false;
+    QueryDto query = Query
+            .from(this.storeName)
+            .where(criterion(this.country, eq("france")))
+            .select(fields, List.of(pop, pOp))
+            .rollup(fields)
+            .build();
+
+    Table result = this.executor.executeQuery(query);
+    Assertions.assertThat(result).containsExactly(
+            Arrays.asList(GRAND_TOTAL, GRAND_TOTAL, GRAND_TOTAL, 11d, 1d),
+            Arrays.asList("eu", TOTAL, TOTAL, 11d, 11d / 11d),
+            Arrays.asList("eu", "france", TOTAL, 11d, 11d / 11d),
+            Arrays.asList("eu", "france", "lyon", 4d, 4d / 11d),
+            Arrays.asList("eu", "france", "paris", 7d, 7d / 11d));
+  }
+
   @Test
   void testCompareWithParentOfColumnPivotTable(TestInfo testInfo) {
     Measure pop = Functions.sum("amount", this.amount);
diff --git a/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts b/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
index a6c160a..c6e2dc4 100644
--- a/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
+++ b/js/typescript-library/src/__tests__/dependencies/computeMeasureDependencies.test.ts
@@ -56,7 +56,7 @@ describe('computeMeasureDependencies', () => {
 
   it('should compute dependencies for ComparisonMeasureReferencePosition', () => {
     const array = []
-    const measure = new ComparisonMeasureReferencePosition('alias', ComparisonMethod.ABSOLUTE_DIFFERENCE, mockMeasure1, new Map([[mockField1, 'value1']]))
+    const measure = new ComparisonMeasureReferencePosition('alias', ComparisonMethod.ABSOLUTE_DIFFERENCE, true, mockMeasure1, new Map([[mockField1, 'value1']]))
     const result = dependencies.computeMeasureDependencies(measure, array)
 
     expect(result).toEqual(expect.arrayContaining([mockField1]))
@@ -69,6 +69,7 @@ describe('computeMeasureDependencies', () => {
     const measure = new ComparisonMeasureReferencePosition(
             'alias',
             ComparisonMethod.ABSOLUTE_DIFFERENCE,
+            true,
             mockMeasure1,
             referencePosition,
             ColumnSetKey.GROUP,
@@ -105,7 +106,7 @@ describe('computeMeasureDependencies', () => {
 
   it('should compute dependencies for ComparisonMeasureGrandTotal', () => {
     const underlying = new BinaryOperationMeasure('alias', BinaryOperator.PLUS, mockMeasure1, mockMeasure2)
-    const measure = new ComparisonMeasureGrandTotal('alias', ComparisonMethod.DIVIDE, underlying)
+    const measure = new ComparisonMeasureGrandTotal('alias', ComparisonMethod.DIVIDE, true, underlying)
     const array = []
     const result = dependencies.computeMeasureDependencies(measure, array)
 
diff --git a/js/typescript-library/src/__tests__/s13n.test.ts b/js/typescript-library/src/__tests__/s13n.test.ts
index 83e3474..b591e1b 100644
--- a/js/typescript-library/src/__tests__/s13n.test.ts
+++ b/js/typescript-library/src/__tests__/s13n.test.ts
@@ -78,9 +78,8 @@ const incrVar95 = new ParametrizedMeasure("incr var measure", "INCREMENTAL_VAR",
   "quantile": 0.95,
   "ancestors": [a, b, c],
 })
-const percentOfParentAlongAncestors = new PartialHierarchicalComparisonMeasure("pop along ancestors", ComparisonMethod.DIVIDE, sumA, Axis.ROW, false)
-const compareWithGrandTotalAlongAncestors = new PartialHierarchicalComparisonMeasure("gt along ancestors", ComparisonMethod.DIVIDE, sumA, Axis.ROW, false)
-
+const percentOfParentAlongAncestors = new PartialHierarchicalComparisonMeasure("pop along ancestors", true, ComparisonMethod.DIVIDE, sumA, Axis.ROW, false)
+const compareWithGrandTotalAlongAncestors = new PartialHierarchicalComparisonMeasure("gt along ancestors", false, ComparisonMethod.DIVIDE, sumA, Axis.ROW, false)
 
 describe('serialization', () => {