diff --git a/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/CECommands.java b/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/CECommands.java
index 867a73a054a4f09496a1a52fb7aeea6116f73a92..332f1ecbe8ba7349cf09a8fd4c82142f3e3ed523 100644
--- a/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/CECommands.java
+++ b/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/CECommands.java
@@ -15,7 +15,6 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.function.Supplier;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.jline.builtins.Less;
@@ -1295,7 +1294,7 @@ public class CECommands {
 			FederatedFactBase federation;
 
 			try {
-				federation = new FederatedFactBase(StorageBuilder.defaultStorage(), ViewBuilder.createFactBases(this.mappingFilePath));
+				federation = new FederatedFactBase(StorageBuilder.defaultStorage(), ViewBuilder.loadDataSources(this.mappingFilePath));
 			} catch (ViewBuilder.ViewBuilderException e) {
 				IGRepl.writeIfVerbose("An error occurred while creating the federation using the view definition file.\n", PrintLevel.MAXIMAL);
 				IGRepl.writeIfVerbose(e.getMessage(), PrintLevel.MAXIMAL);
diff --git a/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/ComplexEnvironment.java b/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/ComplexEnvironment.java
index a7b0a4843bc0ce82a1fd5e4e46e9f35bcb088ce2..1442b4511d19ac9d78e476c05a8c68450ab1e960 100644
--- a/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/ComplexEnvironment.java
+++ b/integraal/integraal-api/src/main/java/fr/boreal/api/integraal_repl/ComplexEnvironment.java
@@ -9,8 +9,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import fr.boreal.api.integraal_repl.CECommands.ComplexEnvironmentCommands;
-import fr.boreal.api.integraal_repl.ComplexEnvironment.WriteMode;
 import fr.boreal.api.integraal_repl.IGRepl.PrintLevel;
 import fr.boreal.io.api.ParseException;
 import fr.boreal.io.dlgp.Directive;
@@ -27,7 +25,6 @@ import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
 import fr.boreal.model.query.api.FOQuery;
 import fr.boreal.model.query.api.Query;
 import fr.boreal.model.rule.api.FORule;
-import fr.boreal.storage.builder.StorageBuilder;
 import fr.boreal.storage.natives.SimpleInMemoryGraphStore;
 import fr.boreal.views.FederatedFactBase;
 import fr.boreal.views.builder.ViewBuilder;
@@ -540,7 +537,7 @@ public class ComplexEnvironment {
 						FederatedFactBase federation;
 						if (factbase == null) factbase = new SimpleInMemoryGraphStore();
 						try {
-							federation = new FederatedFactBase(factbase, ViewBuilder.createFactBases(vdPath.toString()));
+							federation = new FederatedFactBase(factbase, ViewBuilder.loadDataSources(vdPath.toString()));
 							this.putFactBase(factBaseName, federation, mode);
 						} catch (ViewBuilderException e) {
 							IGRepl.writeIfVerbose("An error occurred while parsing the view definition file. Skipping.\n", PrintLevel.MAXIMAL);
diff --git a/integraal/integraal-api/src/test/java/fr/boreal/explanation/api/EndUserAPITest.java b/integraal/integraal-api/src/test/java/fr/boreal/explanation/api/EndUserAPITest.java
index 42b6f7a5561b811ece928d0591a0ada06b291b79..269479bcd1952504921940bf0a08dab63ffc3fce 100644
--- a/integraal/integraal-api/src/test/java/fr/boreal/explanation/api/EndUserAPITest.java
+++ b/integraal/integraal-api/src/test/java/fr/boreal/explanation/api/EndUserAPITest.java
@@ -64,7 +64,7 @@ class EndUserAPITest {
 		c.createStatement().execute("INSERT INTO p VALUES('e', 'e');");
 
 		federation = new FederatedFactBase(StorageBuilder.defaultStorage(),
-				ViewBuilder.createFactBases(viewDefinitionFile.toString()));
+				ViewBuilder.loadDataSources(viewDefinitionFile.toString()));
 
 		ParserResult parserResult = DlgpParser.parseFile(dlgpFile.toString());
 		memory_save = parserResult.atoms();
diff --git a/integraal/integraal-api/src/test/java/views/ViewTest.java b/integraal/integraal-api/src/test/java/views/ViewTest.java
index 210c094d4f9492fadb67337a1a9e95c895de2bfe..ef42d7327af300ade9e3670d3021cfc3266909c9 100644
--- a/integraal/integraal-api/src/test/java/views/ViewTest.java
+++ b/integraal/integraal-api/src/test/java/views/ViewTest.java
@@ -6,6 +6,7 @@ import java.util.stream.Stream;
 
 import fr.boreal.model.data.readable.exception.EvaluationException;
 import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.views.datasource.DataSource;
 import org.junit.Assert;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -27,7 +28,7 @@ import fr.boreal.query_evaluation.generic.GenericFOQueryEvaluator;
 import fr.boreal.storage.builder.StorageBuilder;
 import fr.boreal.views.FederatedFactBase;
 import fr.boreal.views.builder.ViewBuilder;
-import fr.boreal.views.datasource.AbstractViewWrapper;
+import fr.boreal.views.datasource.AbstractDataSource;
 
 @RunWith(Parameterized.class)
 class ViewTest {
@@ -59,7 +60,7 @@ class ViewTest {
     @ParameterizedTest(name = "{index}: querying {1} on {0} should work ...")
     @MethodSource("data")
     public void dlgpViewSupportWithQueryEvaluation(String vdFilePath, FOQuery<?> query) throws ViewBuilder.ViewBuilderException {
-        Collection<AbstractViewWrapper<String, ?>> wrappers = ViewBuilder.createFactBases(vdFilePath);
+        Collection<DataSource<String, ?>> wrappers = ViewBuilder.loadDataSources(vdFilePath);
         FederatedFactBase fb = new FederatedFactBase(StorageBuilder.defaultStorage(), wrappers);
         Iterator<Substitution> results = null;
         try {
@@ -79,7 +80,7 @@ class ViewTest {
     @ParameterizedTest(name = "{index}: querying {1} on {0} should work ...")
     @MethodSource("data")
     public void dlgpViewSupportWithAPIQueryEvaluation(String vdFilePath, FOQuery<?> query) throws ViewBuilder.ViewBuilderException {
-        Collection<AbstractViewWrapper<String, ?>> wrappers = ViewBuilder.createFactBases(vdFilePath);
+        Collection<DataSource<String, ?>> wrappers = ViewBuilder.loadDataSources(vdFilePath);
         FederatedFactBase fb = new FederatedFactBase(StorageBuilder.defaultStorage(), wrappers);
         var results = EndUserAPI.evaluateOld(fb, query);
         int count = 0;
diff --git a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/ChaseComponentBuilder.java b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/ChaseComponentBuilder.java
index 4ab33e367ce2bd683f2c263653e8800a8f3f0582..0589ca389a95a7d205389a4532531e3e10c78749 100644
--- a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/ChaseComponentBuilder.java
+++ b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/ChaseComponentBuilder.java
@@ -26,9 +26,9 @@ public class ChaseComponentBuilder {
 	 *
 	 * @return the prepared instance of the Chase algorithm.
 	 */
-	public static Chase prepareAndGetChaseFrom(FactBase fb, RuleBase rb, IAlgorithmParameters chaseParams) {
+	public static Chase<FactBase> prepareAndGetChaseFrom(FactBase fb, RuleBase rb, IAlgorithmParameters chaseParams) {
 
-		ChaseBuilder builder = ChaseBuilder.defaultBuilder(fb, rb);
+		ChaseBuilder<FactBase> builder = ChaseBuilder.defaultBuilder(fb, rb);
 
 		// SCHEDULER
 
@@ -98,9 +98,7 @@ public class ChaseComponentBuilder {
 			builder.addHaltingConditions(new Timeout(timeout.get().toMillis()));
 		}
 
-		Chase customizedChase = builder.build().get();
-
-		return customizedChase;
+        return builder.build().orElseThrow();
 
 	}
 
diff --git a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/FactBaseLoaderFromFile.java b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/FactBaseLoaderFromFile.java
index d77fb2a764f2ee15496f79f43ad8c0b3811aa2f0..e441913359ab55aee06e245f3998ae6383fae201 100644
--- a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/FactBaseLoaderFromFile.java
+++ b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/components/FactBaseLoaderFromFile.java
@@ -80,7 +80,7 @@ public class FactBaseLoaderFromFile {
 	public static FactBase getFederatedFactbaseFor(IInputDataScenario kbscenario,
 												   IAlgorithmParameters integraalAlgorithmParameters) {
 		try {
-			return new FederatedFactBase(StorageBuilder.defaultStorage(), ViewBuilder.createFactBases(kbscenario.getMappingbasePaths().get()));
+			return new FederatedFactBase(StorageBuilder.defaultStorage(), ViewBuilder.loadDataSources(kbscenario.getMappingbasePaths().get()));
 		} catch (ViewBuilder.ViewBuilderException e) {
 			LOG.error(e.getMessage());
 			throw new RuntimeException(
diff --git a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/operations/ChaseRunOperationResult.java b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/operations/ChaseRunOperationResult.java
index b33fb6aa94248320550b865af58c7a138ed4082d..96a14e41120f245f6f8cd16febfdc2303542e5d8 100644
--- a/integraal/integraal-component/src/main/java/fr/boreal/component_builder/operations/ChaseRunOperationResult.java
+++ b/integraal/integraal-component/src/main/java/fr/boreal/component_builder/operations/ChaseRunOperationResult.java
@@ -4,6 +4,7 @@ import java.io.Serializable;
 
 import fr.boreal.component_builder.api.IOperationResult;
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.kb.api.FactBase;
 
 /**
  * records the size of the chase result
@@ -18,8 +19,8 @@ public record ChaseRunOperationResult(long size) implements IOperationResult, Se
 	 * 
 	 * @param chase
 	 */
-	public ChaseRunOperationResult(Chase chase) {
-		this(chase.getFactBase().size());
+	public ChaseRunOperationResult(Chase<?> chase) {
+		this(chase.getChasableData().getWritingTarget().size());
 	}
 
 	public String serializationString() {
diff --git a/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceAndVariableCoreProcessor.java b/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceAndVariableCoreProcessor.java
index b5bdd59ef33da19dc5e89b73f971857aa20c3881..61708d79888890691692be67f93bd91e41c472b3 100644
--- a/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceAndVariableCoreProcessor.java
+++ b/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceAndVariableCoreProcessor.java
@@ -37,7 +37,7 @@ import java.util.stream.Collectors;
  */
 
 
-public class ByPieceAndVariableCoreProcessor implements CoreProcessor {
+public class ByPieceAndVariableCoreProcessor implements CoreProcessor<FactBase> {
     private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
 
     public ByPieceAndVariableCoreProcessor() {
diff --git a/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceCoreProcessor.java b/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceCoreProcessor.java
index 35fc984c897aaa361ace01048f2d09c3d24fbea2..484b5735418ae5d3b72deccf8801a181a81bedeb 100644
--- a/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceCoreProcessor.java
+++ b/integraal/integraal-core/src/main/java/fr/boreal/core/ByPieceCoreProcessor.java
@@ -1,10 +1,11 @@
 package fr.boreal.core;
 
+import fr.boreal.model.data.readable.MaterializedData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
 import fr.boreal.model.formula.factory.FOFormulaFactory;
-import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
@@ -38,9 +39,9 @@ import java.util.stream.Collectors;
  *
  */
 
-public class ByPieceCoreProcessor implements CoreProcessor {
+public class ByPieceCoreProcessor<RW extends MaterializedData & Writable> implements CoreProcessor<RW> {
     private final Variant variant; // Variant of the algorithm to use
-    private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
+    private final FOQueryEvaluator<FOFormula, ? super RW> evaluator;
     
     public enum Variant {
         EXHAUSTIVE,
@@ -48,7 +49,7 @@ public class ByPieceCoreProcessor implements CoreProcessor {
         BY_DELETION
     }
 
-    public ByPieceCoreProcessor(Variant variant, FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+    public ByPieceCoreProcessor(Variant variant, FOQueryEvaluator<FOFormula, ? super RW> evaluator) {
         this.variant = variant;
         this.evaluator = evaluator;
     }
@@ -57,7 +58,7 @@ public class ByPieceCoreProcessor implements CoreProcessor {
         this(variant, GenericFOQueryEvaluator.defaultInstance());
     }
 
-    public ByPieceCoreProcessor(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+    public ByPieceCoreProcessor(FOQueryEvaluator<FOFormula, ? super RW> evaluator) {
         this(Variant.BY_DELETION, evaluator);
     }
 
@@ -66,7 +67,7 @@ public class ByPieceCoreProcessor implements CoreProcessor {
     }
 
     @Override
-    public void computeCore(FactBase fb, Set<Variable> frozenVariables) {
+    public void computeCore(RW fb, Set<Variable> frozenVariables) {
         // We need to compute the set of all variables that are not frozen
         // The pieces of "a" will be computed with these variables
         Set<Variable> notFrozenVariables = new HashSet<>(
@@ -103,7 +104,7 @@ public class ByPieceCoreProcessor implements CoreProcessor {
     }
 
     private void retractPiecesByDeletion (
-            FactBase fb,
+            RW fb,
             SimpleInMemoryGraphStore p,
             Substitution frozenVariablesSubstitution,
             Set<Variable> frozenVariables) {
@@ -168,7 +169,7 @@ public class ByPieceCoreProcessor implements CoreProcessor {
     }
 
     private void retractPiecesBySpecialisation (
-            FactBase fb,
+            RW fb,
             SimpleInMemoryGraphStore p,
             Substitution frozenVariablesSubstitution,
             Set<Variable> frozenVariables) {
@@ -245,11 +246,11 @@ public class ByPieceCoreProcessor implements CoreProcessor {
             }
         }
 
-        removeFromFactBase(toRemove, p, fb);
+        removeFromRW(toRemove, p, fb);
     }
 
     private void retractPiecesExhaustive (
-            FactBase fb,
+            RW fb,
             SimpleInMemoryGraphStore p,
             Substitution frozenVariablesSubstitution,
             Set<Variable> frozenVariables) {
@@ -300,10 +301,10 @@ public class ByPieceCoreProcessor implements CoreProcessor {
             }
         }
 
-        removeFromFactBase(toRemove, p, fb);
+        removeFromRW(toRemove, p, fb);
     }
 
-    private void removeFromFactBase(Set<Variable> toRemove, SimpleInMemoryGraphStore p, FactBase fb) {
+    private void removeFromRW(Set<Variable> toRemove, SimpleInMemoryGraphStore p, RW fb) {
         for (Variable v : toRemove) {
             Iterator<Atom> it_var = p.getAtomsByTerm(v).iterator();
             while (it_var.hasNext()) {
diff --git a/integraal/integraal-core/src/main/java/fr/boreal/core/CoreProcessor.java b/integraal/integraal-core/src/main/java/fr/boreal/core/CoreProcessor.java
index c045c6d16c3a20cd50a764780edce8136e0a7f45..caa14aa385f77c1708cef8d7c670ed9c81e88564 100644
--- a/integraal/integraal-core/src/main/java/fr/boreal/core/CoreProcessor.java
+++ b/integraal/integraal-core/src/main/java/fr/boreal/core/CoreProcessor.java
@@ -1,5 +1,7 @@
 package fr.boreal.core;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Variable;
 
@@ -15,22 +17,22 @@ import java.util.Set;
  *
  */
 
-public interface CoreProcessor {
+public interface CoreProcessor<RW extends MaterializedData & Writable> {
     /**
      * Compute the core of a fact base by removing all the redundant atoms in it
      *
-     * @param fb the fact base on which we want to compute the core
+     * @param writableData the data on which we want to compute the core
      */
-    default void computeCore(FactBase fb) {
-        computeCore(fb, new HashSet<>());
+    default void computeCore(RW writableData) {
+        computeCore(writableData, new HashSet<>());
     }
 
     /**
      * Compute the core of a fact base by removing all the redundant atoms in it, in considering the frozen variables as constants,
      * these variables must belong to the core.
      *
-     * @param fb the fact base on which we want to compute the core
+     * @param writableData the writable data on which we want to compute the core
      * @param frozenVariables Variables that will be treated as constants
      */
-    void computeCore(FactBase fb, Set<Variable> frozenVariables);
+    void computeCore(RW writableData, Set<Variable> frozenVariables);
 }
diff --git a/integraal/integraal-core/src/main/java/fr/boreal/core/MultiThreadsByPieceCoreProcessor.java b/integraal/integraal-core/src/main/java/fr/boreal/core/MultiThreadsByPieceCoreProcessor.java
index e5465a4ba8e66c0f136f60d1bb26284c73b68762..a7a2387d8622e2cc9867b8218152d8ad7e306e2e 100644
--- a/integraal/integraal-core/src/main/java/fr/boreal/core/MultiThreadsByPieceCoreProcessor.java
+++ b/integraal/integraal-core/src/main/java/fr/boreal/core/MultiThreadsByPieceCoreProcessor.java
@@ -1,10 +1,11 @@
 package fr.boreal.core;
 
+import fr.boreal.model.data.readable.MaterializedData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
 import fr.boreal.model.formula.factory.FOFormulaFactory;
-import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
@@ -43,12 +44,12 @@ import java.util.stream.Collectors;
  *
  */
 
-public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
-    private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
+public class MultiThreadsByPieceCoreProcessor<RW extends MaterializedData & Writable> implements CoreProcessor<RW> {
+    private final FOQueryEvaluator<FOFormula, ? super RW> evaluator;
     Set<Variable> deletedVariables; // Set of variables that will be deleted at the end of the execution
     Set<Variable> frozenVariables; // Set of variables that will not be retracted
     Set<Variable> notFrozenVariables; // Complementary of frozenVariables
-    FactBase target; // Fact base on which we compute the core
+    RW target; // Fact base on which we compute the core
 
     Queue<SimpleInMemoryGraphStore> piecesQueue; // Queue to send pieces to the threads
     List<Thread> threads; // List of the threads
@@ -68,7 +69,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
      * @param limitNbThreads Maximum number of threads
      * @param variant Variant of the algorithm
      */
-    public MultiThreadsByPieceCoreProcessor(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator, long limitNbThreads, Variant variant) {
+    public MultiThreadsByPieceCoreProcessor(FOQueryEvaluator<FOFormula, ? super RW> evaluator, long limitNbThreads, Variant variant) {
         this.evaluator = evaluator;
         this.variant = variant;
         this.limitNbThreads = limitNbThreads;
@@ -88,7 +89,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
      * @param limitNbThreads Maximum number of threads
      * @param evaluator Query evaluator
      */
-    public MultiThreadsByPieceCoreProcessor(long limitNbThreads, FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+    public MultiThreadsByPieceCoreProcessor(long limitNbThreads, FOQueryEvaluator<FOFormula, ? super RW> evaluator) {
         this(evaluator, limitNbThreads, Variant.BY_DELETION);
     }
 
@@ -97,7 +98,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
     }
 
     @Override
-    public void computeCore(FactBase fb, Set<Variable> frozenVariables) {
+    public void computeCore(RW fb, Set<Variable> frozenVariables) {
         // We initialize the attributes of the object
         init(fb, frozenVariables);
 
@@ -142,7 +143,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
      * @param fb the fact base which we compute the core
      * @param frozenVariables Set of variables that will not be retracted
      */
-    private void init(FactBase fb, Set<Variable> frozenVariables) {
+    private void init(RW fb, Set<Variable> frozenVariables) {
         // We need to compute the set of all variables that are not frozen
         // The pieces of "a" will be computed with these variables
         notFrozenVariables = new HashSet<>();
@@ -226,7 +227,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
         }
     }
 
-    private Iterator<Substitution> computeHomomorphismsToFactBase(
+    private Iterator<Substitution> computeHomomorphismsToRW(
             SimpleInMemoryGraphStore p, Substitution frozenVariablesSubstitution) {
         FOQuery<FOFormulaConjunction> q = FOQueryFactory.instance().createOrGetQuery(
                 FOFormulaFactory.instance().createOrGetConjunction(p), null);
@@ -262,7 +263,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
     private void retractPiecesExhaustive (SimpleInMemoryGraphStore p, Substitution frozenVariablesSubstitution)
             throws InterruptedException {
         // We get an iterator on the retractions of the piece into the atom set target
-        Iterator<Substitution> it = computeHomomorphismsToFactBase(p, frozenVariablesSubstitution);
+        Iterator<Substitution> it = computeHomomorphismsToRW(p, frozenVariablesSubstitution);
 
         // Variables of p
         Set<Variable> pVars = p.getVariables().collect(Collectors.toSet());
@@ -316,7 +317,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
     private void retractPiecesByDeletion (SimpleInMemoryGraphStore p, Substitution frozenVariablesSubstitution)
             throws InterruptedException {
         // We get an iterator on the retractions of the piece into the atom set target
-        Iterator<Substitution> it = computeHomomorphismsToFactBase(p, frozenVariablesSubstitution);
+        Iterator<Substitution> it = computeHomomorphismsToRW(p, frozenVariablesSubstitution);
 
         // Variables of p
         Set<Variable> pVars = p.getVariables().collect(Collectors.toSet());
@@ -372,7 +373,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
                     pVars.removeAll(deletedVars);
 
                     // And we begin new research of retractions
-                    it = computeHomomorphismsToFactBase(p, frozenVariablesSubstitution);
+                    it = computeHomomorphismsToRW(p, frozenVariablesSubstitution);
                 }
             }
         }
@@ -381,7 +382,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
     private void retractPiecesBySpecialisation (SimpleInMemoryGraphStore p, Substitution frozenVariablesSubstitution)
             throws InterruptedException {
         // We get an iterator on the retractions of the piece into the atom set target
-        Iterator<Substitution> it = computeHomomorphismsToFactBase(p, frozenVariablesSubstitution);
+        Iterator<Substitution> it = computeHomomorphismsToRW(p, frozenVariablesSubstitution);
 
         // Variables of p
         Set<Variable> pVars = p.getVariables().collect(Collectors.toSet());
@@ -447,7 +448,7 @@ public class MultiThreadsByPieceCoreProcessor implements CoreProcessor {
                     }
 
                     // And we begin new research of retractions
-                    it = computeHomomorphismsToFactBase(p, frozenVariablesSubstitution);
+                    it = computeHomomorphismsToRW(p, frozenVariablesSubstitution);
                 }
             }
         }
diff --git a/integraal/integraal-core/src/main/java/fr/boreal/core/NaiveCoreProcessor.java b/integraal/integraal-core/src/main/java/fr/boreal/core/NaiveCoreProcessor.java
index 9e8642c550dc0cc5b9c991e22a339fb12bd70d1b..be16e16e6ecf77656a7674027ac5fdcb7bc0886a 100644
--- a/integraal/integraal-core/src/main/java/fr/boreal/core/NaiveCoreProcessor.java
+++ b/integraal/integraal-core/src/main/java/fr/boreal/core/NaiveCoreProcessor.java
@@ -19,7 +19,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-public class NaiveCoreProcessor implements CoreProcessor {
+public class NaiveCoreProcessor implements CoreProcessor<FactBase> {
     private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
 
     public NaiveCoreProcessor() {
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/Chase.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/Chase.java
index 35ad932f9c63ad8a6cd93ec719ce13d571171c37..a6786264fa5d9e53592c3b93d0f28793b57544c3 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/Chase.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/Chase.java
@@ -1,16 +1,19 @@
 package fr.boreal.forward_chaining.chase;
 
 import fr.boreal.forward_chaining.api.ForwardChainingAlgorithm;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.rule_scheduler.RuleScheduler;
-import fr.boreal.model.kb.api.FactBase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.RuleBase;
 
 /**
- * The Chase is a way to saturate a {@link FactBase} according to rules
+ * The Chase is a way to saturate a {@link ChasableData} according to rules
  *
  * The work done for the modeling and implementation of the Chase is mostly part of Guillaume Pérution-Kihli internship's work (2020)
  */
-public interface Chase extends ForwardChainingAlgorithm {
+public interface Chase<RW extends MaterializedData & Writable> extends ForwardChainingAlgorithm {
 
 	/**
 	 * @return true iff this chase has a next step
@@ -62,9 +65,9 @@ public interface Chase extends ForwardChainingAlgorithm {
 	/////////////////////////////////
 	
 	/**
-	 * @return the factbase of this chase
+	 * @return the ChasableData of this chase
 	 */
-    FactBase getFactBase();
+	ChasableData<RW> getChasableData();
 
 	/**
 	 * @return the rulebase of this chase
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
index 28d087e350720083c13c1895ad0cdea1c84b152e..031fbd4856b69a89a333162828f8fcfbe155e280 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseBuilder.java
@@ -1,5 +1,7 @@
 package fr.boreal.forward_chaining.chase;
 
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.forward_chaining.chase.data.ChasableDataImpl;
 import fr.boreal.forward_chaining.chase.halting_condition.CreatedFactsAtPreviousStep;
 import fr.boreal.forward_chaining.chase.halting_condition.HaltingCondition;
 import fr.boreal.forward_chaining.chase.halting_condition.HasRulesToApply;
@@ -26,6 +28,9 @@ import fr.boreal.forward_chaining.chase.treatment.AddCreatedFacts;
 import fr.boreal.forward_chaining.chase.treatment.Debug;
 import fr.boreal.forward_chaining.chase.treatment.EndTreatment;
 import fr.boreal.forward_chaining.chase.treatment.Pretreatment;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.kb.api.RuleBase;
@@ -42,9 +47,9 @@ import java.util.*;
  *
  * Builder to create a parameterized chase algorithm
  */
-public class ChaseBuilder {
+public class ChaseBuilder<RW extends MaterializedData & Writable> {
 
-	private FactBase fb;
+	private ChasableData<RW> chasableData;
 	private RuleBase rb;
 	private TermFactory tf = FactoryConstants.DEFAULT_TERM_FACTORY;
 
@@ -52,11 +57,11 @@ public class ChaseBuilder {
 	private Scheduler scheduler = Scheduler.GRD;
 	private enum Scheduler {NAIVE, GRD}
 
-	private FOQueryEvaluator<FOFormula, ? super FactBase> eval;
+	private FOQueryEvaluator<FOFormula, QueryableData> eval;
 	private Evaluator evaluator = Evaluator.GENERIC;
 	private enum Evaluator {GENERIC, SMART}
 
-	private RuleApplier ra;
+	private RuleApplier<RW> ra;
 	private Applier applier = Applier.BREADTH_FIRST_TRIGGER;
 	private enum Applier {BREADTH_FIRST_TRIGGER, PARALLEL_TRIGGER, SOURCE_DELEGATED_DATALOG, MULTI_THREAD_TRIGGER}
 
@@ -64,14 +69,14 @@ public class ChaseBuilder {
 	private Transformer transformer = Transformer.FRONTIER;
 	private enum Transformer {ALL, FRONTIER}
 
-	private TriggerComputer tc;
+	private TriggerComputer<RW> tc;
 	private Computer computer = Computer.SEMI_NAIVE;
 	private enum Computer {NAIVE, SEMI_NAIVE, TWO_STEP}
-	private TriggerChecker tch;
+	private TriggerChecker<RW> tch;
 	private Checker checker = Checker.SEMI_OBLIVIOUS;
 	private enum Checker {TRUE, OBLIVIOUS, SEMI_OBLIVIOUS, RESTRICTED, EQUIVALENT}
-	private TriggerApplier ta;
-	private FactsHandler fh;
+	private TriggerApplier<RW> ta;
+	private FactsHandler<RW> fh;
 	private Application application = Application.DIRECT;
 	private enum Application {DIRECT, PARALLEL}
 	private TriggerRenamer renamer;
@@ -79,11 +84,11 @@ public class ChaseBuilder {
 	private enum Skolem {FRESH, BODY, FRONTIER, FRONTIER_PIECE}
 
 
-	private final List<HaltingCondition> hcs = new ArrayList<>();
-	private final List<Pretreatment> global_pts = new ArrayList<>();
-	private final List<Pretreatment> step_pts = new ArrayList<>();
-	private final List<EndTreatment> global_end_ts = new ArrayList<>();
-	private final List<EndTreatment> end_step_ts = new ArrayList<>();
+	private final List<HaltingCondition<RW>> hcs = new ArrayList<>();
+	private final List<Pretreatment<RW>> global_pts = new ArrayList<>();
+	private final List<Pretreatment<RW>> step_pts = new ArrayList<>();
+	private final List<EndTreatment<RW>> global_end_ts = new ArrayList<>();
+	private final List<EndTreatment<RW>> end_step_ts = new ArrayList<>();
 
 	private boolean debug = false;
 
@@ -93,7 +98,7 @@ public class ChaseBuilder {
 
 	/**
 	 * The minimal configuration requires : <br>
-	 * * a FactBase to saturate <br>
+	 * * a QueryableWritableData to saturate <br>
 	 * * a RuleBase to get Rules from <br>
 	 * * a TermFactory to create new terms <br>
 	 * <br>
@@ -111,9 +116,9 @@ public class ChaseBuilder {
 	 *
 	 * @return the created chase or an empty optional if the configuration is incorrect
 	 */
-	public Optional<Chase> build() {
+	public Optional<Chase<RW>> build() {
 		if(this.getMinimalConfig().isPresent()) {
-			return Optional.of(new ChaseImpl(fb, rb, rsc, ra, hcs, global_pts, step_pts, global_end_ts, end_step_ts));
+			return Optional.of(new ChaseImpl<>(chasableData, rb, rsc, ra, hcs, global_pts, step_pts, global_end_ts, end_step_ts));
 		} else {
 			return Optional.empty();
 		}
@@ -129,9 +134,21 @@ public class ChaseBuilder {
 	 * @param rb the rule to apply
 	 * @return the builder initialized with the given parameters
 	 */
-	public static ChaseBuilder defaultBuilder(FactBase fb, RuleBase rb) {
-		return new ChaseBuilder()
-				.setFactBase(fb)
+	public static ChaseBuilder<FactBase> defaultBuilder(FactBase fb, RuleBase rb) {
+		return defaultBuilder(new ChasableDataImpl<>(fb), rb);
+	}
+	
+	/**
+	 * Builder initialized with the default chase and mandatory parameters
+	 * @param chasableData the chasable data to saturate
+	 * @param rb the rule to apply
+	 * @return the builder initialized with the given parameters
+	 */
+	public static <RW extends MaterializedData & Writable> ChaseBuilder<RW> defaultBuilder(
+			ChasableData<RW> chasableData,
+			RuleBase rb) {
+		return new ChaseBuilder<RW>()
+				.setChasableData(chasableData)
 				.setRuleBase(rb);
 	}
 
@@ -141,20 +158,32 @@ public class ChaseBuilder {
 	 * @param rb the rule to apply
 	 * @return the default chase initialized with the given parameters
 	 */
-	public static Chase defaultChase(FactBase fb, RuleBase rb) {
-		return new ChaseBuilder()
-				.setFactBase(fb)
+	public static Chase<FactBase> defaultChase(FactBase fb, RuleBase rb) {
+		return defaultChase(new ChasableDataImpl<>(fb), rb);
+	}
+
+	/**
+	 * Chase initialized with the default parameters and the given mandatory parameters
+	 * @param chasableData the chasable data to saturate
+	 * @param rb the rule to apply
+	 * @return the default chase initialized with the given parameters
+	 */
+	public static <RW extends MaterializedData & Writable> Chase<RW> defaultChase(
+			ChasableData<RW> chasableData,
+			RuleBase rb) {
+		return new ChaseBuilder<RW>()
+				.setChasableData(chasableData)
 				.setRuleBase(rb)
 				.build()
-				.get();
+				.orElseThrow();
 	}
 
 	//////////////////////
 	// Default settings //
 	//////////////////////
 
-	private Optional<ChaseBuilder> getMinimalConfig() {
-		if(this.fb == null) {
+	private Optional<ChaseBuilder<RW>> getMinimalConfig() {
+		if(this.chasableData == null) {
 			return Optional.empty();
 		}
 		if(this.rb == null) {
@@ -186,18 +215,18 @@ public class ChaseBuilder {
 					}
 					if(this.tc == null) {
 						switch (this.computer) {
-							case NAIVE : this.setTriggerComputer(new NaiveTriggerComputer(this.eval)); break;
-							case SEMI_NAIVE : this.setTriggerComputer(new SemiNaiveComputer(this.eval)); break;
-							case TWO_STEP : this.setTriggerComputer(new TwoStepComputer(this.eval)); break;
+							case NAIVE : this.setTriggerComputer(new NaiveTriggerComputer<>(this.eval)); break;
+							case SEMI_NAIVE : this.setTriggerComputer(new SemiNaiveComputer<>(this.eval)); break;
+							case TWO_STEP : this.setTriggerComputer(new TwoStepComputer<>(this.eval)); break;
 						}
 					}
 					if(this.tch == null) {
 						switch (this.checker) {
-							case TRUE : this.setTriggerChecker(new AlwaysTrueChecker()); break;
-							case OBLIVIOUS : this.setTriggerChecker(new ObliviousChecker()); break;
-							case SEMI_OBLIVIOUS : this.setTriggerChecker(new SemiObliviousChecker()); break;
-							case RESTRICTED : this.setTriggerChecker(new RestrictedChecker(this.eval)); break;
-							case EQUIVALENT : this.setTriggerChecker(new EquivalentChecker(this.eval)); break;
+							case TRUE : this.setTriggerChecker(new AlwaysTrueChecker<>()); break;
+							case OBLIVIOUS : this.setTriggerChecker(new ObliviousChecker<>()); break;
+							case SEMI_OBLIVIOUS : this.setTriggerChecker(new SemiObliviousChecker<>()); break;
+							case RESTRICTED : this.setTriggerChecker(new RestrictedChecker<>(this.eval)); break;
+							case EQUIVALENT : this.setTriggerChecker(new EquivalentChecker<>(this.eval)); break;
 						}
 					}
 					if(this.ta == null) {
@@ -211,11 +240,11 @@ public class ChaseBuilder {
 						}
 						if(this.fh == null) {
 							switch(this.application) {
-								case DIRECT : this.setNewFactsHandler(new DirectApplication()); break;
-								case PARALLEL : this.setNewFactsHandler(new DelegatedApplication()); break;
+								case DIRECT : this.setNewFactsHandler(new DirectApplication<>()); break;
+								case PARALLEL : this.setNewFactsHandler(new DelegatedApplication<>()); break;
 							}
 						}
-						this.setTriggerApplier(new TriggerApplierImpl(this.renamer, this.fh));
+						this.setTriggerApplier(new TriggerApplierImpl<>(this.renamer, this.fh));
 					}
 					break;
 				}
@@ -223,20 +252,20 @@ public class ChaseBuilder {
 					break;
 			}
 			switch(this.applier) {
-				case BREADTH_FIRST_TRIGGER : this.setRuleApplier(new BreadthFirstTriggerRuleApplier(this.transf, this.tc, this.tch, this.ta)); break;
-				case PARALLEL_TRIGGER : this.setRuleApplier(new ParallelTriggerRuleApplier(this.transf, this.tc, this.tch, this.ta)); break;
-				case SOURCE_DELEGATED_DATALOG : this.setRuleApplier(new SourceDelegatedDatalogRuleApplier()); break;
-				case MULTI_THREAD_TRIGGER : this.setRuleApplier(new MultiThreadRuleApplier(this.transf, this.tc, this.tch, this.ta)); break;
+				case BREADTH_FIRST_TRIGGER : this.setRuleApplier(new BreadthFirstTriggerRuleApplier<>(this.transf, this.tc, this.tch, this.ta)); break;
+				case PARALLEL_TRIGGER : this.setRuleApplier(new ParallelTriggerRuleApplier<>(this.transf, this.tc, this.tch, this.ta)); break;
+				case SOURCE_DELEGATED_DATALOG : this.setRuleApplier(new SourceDelegatedDatalogRuleApplier<>()); break;
+				case MULTI_THREAD_TRIGGER : this.setRuleApplier(new MultiThreadRuleApplier<>(this.transf, this.tc, this.tch, this.ta)); break;
 			}
 		}
 		if(this.hcs.isEmpty()) {
 			this.addStandardHaltingConditions();
 		}
 		if(this.application == Application.PARALLEL) {
-			this.end_step_ts.addFirst(new AddCreatedFacts());
+			this.end_step_ts.addFirst(new AddCreatedFacts<>());
 		}
 		if(this.debug) {
-			this.addStepEndTreatments(new Debug());
+			this.addStepEndTreatments(new Debug<>());
 		}
 		return Optional.of(this);
 	}
@@ -251,7 +280,7 @@ public class ChaseBuilder {
 	 * Use a breadth first trigger applier
 	 * @return this
 	 */
-	public ChaseBuilder useTriggerRuleApplier() {
+	public ChaseBuilder<RW> useTriggerRuleApplier() {
 		this.applier = Applier.BREADTH_FIRST_TRIGGER;
 		return this;
 	}
@@ -262,7 +291,7 @@ public class ChaseBuilder {
 	 * Use the generic query evaluator
 	 * @return this
 	 */
-	public ChaseBuilder useGenericFOQueryEvaluator() {
+	public ChaseBuilder<RW> useGenericFOQueryEvaluator() {
 		this.evaluator = Evaluator.GENERIC;
 		return this;
 	}
@@ -271,7 +300,7 @@ public class ChaseBuilder {
 	 * Use the smart query evaluator
 	 * @return this
 	 */
-	public ChaseBuilder useSmartFOQueryEvaluator() {
+	public ChaseBuilder<RW> useSmartFOQueryEvaluator() {
 		this.evaluator = Evaluator.SMART;
 		return this;
 	}
@@ -282,7 +311,7 @@ public class ChaseBuilder {
 	 * Use a naive rule scheduler
 	 * @return this
 	 */
-	public ChaseBuilder useNaiveRuleScheduler() {
+	public ChaseBuilder<RW> useNaiveRuleScheduler() {
 		this.scheduler = Scheduler.NAIVE;
 		return this;
 	}
@@ -291,7 +320,7 @@ public class ChaseBuilder {
 	 * Use a rule scheduler based on the GRD
 	 * @return this
 	 */
-	public ChaseBuilder useGRDRuleScheduler() {
+	public ChaseBuilder<RW> useGRDRuleScheduler() {
 		this.scheduler = Scheduler.GRD;
 		return this;
 	}
@@ -302,7 +331,7 @@ public class ChaseBuilder {
 	 * Use a transformation that keep all variables as answer variables when evaluating a rule's body
 	 * @return this
 	 */
-	public ChaseBuilder useAllTransformer() {
+	public ChaseBuilder<RW> useAllTransformer() {
 		this.transformer = Transformer.ALL;
 		return this;
 	}
@@ -311,7 +340,7 @@ public class ChaseBuilder {
 	 * Use a transformation that keep only the variables of the frontier as answer variables when evaluating a rule's body
 	 * @return this
 	 */
-	public ChaseBuilder useFrontierTransformer() {
+	public ChaseBuilder<RW> useFrontierTransformer() {
 		this.transformer = Transformer.FRONTIER;
 		return this;
 	}
@@ -322,7 +351,7 @@ public class ChaseBuilder {
 	 * Use a naive method to compute triggers
 	 * @return this
 	 */
-	public ChaseBuilder useNaiveComputer() {
+	public ChaseBuilder<RW> useNaiveComputer() {
 		this.computer = Computer.NAIVE;
 		return this;
 	}
@@ -331,7 +360,7 @@ public class ChaseBuilder {
 	 * Use the semi naive method to compute triggers
 	 * @return this
 	 */
-	public ChaseBuilder useSemiNaiveComputer() {
+	public ChaseBuilder<RW> useSemiNaiveComputer() {
 		this.computer = Computer.SEMI_NAIVE;
 		return this;
 	}
@@ -340,7 +369,7 @@ public class ChaseBuilder {
 	 * Use the two step method to compute triggers
 	 * @return this
 	 */
-	public ChaseBuilder useTwoStepComputer() {
+	public ChaseBuilder<RW> useTwoStepComputer() {
 		this.computer = Computer.TWO_STEP;
 		return this;
 	}
@@ -351,7 +380,7 @@ public class ChaseBuilder {
 	 * Use a direct application of the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useDirectApplication() {
+	public ChaseBuilder<RW> useDirectApplication() {
 		this.application = Application.DIRECT;
 		this.applier = Applier.BREADTH_FIRST_TRIGGER;
 		return this;
@@ -361,7 +390,7 @@ public class ChaseBuilder {
 	 * Use a parallel application of the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useParallelApplication() {
+	public ChaseBuilder<RW> useParallelApplication() {
 		this.application = Application.PARALLEL;
 		this.applier = Applier.PARALLEL_TRIGGER;
 		return this;
@@ -373,7 +402,7 @@ public class ChaseBuilder {
 	 *
 	 * @return this
 	 */
-	public ChaseBuilder useMultiThreadRuleApplier() {
+	public ChaseBuilder<RW> useMultiThreadRuleApplier() {
 		this.application = Application.PARALLEL;
 		this.applier = Applier.MULTI_THREAD_TRIGGER;
 		return this;
@@ -384,7 +413,7 @@ public class ChaseBuilder {
 	 * Use a method of delegating to the source the application of the datalog rules
 	 * @return this
 	 */
-	public ChaseBuilder useSourceDelegatedDatalogApplication() {
+	public ChaseBuilder<RW> useSourceDelegatedDatalogApplication() {
 		this.applier = Applier.SOURCE_DELEGATED_DATALOG;
 		return this;
 	}
@@ -395,7 +424,7 @@ public class ChaseBuilder {
 	 * Use an always true criteria for the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useAlwaysTrueChecker() {
+	public ChaseBuilder<RW> useAlwaysTrueChecker() {
 		this.checker = Checker.TRUE;
 		return this;
 	}
@@ -404,7 +433,7 @@ public class ChaseBuilder {
 	 * Use a oblivious criteria for the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useObliviousChecker() {
+	public ChaseBuilder<RW> useObliviousChecker() {
 		this.checker = Checker.OBLIVIOUS;
 		return this;
 	}
@@ -413,7 +442,7 @@ public class ChaseBuilder {
 	 * Use a semi oblivious criteria for the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useSemiObliviousChecker() {
+	public ChaseBuilder<RW> useSemiObliviousChecker() {
 		this.checker = Checker.SEMI_OBLIVIOUS;
 		return this;
 	}
@@ -422,7 +451,7 @@ public class ChaseBuilder {
 	 * Use a restricted criteria for the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useRestrictedChecker() {
+	public ChaseBuilder<RW> useRestrictedChecker() {
 		this.checker = Checker.RESTRICTED;
 		return this;
 	}
@@ -431,7 +460,7 @@ public class ChaseBuilder {
 	 * Use an equivalent criteria for the triggers
 	 * @return this
 	 */
-	public ChaseBuilder useEquivalentChecker() {
+	public ChaseBuilder<RW> useEquivalentChecker() {
 		this.checker = Checker.EQUIVALENT;
 		return this;
 	}
@@ -442,7 +471,7 @@ public class ChaseBuilder {
 	 * Use a fresh name for the existentials
 	 * @return this
 	 */
-	public ChaseBuilder useFreshNaming() {
+	public ChaseBuilder<RW> useFreshNaming() {
 		this.skolem = Skolem.FRESH;
 		return this;
 	}
@@ -451,7 +480,7 @@ public class ChaseBuilder {
 	 * Use a skolem of the body as name for the existentials
 	 * @return this
 	 */
-	public ChaseBuilder useBodySkolem() {
+	public ChaseBuilder<RW> useBodySkolem() {
 		this.skolem = Skolem.BODY;
 		return this;
 	}
@@ -460,7 +489,7 @@ public class ChaseBuilder {
 	 * Use a skolem of the body, limited to the frontier as name for the existentials
 	 * @return this
 	 */
-	public ChaseBuilder useFrontierSkolem() {
+	public ChaseBuilder<RW> useFrontierSkolem() {
 		this.skolem = Skolem.FRONTIER;
 		return this;
 	}
@@ -469,7 +498,7 @@ public class ChaseBuilder {
 	 * Use a skolem of the body, limited to the frontier of the piece as name for the existentials
 	 * @return this
 	 */
-	public ChaseBuilder useFrontierByPieceSkolem() {
+	public ChaseBuilder<RW> useFrontierByPieceSkolem() {
 		this.skolem = Skolem.FRONTIER_PIECE;
 		return this;
 	}
@@ -479,12 +508,12 @@ public class ChaseBuilder {
 	/////////////
 
 	/**
-	 * Sets the FactBase
-	 * @param fb the FactBase
+	 * Sets the QueryableWritableData
+	 * @param chasableData the chasable data
 	 * @return this
 	 */
-	public ChaseBuilder setFactBase(FactBase fb) {
-		this.fb = fb;
+	public ChaseBuilder<RW> setChasableData(ChasableData<RW> chasableData) {
+		this.chasableData = chasableData;
 		return this;
 	}
 
@@ -493,7 +522,7 @@ public class ChaseBuilder {
 	 * @param rb the RuleBase
 	 * @return this
 	 */
-	public ChaseBuilder setRuleBase(RuleBase rb) {
+	public ChaseBuilder<RW> setRuleBase(RuleBase rb) {
 		this.rb = rb;
 		return this;
 	}
@@ -503,7 +532,7 @@ public class ChaseBuilder {
 	 * @param tf the TermFactory
 	 * @return this
 	 */
-	public ChaseBuilder setTermFactory(TermFactory tf) {
+	public ChaseBuilder<RW> setTermFactory(TermFactory tf) {
 		this.tf = tf;
 		return this;
 	}
@@ -513,7 +542,7 @@ public class ChaseBuilder {
 	 * @param rsc the RuleScheduler
 	 * @return this
 	 */
-	public ChaseBuilder setRuleScheduler(RuleScheduler rsc) {
+	public ChaseBuilder<RW> setRuleScheduler(RuleScheduler rsc) {
 		this.rsc = rsc;
 		return this;
 	}
@@ -523,7 +552,8 @@ public class ChaseBuilder {
 	 * @param eval the FOQueryEvaluator
 	 * @return this
 	 */
-	public ChaseBuilder setFOQueryEvaluator(FOQueryEvaluator<FOFormula, ? super FactBase> eval) {
+	public ChaseBuilder<RW> setFOQueryEvaluator(
+			FOQueryEvaluator<FOFormula, QueryableData> eval) {
 		this.eval = eval;
 		return this;
 	}
@@ -533,7 +563,7 @@ public class ChaseBuilder {
 	 * @param ra the RuleApplier
 	 * @return this
 	 */
-	public ChaseBuilder setRuleApplier(RuleApplier ra) {
+	public ChaseBuilder<RW> setRuleApplier(RuleApplier<RW> ra) {
 		this.ra = ra;
 		return this;
 	}
@@ -545,7 +575,7 @@ public class ChaseBuilder {
 	 * @param transf the BodyToQueryTransformer
 	 * @return this
 	 */
-	public ChaseBuilder setBodyToQueryTransformer(BodyToQueryTransformer transf) {
+	public ChaseBuilder<RW> setBodyToQueryTransformer(BodyToQueryTransformer transf) {
 		this.transf = transf;
 		return this;
 	}
@@ -555,7 +585,7 @@ public class ChaseBuilder {
 	 * @param tc the TriggerComputer
 	 * @return this
 	 */
-	public ChaseBuilder setTriggerComputer(TriggerComputer tc) {
+	public ChaseBuilder<RW> setTriggerComputer(TriggerComputer<RW> tc) {
 		this.tc = tc;
 		return this;
 	}
@@ -565,7 +595,7 @@ public class ChaseBuilder {
 	 * @param tch the TriggerChecker
 	 * @return this
 	 */
-	public ChaseBuilder setTriggerChecker(TriggerChecker tch) {
+	public ChaseBuilder<RW> setTriggerChecker(TriggerChecker<RW> tch) {
 		this.tch = tch;
 		return this;
 	}
@@ -575,7 +605,7 @@ public class ChaseBuilder {
 	 * @param ta the TriggerApplier
 	 * @return this
 	 */
-	public ChaseBuilder setTriggerApplier(TriggerApplier ta) {
+	public ChaseBuilder<RW> setTriggerApplier(TriggerApplier<RW> ta) {
 		this.ta = ta;
 		return this;
 	}
@@ -585,7 +615,7 @@ public class ChaseBuilder {
 	 * @param tr the TriggerRenamer
 	 * @return this
 	 */
-	public ChaseBuilder setExistentialsRenamer(TriggerRenamer tr) {
+	public ChaseBuilder<RW> setExistentialsRenamer(TriggerRenamer tr) {
 		this.renamer = tr;
 		return this;
 	}
@@ -595,7 +625,7 @@ public class ChaseBuilder {
 	 * @param fh the FactsHandler
 	 * @return this
 	 */
-	public ChaseBuilder setNewFactsHandler(FactsHandler fh) {
+	public ChaseBuilder<RW> setNewFactsHandler(FactsHandler<RW> fh) {
 		this.fh = fh;
 		return this;
 	}
@@ -606,8 +636,8 @@ public class ChaseBuilder {
 	 * Adds the standard halting conditions
 	 * @return this
 	 */
-	public ChaseBuilder addStandardHaltingConditions() {
-		this.addHaltingConditions(new CreatedFactsAtPreviousStep(), new HasRulesToApply());
+	public ChaseBuilder<RW> addStandardHaltingConditions() {
+		this.addHaltingConditions(new CreatedFactsAtPreviousStep<>(), new HasRulesToApply<>());
 		return this;
 	}
 
@@ -616,7 +646,8 @@ public class ChaseBuilder {
 	 * @param hcs halting conditions
 	 * @return this
 	 */
-	public ChaseBuilder addHaltingConditions(HaltingCondition... hcs) {
+	@SafeVarargs
+    public final ChaseBuilder<RW> addHaltingConditions(HaltingCondition<RW>... hcs) {
 		this.hcs.addAll(Arrays.asList(hcs));
 		return this;
 	}
@@ -626,7 +657,7 @@ public class ChaseBuilder {
 	 * @param hcs halting conditions
 	 * @return this
 	 */
-	public ChaseBuilder addHaltingConditions(Collection<HaltingCondition> hcs) {
+	public ChaseBuilder<RW> addHaltingConditions(Collection<HaltingCondition<RW>> hcs) {
 		this.hcs.addAll(hcs);
 		return this;
 	}
@@ -638,7 +669,8 @@ public class ChaseBuilder {
 	 * @param pts Global pretreatment
 	 * @return this
 	 */
-	public ChaseBuilder addGlobalPretreatments(Pretreatment... pts) {
+	@SafeVarargs
+    public final ChaseBuilder<RW> addGlobalPretreatments(Pretreatment<RW>... pts) {
 		this.global_pts.addAll(Arrays.asList(pts));
 		return this;
 	}
@@ -648,7 +680,7 @@ public class ChaseBuilder {
 	 * @param pts Global pretreatment
 	 * @return this
 	 */
-	public ChaseBuilder addGlobalPretreatments(Collection<Pretreatment> pts) {
+	public ChaseBuilder<RW> addGlobalPretreatments(Collection<Pretreatment<RW>> pts) {
 		this.global_pts.addAll(pts);
 		return this;
 	}
@@ -660,7 +692,8 @@ public class ChaseBuilder {
 	 * @param pts Step pretreatment
 	 * @return this
 	 */
-	public ChaseBuilder addStepPretreatments(Pretreatment... pts) {
+	@SafeVarargs
+    public final ChaseBuilder<RW> addStepPretreatments(Pretreatment<RW>... pts) {
 		this.step_pts.addAll(Arrays.asList(pts));
 		return this;
 	}
@@ -670,7 +703,7 @@ public class ChaseBuilder {
 	 * @param pts Step pretreatment
 	 * @return this
 	 */
-	public ChaseBuilder addStepPretreatments(Collection<Pretreatment> pts) {
+	public ChaseBuilder<RW> addStepPretreatments(Collection<Pretreatment<RW>> pts) {
 		this.step_pts.addAll(pts);
 		return this;
 	}
@@ -682,7 +715,7 @@ public class ChaseBuilder {
 	 * @param ets Step Global end treatement
 	 * @return this
 	 */
-	public ChaseBuilder addGlobalEndTreatments(EndTreatment... ets) {
+	public ChaseBuilder<RW> addGlobalEndTreatments(EndTreatment<RW>... ets) {
 		this.global_end_ts.addAll(Arrays.asList(ets));
 		return this;
 	}
@@ -692,7 +725,7 @@ public class ChaseBuilder {
 	 * @param ets Step Global end treatement
 	 * @return this
 	 */
-	public ChaseBuilder addGlobalEndTreatments(Collection<EndTreatment> ets) {
+	public ChaseBuilder<RW> addGlobalEndTreatments(Collection<EndTreatment<RW>> ets) {
 		this.global_end_ts.addAll(ets);
 		return this;
 	}
@@ -704,7 +737,8 @@ public class ChaseBuilder {
 	 * @param ets Step end treatement
 	 * @return this
 	 */
-	public ChaseBuilder addStepEndTreatments(EndTreatment... ets) {
+	@SafeVarargs
+    public final ChaseBuilder<RW> addStepEndTreatments(EndTreatment<RW>... ets) {
 		this.end_step_ts.addAll(Arrays.asList(ets));
 		return this;
 	}
@@ -714,7 +748,7 @@ public class ChaseBuilder {
 	 * @param ets Step end treatement
 	 * @return this
 	 */
-	public ChaseBuilder addStepEndTreatments(Collection<EndTreatment> ets) {
+	public ChaseBuilder<RW> addStepEndTreatments(Collection<EndTreatment<RW>> ets) {
 		this.end_step_ts.addAll(ets);
 		return this;
 	}
@@ -723,21 +757,21 @@ public class ChaseBuilder {
 	 * Adds the debug option
 	 * @return this
 	 */
-	public ChaseBuilder debug() {
+	public ChaseBuilder<RW> debug() {
 		this.debug = true;
 		return this;
 	}
 
 	/**
 	 * Returns a StratifiedChaseBuilder for creating a StratifiedChase, with this ChaseBuilder in parameter.
-	 * Transfers the FactBase and RuleBase if they are already set.
+	 * Transfers the QueryableWritableData and RuleBase if they are already set.
 	 *
 	 * @return a new StratifiedChaseBuilder instance.
 	 */
-	public StratifiedChaseBuilder useStratifiedChase() {
-		StratifiedChaseBuilder stratifiedChaseBuilder = new StratifiedChaseBuilder(this);
-		if (this.fb != null) {
-			stratifiedChaseBuilder.setFactBase(this.fb);
+	public StratifiedChaseBuilder<RW> useStratifiedChase() {
+		StratifiedChaseBuilder<RW> stratifiedChaseBuilder = new StratifiedChaseBuilder<RW>(this);
+		if (this.chasableData != null) {
+			stratifiedChaseBuilder.setChasableData(this.chasableData);
 		}
 		if (this.rb != null) {
 			stratifiedChaseBuilder.setRuleBase(this.rb);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseImpl.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseImpl.java
index ee83d0802f0f5d0a2fee7a50675bcf303a89523b..36ff06817e3cc352b37d8e5933655e5501f8b40a 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseImpl.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/ChaseImpl.java
@@ -1,36 +1,38 @@
 package fr.boreal.forward_chaining.chase;
 
-import java.util.Collection;
-
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.halting_condition.HaltingCondition;
 import fr.boreal.forward_chaining.chase.rule_applier.RuleApplier;
 import fr.boreal.forward_chaining.chase.rule_scheduler.RuleScheduler;
 import fr.boreal.forward_chaining.chase.treatment.EndTreatment;
 import fr.boreal.forward_chaining.chase.treatment.Pretreatment;
 import fr.boreal.forward_chaining.chase.treatment.Treatment;
-import fr.boreal.model.kb.api.FactBase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.RuleBase;
 import fr.boreal.model.rule.api.FORule;
 
+import java.util.Collection;
+
 /**
  * Default implementation of the chase algorithm
  */
-public class ChaseImpl implements Chase {
+public class ChaseImpl<RW extends MaterializedData & Writable> implements Chase<RW> {
 
-	private final FactBase fb;
+	private final ChasableData<RW> chasableData;
 	private RuleBase rb;
 
 	private final RuleScheduler rule_scheduler;
-	private final RuleApplier rule_applier;
+	private final RuleApplier<RW> rule_applier;
 	private RuleApplicationStepResult last_step_result;
 
-	private final Collection<HaltingCondition> halting_conditions;
+	private final Collection<HaltingCondition<RW>> halting_conditions;
 
-	private final Collection<Pretreatment> global_pretreatments;
-	private final Collection<Pretreatment> step_pretreatments;
+	private final Collection<Pretreatment<RW>> global_pretreatments;
+	private final Collection<Pretreatment<RW>> step_pretreatments;
 
-	private final Collection<EndTreatment> global_end_treatments;
-	private final Collection<EndTreatment> end_of_step_treatments;
+	private final Collection<EndTreatment<RW>> global_end_treatments;
+	private final Collection<EndTreatment<RW>> end_of_step_treatments;
 
 	private int step_number = 0;
 
@@ -40,7 +42,7 @@ public class ChaseImpl implements Chase {
 
 	/**
 	 * Use {@link ChaseBuilder} to create a chase
-	 * @param fb the factbase
+	 * @param chasableData the factbase
 	 * @param rb the rulebase
 	 * @param rule_scheduler the rule scheduler
 	 * @param rule_applier the rule applier
@@ -50,14 +52,14 @@ public class ChaseImpl implements Chase {
 	 * @param global_end_treatments the global end treatments
 	 * @param end_of_step_treatments the end of step treatments
 	 */
-	protected ChaseImpl(FactBase fb, RuleBase rb,
-			RuleScheduler rule_scheduler, RuleApplier rule_applier,
-			Collection<HaltingCondition> halting_conditions,
-			Collection<Pretreatment> global_pretreatments,
-			Collection<Pretreatment> step_pretreatments,
-			Collection<EndTreatment> global_end_treatments,
-			Collection<EndTreatment> end_of_step_treatments) {
-		this.fb = fb;
+	protected ChaseImpl(ChasableData<RW> chasableData, RuleBase rb,
+						RuleScheduler rule_scheduler, RuleApplier<RW> rule_applier,
+						Collection<HaltingCondition<RW>> halting_conditions,
+						Collection<Pretreatment<RW>> global_pretreatments,
+						Collection<Pretreatment<RW>> step_pretreatments,
+						Collection<EndTreatment<RW>> global_end_treatments,
+						Collection<EndTreatment<RW>> end_of_step_treatments) {
+		this.chasableData = chasableData;
 		this.rb = rb;
 		this.rule_scheduler = rule_scheduler;
 		this.rule_applier = rule_applier;
@@ -83,7 +85,7 @@ public class ChaseImpl implements Chase {
 	public void nextStep() {
 		++step_number;
 		Collection<FORule> rules_to_apply = this.rule_scheduler.getRulesToApply(this.last_step_result.applied_rules());
-        this.last_step_result = this.rule_applier.apply(rules_to_apply, this.fb);
+        this.last_step_result = this.rule_applier.apply(rules_to_apply, this.chasableData);
 	}
 
 	@Override
@@ -112,8 +114,8 @@ public class ChaseImpl implements Chase {
 	/////////////////////////////////////////////////
 
 	@Override
-	public FactBase getFactBase() {
-		return this.fb;
+	public ChasableData<RW> getChasableData() {
+		return this.chasableData;
 	}
 
 	@Override
@@ -146,7 +148,7 @@ public class ChaseImpl implements Chase {
 	public String toString() {
 		return "Steps : " + this.step_number +
 				"\nStep result :\n" + this.last_step_result +
-				"\nFacts :\n" +this.fb.toString();
+				"\nFacts :\n" +this.chasableData.toString();
 	}
 
 	/////////////////////////////////////////////////
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableData.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableData.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f41953577f9467af1cd7d77c6de7af3157293d6
--- /dev/null
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableData.java
@@ -0,0 +1,50 @@
+package fr.boreal.forward_chaining.chase.data;
+
+import fr.boreal.model.data.collection.api.QueryableDataCollection;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Represents data on which we can apply the chase.
+ * There are two parts: a part read-only that can be any queryable and a part read-write that is materialized and writable.
+ * The chase writes data only in the second part.
+ * The read-write part cannot have predicates that are in the read-only part.
+ * @param <ReadWrite> Read-Write data that will contain the result of the chase
+ */
+public interface ChasableData<ReadWrite extends MaterializedData & Writable> {
+    /**
+     * Read-only data - the predicates are distinct from the read-write data
+     * @return the read-only data
+     */
+    Optional<QueryableData> getDataSource();
+
+    /**
+     * Read-write data - the predicates are distinct from the read-only data
+     * @return the data that will notably contain the result of the chase
+     */
+    ReadWrite getWritingTarget();
+
+    /**
+     * Checks the validity of the Chasable
+     * @return true if this Chasable is valid
+     */
+    default boolean checkValidity() {
+        if (getDataSource().isEmpty()) {
+            return true;
+        }
+
+        Collection<Predicate> readOnlyPredicates = getDataSource().get().getPredicates();
+        return getWritingTarget().getPredicates().stream().noneMatch(readOnlyPredicates::contains);
+    }
+
+    /**
+     * Get a queryable data collection containing both the read-only and the read-write data
+     * @return a queryable data collection containing all readable data
+     */
+    QueryableData getAllReadableData();
+}
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableDataImpl.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableDataImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..e5c40ce5c70b88a0a39aeb16b7f72aeabaeb3575
--- /dev/null
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/data/ChasableDataImpl.java
@@ -0,0 +1,52 @@
+package fr.boreal.forward_chaining.chase.data;
+
+import fr.boreal.model.data.collection.builder.ReadOnlyDataCollectionBuilder;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
+
+import java.util.Optional;
+
+public class ChasableDataImpl<ReadWrite extends MaterializedData & Writable>
+    implements ChasableData<ReadWrite> {
+    private final QueryableData dataSource;
+    private final ReadWrite writingTarget;
+    private final QueryableData allReadableData;
+
+    public ChasableDataImpl(ReadWrite writingTarget) {
+        this(null, writingTarget);
+    }
+
+    public ChasableDataImpl(QueryableData dataSource, ReadWrite writingTarget) {
+        this.dataSource = dataSource;
+        this.writingTarget = writingTarget;
+
+        if (dataSource != null) {
+            allReadableData = new ReadOnlyDataCollectionBuilder<>()
+                    .addQueryableData(dataSource)
+                    .addQueryableData(writingTarget)
+                    .build();
+        } else {
+            allReadableData = writingTarget;
+        }
+
+        if (!checkValidity()) {
+            throw new IllegalArgumentException("The Chasable Data is not valid");
+        }
+    }
+
+    @Override
+    public Optional<QueryableData> getDataSource() {
+        return Optional.ofNullable(dataSource);
+    }
+
+    @Override
+    public ReadWrite getWritingTarget() {
+        return writingTarget;
+    }
+
+    @Override
+    public QueryableData getAllReadableData() {
+        return allReadableData;
+    }
+}
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/CreatedFactsAtPreviousStep.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/CreatedFactsAtPreviousStep.java
index 1f9a1b0a97ac0621f3e48b6947334419c48a1bb9..44b2d45292606961f16f469b497e08de29847fc4 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/CreatedFactsAtPreviousStep.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/CreatedFactsAtPreviousStep.java
@@ -1,13 +1,17 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * This halting condition stops the chase if no facts were created at the last step
  */
-public class CreatedFactsAtPreviousStep implements HaltingCondition {
+public class CreatedFactsAtPreviousStep<RW extends MaterializedData & Writable>
+		implements HaltingCondition<RW> {
 	
-	private Chase c;
+	private Chase<RW> c;
 
 	@Override
 	public boolean check() {
@@ -19,7 +23,7 @@ public class CreatedFactsAtPreviousStep implements HaltingCondition {
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.c = c;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HaltingCondition.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HaltingCondition.java
index 72942ff935bf973b1f4e225ed1cebbea3cbb7360..9670ba69343ee1ed2ba616e18a46d61117fe6cb1 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HaltingCondition.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HaltingCondition.java
@@ -1,17 +1,20 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * The Halting condition computes if there is a need for a next chase step or if it stops
  */
-public interface HaltingCondition {
+public interface HaltingCondition<RW extends MaterializedData & Writable> {
 
 	/**
 	 * Initialize the halting condition for the given chase
 	 * @param c the Chase object
 	 */
-    void init(Chase c);
+    void init(Chase<RW> c);
 	
 	/**
 	 * @return true iff the condition is respected
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HasRulesToApply.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HasRulesToApply.java
index d0dac56ad80328cdea49ddbafb441f25da1e7d12..7813c8962f54c1d6cd11b06b9c85cf016e578810 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HasRulesToApply.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/HasRulesToApply.java
@@ -1,13 +1,17 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * This halting condition stops the chase if no rules need to be applied according to the scheduler
  */
-public class HasRulesToApply implements HaltingCondition {
+public class HasRulesToApply<RW extends MaterializedData & Writable>
+		implements HaltingCondition<RW> {
 
-	Chase c;
+	Chase<RW> c;
 
 	@Override
 	public boolean check() {
@@ -15,7 +19,7 @@ public class HasRulesToApply implements HaltingCondition {
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.c = c;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitAtoms.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitAtoms.java
index 0e232401544c06c08acfd253da7109086cfdc49f..e2f900e8d4959f17da0ffd29fc226f8d649a457f 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitAtoms.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitAtoms.java
@@ -1,13 +1,17 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
- * This halting condition stops the chase if there is more than a given number of atoms on the factbase
+ * This halting condition stops the chase if there is more than a given number of atoms on the writable data
  */
-public class LimitAtoms implements HaltingCondition {
+public class LimitAtoms<RW extends MaterializedData & Writable>
+		implements HaltingCondition<RW> {
 	
-	private Chase c;
+	private Chase<RW> c;
 	private final long nbLimitAtoms;
 	
 	/**
@@ -19,11 +23,11 @@ public class LimitAtoms implements HaltingCondition {
 
 	@Override
 	public boolean check() {
-		return c.getFactBase().size() < this.nbLimitAtoms;
+		return c.getChasableData().getWritingTarget().size() < this.nbLimitAtoms;
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.c = c;
 	}
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitNumberOfStep.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitNumberOfStep.java
index 090eab031a7956e243b3936f6ed5f788c6f10823..135c85fe9d761800ad2171d33df949a512348ad8 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitNumberOfStep.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/LimitNumberOfStep.java
@@ -1,13 +1,17 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * This halting condition stops the chase if it reaches a given number a steps
  */
-public class LimitNumberOfStep implements HaltingCondition {
+public class LimitNumberOfStep<RW extends MaterializedData & Writable>
+		implements HaltingCondition<RW> {
 
-	private Chase c;
+	private Chase<RW> c;
 	
 	private final int max;
 	
@@ -24,7 +28,7 @@ public class LimitNumberOfStep implements HaltingCondition {
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.c = c;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/Timeout.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/Timeout.java
index 90c603b9a1ddde7bce30bf3a0a1258360b4932d6..4821134370152d95a0824a0a88a309b5b88fb07c 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/Timeout.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/halting_condition/Timeout.java
@@ -1,11 +1,15 @@
 package fr.boreal.forward_chaining.chase.halting_condition;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * This halting condition stops the chase if more than a given amount of time passed
  */
-public class Timeout implements HaltingCondition {
+public class Timeout<RW extends MaterializedData & Writable>
+		implements HaltingCondition<RW> {
 	
 	private final long timeout;
 	private long start_time;
@@ -24,7 +28,7 @@ public class Timeout implements HaltingCondition {
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.start_time = System.nanoTime();
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChase.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChase.java
index 10b6b49798e90dabdf723219bf83c52694476c37..09ce910c4284e4455f284d8827e989aff515b2c1 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChase.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChase.java
@@ -3,47 +3,51 @@ package fr.boreal.forward_chaining.chase.metachase.stratified;
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.ChaseBuilder;
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.halting_condition.HaltingCondition;
 import fr.boreal.forward_chaining.chase.rule_scheduler.RuleScheduler;
 import fr.boreal.forward_chaining.chase.treatment.EndTreatment;
 import fr.boreal.forward_chaining.chase.treatment.Pretreatment;
 import fr.boreal.forward_chaining.chase.treatment.Treatment;
-import fr.boreal.model.kb.api.FactBase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.RuleBase;
 
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
 
-public class StratifiedChase implements Chase {
-    private final FactBase fb;
+public class StratifiedChase<RW extends MaterializedData & Writable>
+        implements Chase<RW> {
+    private final ChasableData<RW> chasableData;
     private List<RuleBase> strata;
 
-    private final ChaseBuilder chaseBuilder;
-    private Chase chase;
+    private final ChaseBuilder<RW> chaseBuilder;
+    private Chase<RW> chase;
 
-    private final Collection<HaltingCondition> halting_conditions;
+    private final Collection<HaltingCondition<RW>> halting_conditions;
 
-    private final Collection<Pretreatment> global_pretreatments;
-    private final Collection<Pretreatment> step_pretreatments;
+    private final Collection<Pretreatment<RW>> global_pretreatments;
+    private final Collection<Pretreatment<RW>> step_pretreatments;
 
-    private final Collection<EndTreatment> global_end_treatments;
-    private final Collection<EndTreatment> end_of_step_treatments;
+    private final Collection<EndTreatment<RW>> global_end_treatments;
+    private final Collection<EndTreatment<RW>> end_of_step_treatments;
 
     private int step_number = 0;
 
-    public StratifiedChase(ChaseBuilder builder, FactBase fb,
+    public StratifiedChase(ChaseBuilder<RW> builder, ChasableData<RW> chasableData,
                            List<RuleBase> strata,
-                           Collection<HaltingCondition> halting_conditions,
-                           Collection<Pretreatment> global_pretreatments,
-                           Collection<Pretreatment> step_pretreatments,
-                           Collection<EndTreatment> global_end_treatments,
-                           Collection<EndTreatment> end_of_step_treatments) {
-        this.fb = fb;
+                           Collection<HaltingCondition<RW>> halting_conditions,
+                           Collection<Pretreatment<RW>> global_pretreatments,
+                           Collection<Pretreatment<RW>> step_pretreatments,
+                           Collection<EndTreatment<RW>> global_end_treatments,
+                           Collection<EndTreatment<RW>> end_of_step_treatments) {
+        this.chasableData = chasableData;
         this.strata = strata;
 
         this.chaseBuilder = builder;
-        this.chaseBuilder.setFactBase(fb);
+        this.chaseBuilder.setChasableData(chasableData);
 
         this.halting_conditions = halting_conditions;
         this.global_pretreatments = global_pretreatments;
@@ -59,7 +63,7 @@ public class StratifiedChase implements Chase {
 
     @Override
     public void nextStep() {
-        Optional<Chase> optChase = this.chaseBuilder
+        Optional<Chase<RW>> optChase = this.chaseBuilder
                 .setRuleBase(this.strata.get(this.step_number))
                 .build();
         if (optChase.isPresent()) {
@@ -93,8 +97,8 @@ public class StratifiedChase implements Chase {
     }
 
     @Override
-    public FactBase getFactBase() {
-        return this.fb;
+    public ChasableData<RW> getChasableData() {
+        return this.chasableData;
     }
 
     @Override
@@ -125,7 +129,7 @@ public class StratifiedChase implements Chase {
     @Override
     public String toString() {
         return "Steps : " + this.step_number +
-                "\nFacts :\n" +this.fb.toString();
+                "\nFacts :\n" +this.chasableData.getWritingTarget().toString();
     }
 
     private void initAll() {
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChaseBuilder.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChaseBuilder.java
index eab5c207debbfa10d26338f223db081750de71de..bfebabc27962830d24c6d2533927d70332fb2da3 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChaseBuilder.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/metachase/stratified/StratifiedChaseBuilder.java
@@ -2,6 +2,7 @@ package fr.boreal.forward_chaining.chase.metachase.stratified;
 
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.ChaseBuilder;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.halting_condition.HaltingCondition;
 import fr.boreal.forward_chaining.chase.halting_condition.LimitNumberOfStep;
 import fr.boreal.forward_chaining.chase.treatment.Debug;
@@ -10,7 +11,9 @@ import fr.boreal.forward_chaining.chase.treatment.PredicateFilterEndTreatment;
 import fr.boreal.forward_chaining.chase.treatment.Pretreatment;
 import fr.boreal.grd.api.GraphOfFORuleDependencies;
 import fr.boreal.grd.impl.GRDImpl;
-import fr.boreal.model.kb.api.FactBase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.RuleBase;
 import fr.boreal.model.logicalElements.api.Predicate;
 
@@ -21,17 +24,17 @@ import java.util.stream.Collectors;
  * Builder for creating a StratifiedChase.
  * Allows setting various configurations and choosing different stratification methods.
  */
-public class StratifiedChaseBuilder {
+public class StratifiedChaseBuilder<RW extends MaterializedData & Writable> {
 
-    private ChaseBuilder chaseBuilder;
-    private FactBase fb;
+    private ChaseBuilder<RW> chaseBuilder;
+    private ChasableData<RW> chasableData;
     private RuleBase rb;
     private List<RuleBase> strata = new ArrayList<>();
-    private final Collection<HaltingCondition> haltingConditions = new ArrayList<>();
-    private final Collection<Pretreatment> globalPretreatments = new ArrayList<>();
-    private final Collection<Pretreatment> stepPretreatments = new ArrayList<>();
-    private final Collection<EndTreatment> globalEndTreatments = new ArrayList<>();
-    private final Collection<EndTreatment> endOfStepTreatments = new ArrayList<>();
+    private final Collection<HaltingCondition<RW>> haltingConditions = new ArrayList<>();
+    private final Collection<Pretreatment<RW>> globalPretreatments = new ArrayList<>();
+    private final Collection<Pretreatment<RW>> stepPretreatments = new ArrayList<>();
+    private final Collection<EndTreatment<RW>> globalEndTreatments = new ArrayList<>();
+    private final Collection<EndTreatment<RW>> endOfStepTreatments = new ArrayList<>();
     private boolean debug = false;
     private StratificationMethod stratificationMethod = StratificationMethod.NONE;
     private List<Predicate> finalPredicates;
@@ -48,7 +51,7 @@ public class StratifiedChaseBuilder {
      *
      * @param chaseBuilder the ChaseBuilder instance to use.
      */
-    public StratifiedChaseBuilder(ChaseBuilder chaseBuilder) {
+    public StratifiedChaseBuilder(ChaseBuilder<RW> chaseBuilder) {
         this.chaseBuilder = chaseBuilder;
     }
 
@@ -59,9 +62,10 @@ public class StratifiedChaseBuilder {
      * @param rb the RuleBase.
      * @return the default StratifiedChaseBuilder initialized with the given parameters.
      */
-    public static StratifiedChaseBuilder defaultBuilder(FactBase fb, RuleBase rb) {
-        return new StratifiedChaseBuilder(new ChaseBuilder())
-                .setFactBase(fb)
+    public static <RW extends MaterializedData & Writable>
+        StratifiedChaseBuilder<RW> defaultBuilder(ChasableData<RW> fb, RuleBase rb) {
+        return new StratifiedChaseBuilder<RW>(new ChaseBuilder<>())
+                .setChasableData(fb)
                 .setRuleBase(rb);
     }
 
@@ -71,7 +75,8 @@ public class StratifiedChaseBuilder {
      * @param chaseBuilder the ChaseBuilder instance to use.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder setChaseBuilder(ChaseBuilder chaseBuilder) {
+    public StratifiedChaseBuilder<RW> setChaseBuilder(
+            ChaseBuilder<RW> chaseBuilder) {
         this.chaseBuilder = chaseBuilder;
         return this;
     }
@@ -79,11 +84,11 @@ public class StratifiedChaseBuilder {
     /**
      * Sets the FactBase.
      *
-     * @param fb the FactBase.
+     * @param chasableData the chasable data.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder setFactBase(FactBase fb) {
-        this.fb = fb;
+    public StratifiedChaseBuilder<RW> setChasableData(ChasableData<RW> chasableData) {
+        this.chasableData = chasableData;
         return this;
     }
 
@@ -93,7 +98,7 @@ public class StratifiedChaseBuilder {
      * @param rb the RuleBase.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder setRuleBase(RuleBase rb) {
+    public StratifiedChaseBuilder<RW> setRuleBase(RuleBase rb) {
         this.rb = rb;
         return this;
     }
@@ -105,7 +110,7 @@ public class StratifiedChaseBuilder {
      * @param strata the list of RuleBase.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder setStrata(List<RuleBase> strata) {
+    public StratifiedChaseBuilder<RW> setStrata(List<RuleBase> strata) {
         this.strata = strata;
         this.stratificationMethod = StratificationMethod.NONE;
         return this;
@@ -117,7 +122,7 @@ public class StratifiedChaseBuilder {
      *
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder usePseudoMinimalStratification() {
+    public StratifiedChaseBuilder<RW> usePseudoMinimalStratification() {
         this.stratificationMethod = StratificationMethod.PSEUDO_MINIMAL;
         return this;
     }
@@ -128,7 +133,7 @@ public class StratifiedChaseBuilder {
      *
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder useStratification() {
+    public StratifiedChaseBuilder<RW> useStratification() {
         this.stratificationMethod = StratificationMethod.DEFAULT;
         return this;
     }
@@ -139,7 +144,7 @@ public class StratifiedChaseBuilder {
      *
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder useSingleEvaluationStratification() {
+    public StratifiedChaseBuilder<RW> useSingleEvaluationStratification() {
         this.stratificationMethod = StratificationMethod.SINGLE_EVALUATION;
         return this;
     }
@@ -150,7 +155,9 @@ public class StratifiedChaseBuilder {
      * @param conditions the halting conditions to add.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder addHaltingConditions(HaltingCondition... conditions) {
+    @SafeVarargs
+    public final StratifiedChaseBuilder<RW>
+        addHaltingConditions(HaltingCondition<RW>... conditions) {
         this.haltingConditions.addAll(Arrays.asList(conditions));
         return this;
     }
@@ -161,7 +168,8 @@ public class StratifiedChaseBuilder {
      * @param treatments the global pretreatments to add.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder addGlobalPretreatments(Pretreatment... treatments) {
+    @SafeVarargs
+    public final StratifiedChaseBuilder<RW> addGlobalPretreatments(Pretreatment<RW>... treatments) {
         this.globalPretreatments.addAll(Arrays.asList(treatments));
         return this;
     }
@@ -172,7 +180,8 @@ public class StratifiedChaseBuilder {
      * @param treatments the step pretreatments to add.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder addStepPretreatments(Pretreatment... treatments) {
+    @SafeVarargs
+    public final StratifiedChaseBuilder<RW> addStepPretreatments(Pretreatment<RW>... treatments) {
         this.stepPretreatments.addAll(Arrays.asList(treatments));
         return this;
     }
@@ -183,7 +192,8 @@ public class StratifiedChaseBuilder {
      * @param treatments the global end treatments to add.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder addGlobalEndTreatments(EndTreatment... treatments) {
+    @SafeVarargs
+    public final StratifiedChaseBuilder<RW> addGlobalEndTreatments(EndTreatment<RW>... treatments) {
         this.globalEndTreatments.addAll(Arrays.asList(treatments));
         return this;
     }
@@ -194,7 +204,8 @@ public class StratifiedChaseBuilder {
      * @param treatments the end of step treatments to add.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder addEndOfStepTreatments(EndTreatment... treatments) {
+    @SafeVarargs
+    public final StratifiedChaseBuilder<RW> addEndOfStepTreatments(EndTreatment<RW>... treatments) {
         this.endOfStepTreatments.addAll(Arrays.asList(treatments));
         return this;
     }
@@ -205,7 +216,7 @@ public class StratifiedChaseBuilder {
      * @param predicates the list of predicates to keep.
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder setFinalPredicates(List<Predicate> predicates) {
+    public StratifiedChaseBuilder<RW> setFinalPredicates(List<Predicate> predicates) {
         this.finalPredicates = predicates;
         return this;
     }
@@ -215,7 +226,7 @@ public class StratifiedChaseBuilder {
      *
      * @return this StratifiedChaseBuilder instance.
      */
-    public StratifiedChaseBuilder debug() {
+    public StratifiedChaseBuilder<RW> debug() {
         this.debug = true;
         return this;
     }
@@ -225,12 +236,12 @@ public class StratifiedChaseBuilder {
      *
      * @return an Optional containing the StratifiedChase if successfully built, otherwise an empty Optional.
      */
-    public Optional<Chase> build() {
+    public Optional<Chase<RW>> build() {
         if (chaseBuilder == null) {
-            chaseBuilder = new ChaseBuilder();
+            chaseBuilder = new ChaseBuilder<>();
         }
 
-        if (fb == null) {
+        if (chasableData == null) {
             return Optional.empty();
         }
 
@@ -238,7 +249,7 @@ public class StratifiedChaseBuilder {
             return Optional.empty();
         }
 
-        chaseBuilder.setFactBase(fb);
+        chaseBuilder.setChasableData(chasableData);
 
         // Apply the selected stratification method
         if (strata.isEmpty()) {
@@ -259,7 +270,7 @@ public class StratifiedChaseBuilder {
                 case SINGLE_EVALUATION:
                     strata = grd.getSingleEvaluationStratification()
                             .orElseThrow(() -> new IllegalArgumentException("The rule base must be stratifiable"));
-                    this.chaseBuilder.addHaltingConditions(new LimitNumberOfStep(1));
+                    this.chaseBuilder.addHaltingConditions(new LimitNumberOfStep<RW>(1));
                     break;
                 case NONE:
                     break;
@@ -276,9 +287,9 @@ public class StratifiedChaseBuilder {
             this.addEndOfStepTreatments(new Debug());
         }
 
-        return Optional.of(new StratifiedChase(
+        return Optional.of(new StratifiedChase<>(
                 chaseBuilder,
-                fb,
+                chasableData,
                 strata,
                 haltingConditions,
                 globalPretreatments,
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/AbstractRuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/AbstractRuleApplier.java
index ba1f76e05f53746f6905105a2fbe4ab476b912e0..b97b466121d345f7c657d143d44d44de566cf461 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/AbstractRuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/AbstractRuleApplier.java
@@ -5,6 +5,8 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import org.slf4j.Logger;
 
 import fr.boreal.forward_chaining.chase.Chase;
@@ -20,7 +22,7 @@ import fr.boreal.model.rule.api.FORule;
  *
  * Abstract class
  */
-public abstract class AbstractRuleApplier implements RuleApplier {
+public abstract class AbstractRuleApplier<RW extends MaterializedData & Writable> implements RuleApplier<RW> {
 
 	protected Logger LOG;
 
@@ -32,17 +34,17 @@ public abstract class AbstractRuleApplier implements RuleApplier {
 	/**
 	 * How to evaluate the rule's body
 	 */
-	protected final TriggerComputer computer;
+	protected final TriggerComputer<RW> computer;
 
 	/**
 	 * How to check the trigger should be applied
 	 */
-	protected final TriggerChecker checker;
+	protected final TriggerChecker<RW> checker;
 
 	/**
 	 * How to effectively apply the trigger
 	 */
-	protected final TriggerApplier applier;
+	protected final TriggerApplier<RW> applier;
 
 	/**
 	 * Constructor
@@ -52,7 +54,11 @@ public abstract class AbstractRuleApplier implements RuleApplier {
 	 * @param checker the TriggerChecker
 	 * @param applier the TriggerApplier
 	 */
-	public AbstractRuleApplier(BodyToQueryTransformer transformer, TriggerComputer computer, TriggerChecker checker, TriggerApplier applier) {
+	public AbstractRuleApplier(
+			BodyToQueryTransformer transformer,
+			TriggerComputer<RW> computer,
+			TriggerChecker<RW> checker,
+			TriggerApplier<RW> applier) {
 		this.transformer = transformer;
 		this.computer = computer;
 		this.checker = checker;
@@ -60,7 +66,7 @@ public abstract class AbstractRuleApplier implements RuleApplier {
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.computer.init(c);		
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/BreadthFirstTriggerRuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/BreadthFirstTriggerRuleApplier.java
index 97d7b8f6153b3f8f38903aab5ef162c36527ab80..3c970667cd896be091fd8cad377639bc14933e33 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/BreadthFirstTriggerRuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/BreadthFirstTriggerRuleApplier.java
@@ -1,10 +1,13 @@
 package fr.boreal.forward_chaining.chase.rule_applier;
 
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.rule_applier.body_to_query_transformer.BodyToQueryTransformer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.TriggerApplier;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_checker.TriggerChecker;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.TriggerComputer;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
@@ -22,7 +25,7 @@ import java.util.*;
  * * Applying the homomorphism to the head of the rule and
  * * Adding the resulting atoms to the factbase
  */
-public class BreadthFirstTriggerRuleApplier extends AbstractRuleApplier {
+public class BreadthFirstTriggerRuleApplier<RW extends MaterializedData & Writable> extends AbstractRuleApplier<RW> {
 
 	/**
 	 * Constructor
@@ -32,13 +35,17 @@ public class BreadthFirstTriggerRuleApplier extends AbstractRuleApplier {
 	 * @param checker the TriggerChecker
 	 * @param applier the TriggerApplier
 	 */
-	public BreadthFirstTriggerRuleApplier(BodyToQueryTransformer transformer, TriggerComputer computer, TriggerChecker checker, TriggerApplier applier) {
+	public BreadthFirstTriggerRuleApplier(
+			BodyToQueryTransformer transformer,
+			TriggerComputer<RW> computer,
+			TriggerChecker<RW> checker,
+			TriggerApplier<RW> applier) {
 		super(transformer, computer, checker, applier);
 		LOG = LoggerFactory.getLogger(BreadthFirstTriggerRuleApplier.class);
 	}
 
 	@Override
-	public RuleApplicationStepResult apply(Collection<FORule> rules, FactBase fb) {
+	public RuleApplicationStepResult apply(Collection<FORule> rules, ChasableData<RW> chasableData) {
 		Map<FOQuery<?>, Collection<FORule>> rules_by_body = this.groupRulesByBodyQuery(rules);
 		Map<FOQuery<?>, Collection<Substitution>> substitutions_by_body = new HashMap<>();
 
@@ -46,7 +53,7 @@ public class BreadthFirstTriggerRuleApplier extends AbstractRuleApplier {
 		for(FOQuery<?> body : rules_by_body.keySet()) {
 			Iterator<Substitution> res;
 			try {
-				res = this.computer.compute(body, fb);
+				res = this.computer.compute(body, chasableData);
 				substitutions_by_body.put(body, new HashSet<>());
 				while(res.hasNext()) {
 					substitutions_by_body.get(body).add(res.next());
@@ -68,7 +75,7 @@ public class BreadthFirstTriggerRuleApplier extends AbstractRuleApplier {
 				for (FORule rule : rules_by_body.get(body)) {
 					boolean toApply;
 					try {
-						toApply = this.checker.check(rule, substitution, fb);
+						toApply = this.checker.check(rule, substitution, chasableData.getWritingTarget());
 					} catch (Exception e) {
 						throw new RuntimeException(
 								String.format("[%s::apply] Error during the application of the rules - " +
@@ -81,7 +88,7 @@ public class BreadthFirstTriggerRuleApplier extends AbstractRuleApplier {
 						FOFormula application_facts;
 
 						try {
-							application_facts = this.applier.apply(rule, substitution, fb);
+							application_facts = this.applier.apply(rule, substitution, chasableData.getWritingTarget());
 						} catch (Exception e) {
 							Thread.currentThread().interrupt();
 							throw new RuntimeException(
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/MultiThreadRuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/MultiThreadRuleApplier.java
index 4ce24d74bb5297161c3a844ba0431de9232723ec..298a6e45b0b5e6c88f5fb5f37264a96bb633aa5c 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/MultiThreadRuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/MultiThreadRuleApplier.java
@@ -1,10 +1,13 @@
 package fr.boreal.forward_chaining.chase.rule_applier;
 
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.rule_applier.body_to_query_transformer.BodyToQueryTransformer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.TriggerApplier;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_checker.TriggerChecker;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.TriggerComputer;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
@@ -20,7 +23,7 @@ import java.util.concurrent.*;
  * Multithreaded Rule Applier with a worker for each rule.
  * @author Guillaume Pérution-Kihli
  */
-public class MultiThreadRuleApplier extends AbstractRuleApplier {
+public class MultiThreadRuleApplier<RW extends MaterializedData & Writable> extends AbstractRuleApplier<RW> {
 
     private Map<FORule, BlockingQueue<Substitution>> checkingQueues; // Queues for checking per rule
     private Map<FORule, BlockingQueue<Substitution>> applicationQueues;  // Queues for application per rule
@@ -28,12 +31,16 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
     private Map<FORule, Boolean> checkingFinished; // Track when each checking process has finished for each rule
     private static final int MAX_WORKERS = 32;
 
-    public MultiThreadRuleApplier(BodyToQueryTransformer transformer, TriggerComputer computer, TriggerChecker checker, TriggerApplier applier) {
+    public MultiThreadRuleApplier(
+            BodyToQueryTransformer transformer,
+            TriggerComputer<RW> computer,
+            TriggerChecker<RW> checker,
+            TriggerApplier<RW> applier) {
         super(transformer, computer, checker, applier);
     }
 
     @Override
-    public RuleApplicationStepResult apply(Collection<FORule> rules, FactBase fb) {
+    public RuleApplicationStepResult apply(Collection<FORule> rules, ChasableData<RW> chasableData) {
         ExecutorService producerExecutor = Executors.newCachedThreadPool();  // 1 thread per body
         // Pool for checking
         ExecutorService checkingWorkerExecutor = Executors.newFixedThreadPool(Math.min(MAX_WORKERS, rules.size())); // Pool for checking per rule
@@ -62,13 +69,13 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
 
         // Start producers: 1 thread per body (FOQuery)
         for (FOQuery<?> body : rulesByBody.keySet()) {
-            producerExecutor.submit(() -> processBody(body, fb, rulesByBody.get(body)));
+            producerExecutor.submit(() -> processBody(body, chasableData, rulesByBody.get(body)));
         }
 
         // Start worker threads for checking and application for each rule
         for (FORule rule : rules) {
-            checkingWorkerExecutor.submit(() -> processChecking(fb, rule));
-            applicationWorkerExecutor.submit(() -> processApplication(fb, createdFacts, appliedRules, rule));
+            checkingWorkerExecutor.submit(() -> processChecking(chasableData, rule));
+            applicationWorkerExecutor.submit(() -> processApplication(chasableData, createdFacts, appliedRules, rule));
         }
 
         // Shutdown the checking and application worker executors
@@ -84,9 +91,9 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
      * Producer thread: Computes the substitutions (homomorphisms) for a given body (FOQuery)
      * and enqueues operations to the checking queue of each rule.
      */
-    private void processBody(FOQuery<?> body, FactBase fb, Collection<FORule> associatedRules) {
+    private void processBody(FOQuery<?> body, ChasableData<RW> chasableData, Collection<FORule> associatedRules) {
         try {
-            Iterator<Substitution> substitutions = this.computer.compute(body, fb);
+            Iterator<Substitution> substitutions = this.computer.compute(body, chasableData);
             substitutions.forEachRemaining(substitution -> {
                 for (FORule rule : associatedRules) {
                     try {
@@ -114,7 +121,7 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
     /**
      * Process checking of rules.
      */
-    private void processChecking(FactBase fb, FORule rule) {
+    private void processChecking(ChasableData<RW> chasableData, FORule rule) {
         BlockingQueue<Substitution> queue = checkingQueues.get(rule); // Get the queue for this rule
         Substitution homomorphism = null;
         while (true) {
@@ -130,7 +137,7 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
                 }
 
                 // Perform the checking operation
-                if (this.checker.check(rule, homomorphism, fb)) {
+                if (this.checker.check(rule, homomorphism, chasableData.getWritingTarget())) {
                     applicationQueues.get(rule).put(homomorphism);  // Enqueue application task
                 }
 
@@ -148,7 +155,7 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
     /**
      * Process application of facts.
      */
-    private void processApplication(FactBase fb, Set<Atom> createdFacts, Set<FORule> appliedRules, FORule rule) {
+    private void processApplication(ChasableData<RW> chasableData, Set<Atom> createdFacts, Set<FORule> appliedRules, FORule rule) {
         BlockingQueue<Substitution> queue = applicationQueues.get(rule); // Get the queue for this rule
         Substitution homomorphism = null;
         while (true) {
@@ -165,7 +172,7 @@ public class MultiThreadRuleApplier extends AbstractRuleApplier {
                 // Perform the application operation
                 FOFormula applicationFacts;
                 synchronized (this.applier) {
-                    applicationFacts = this.applier.apply(rule, homomorphism, fb);
+                    applicationFacts = this.applier.apply(rule, homomorphism, chasableData.getWritingTarget());
                 }
                 if (applicationFacts != null) {
                     createdFacts.addAll(applicationFacts.asAtomSet());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/ParallelTriggerRuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/ParallelTriggerRuleApplier.java
index af92f4158c9997d529e9e3dfaf819349640eb7d3..11540bb9f860588ecfe2c10304291e558045fe20 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/ParallelTriggerRuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/ParallelTriggerRuleApplier.java
@@ -6,10 +6,13 @@ import java.util.Iterator;
 import java.util.Map;
 
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.rule_applier.body_to_query_transformer.BodyToQueryTransformer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.TriggerApplier;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_checker.TriggerChecker;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.TriggerComputer;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
@@ -24,7 +27,7 @@ import fr.boreal.model.rule.api.FORule;
  * * Applying the homomorphism to the head of the rule and
  * * Adding the resulting atoms to a temporary factbase that will need to be merged into the factbase at the end of the step
  */
-public class ParallelTriggerRuleApplier extends AbstractRuleApplier {
+public class ParallelTriggerRuleApplier<RW extends MaterializedData & Writable> extends AbstractRuleApplier<RW> {
 
 	/**
 	 * Constructor
@@ -34,12 +37,16 @@ public class ParallelTriggerRuleApplier extends AbstractRuleApplier {
 	 * @param checker the TriggerChecker
 	 * @param applier the TriggerApplier
 	 */
-	public ParallelTriggerRuleApplier(BodyToQueryTransformer transformer, TriggerComputer computer, TriggerChecker checker, TriggerApplier applier) {
+	public ParallelTriggerRuleApplier(
+			BodyToQueryTransformer transformer,
+			TriggerComputer<RW> computer,
+			TriggerChecker<RW> checker,
+			TriggerApplier<RW> applier) {
 		super(transformer, computer, checker, applier);
 	}
 
 	@Override
-	public RuleApplicationStepResult apply(Collection<FORule> rules, FactBase fb) {
+	public RuleApplicationStepResult apply(Collection<FORule> rules, ChasableData<RW> chasableData) {
 		Map<FOQuery<?>, Collection<FORule>> rules_by_body = this.groupRulesByBodyQuery(rules);
 		Collection<FORule> applied_rules = new HashSet<>();
 		Collection<Atom> created_facts = new HashSet<>();
@@ -48,7 +55,7 @@ public class ParallelTriggerRuleApplier extends AbstractRuleApplier {
 		for(FOQuery<?> body : rules_by_body.keySet()) {
 			Iterator<Substitution> res;
 			try {
-				res = this.computer.compute(body, fb);
+				res = this.computer.compute(body, chasableData);
 			} catch (Exception e) {
 				throw new RuntimeException(
 						String.format("[%s::apply] Error during the application of the rules - " +
@@ -74,7 +81,7 @@ public class ParallelTriggerRuleApplier extends AbstractRuleApplier {
 				for(FORule rule : rules_by_body.get(body)) {
 					boolean toApply;
 					try {
-						toApply = this.checker.check(rule, h, fb);
+						toApply = this.checker.check(rule, h, chasableData.getWritingTarget());
 					} catch (Exception e) {
 						throw new RuntimeException(
 								String.format("[%s::apply] Error during the application of the rules - " +
@@ -87,7 +94,7 @@ public class ParallelTriggerRuleApplier extends AbstractRuleApplier {
 						FOFormula application_facts;
 
 						try {
-							application_facts = this.applier.apply(rule, h, fb);
+							application_facts = this.applier.apply(rule, h, chasableData.getWritingTarget());
 						} catch (Exception e) {
 							Thread.currentThread().interrupt();
 							throw new RuntimeException(
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/RuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/RuleApplier.java
index bcdee302cd05429d751c81845df35f6dac9ec2f1..e3f54cbdd454005a359fad0292f597b7524881fb 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/RuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/RuleApplier.java
@@ -4,26 +4,30 @@ import java.util.Collection;
 
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.rule.api.FORule;
 
 /**
  * A rule applier applies the given rules of the given factbase
  */
-public interface RuleApplier {
+public interface RuleApplier<RW extends MaterializedData & Writable> {
 	
 	/**
 	 * Initialize the rule applier for the given chase
 	 * @param c the chase object
 	 */
-    void init(Chase c);
+    void init(Chase<RW> c);
 	
 	/**
-	 * Applies the given rules on the given factbase an returns the result (see {@link RuleApplicationStepResult})
+	 * Applies the given rules on the given data and returns the result (see {@link RuleApplicationStepResult})
 	 * @param rules the rules to apply
-	 * @param fb  the factbase to apply the rules on
+	 * @param chasableData  the data to apply the rules on
 	 * @return the result of one application step
 	 */
-    RuleApplicationStepResult apply(Collection<FORule> rules, FactBase fb);
+    RuleApplicationStepResult apply(Collection<FORule> rules, ChasableData<RW> chasableData);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/SourceDelegatedDatalogRuleApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/SourceDelegatedDatalogRuleApplier.java
index 40584c6dce1e36b03cbb36612d77864a63566d2a..1372aa63c5ac27c88befafd20f4cb7476466c6cb 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/SourceDelegatedDatalogRuleApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/SourceDelegatedDatalogRuleApplier.java
@@ -2,6 +2,7 @@ package fr.boreal.forward_chaining.chase.rule_applier;
 
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.RuleApplicationStepResult;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
 import fr.boreal.forward_chaining.chase.rule_applier.body_to_query_transformer.AllTransformer;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.TriggerApplierImpl;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.facts_handler.DirectApplication;
@@ -9,6 +10,8 @@ import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.renamer.Fre
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_checker.ObliviousChecker;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_computer.NaiveTriggerComputer;
 import fr.boreal.model.data.readable.DatalogDelegable;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
@@ -24,21 +27,21 @@ import java.util.HashSet;
  * * Delegating the application to the factbase if it can handle it
  * * Using a fallback method is it can't
  */
-public class SourceDelegatedDatalogRuleApplier implements RuleApplier {
+public class SourceDelegatedDatalogRuleApplier<RW extends MaterializedData & Writable> implements RuleApplier<RW> {
 
-	private final RuleApplier fallback;
+	private final RuleApplier<RW> fallback;
 
 	/**
 	 * DEfault constructor with a oblivious/naive chase as fallback
 	 */
 	public SourceDelegatedDatalogRuleApplier() {
-		this(new BreadthFirstTriggerRuleApplier(
+		this(new BreadthFirstTriggerRuleApplier<>(
 				new AllTransformer(),
-				new NaiveTriggerComputer(FOQueryEvaluatorWithDBMSDelegation.defaultInstance()),
-				new ObliviousChecker(),
-				new TriggerApplierImpl(
+				new NaiveTriggerComputer<>(FOQueryEvaluatorWithDBMSDelegation.defaultInstance()),
+				new ObliviousChecker<>(),
+				new TriggerApplierImpl<>(
 						new FreshRenamer(SameObjectTermFactory.instance()),
-						new DirectApplication())
+						new DirectApplication<>())
 				));		
 	}
 
@@ -46,19 +49,20 @@ public class SourceDelegatedDatalogRuleApplier implements RuleApplier {
 	 * Constructor with that applied the given chase as fallback
 	 * @param fallback fallback application
 	 */
-	public SourceDelegatedDatalogRuleApplier(RuleApplier fallback) {
+	public SourceDelegatedDatalogRuleApplier(RuleApplier<RW> fallback) {
 		this.fallback = fallback;
 	}
 
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		// nothing to do
 	}
 
 	@Override
-	public RuleApplicationStepResult apply(Collection<FORule> rules, FactBase fb) {
-		if(fb instanceof DatalogDelegable storage) {
+	public RuleApplicationStepResult apply(Collection<FORule> rules, ChasableData<RW> chasableData) {
+		if(chasableData.getWritingTarget() instanceof DatalogDelegable storage
+			&& chasableData.getDataSource().isEmpty()) { // TODO: it would be better to check the vocabulary of the rule
             Collection<FORule> existential_rules = new HashSet<>();
 			Collection<FORule> range_restricted_rules = new HashSet<>();
 
@@ -74,10 +78,10 @@ public class SourceDelegatedDatalogRuleApplier implements RuleApplier {
 			try {
 				changed = storage.delegate(range_restricted_rules);
 			} catch (Exception e) {
-				e.printStackTrace();
+				throw new RuntimeException(e);
 			}
 
-			RuleApplicationStepResult existential_result = this.fallback.apply(existential_rules, fb);
+			RuleApplicationStepResult existential_result = this.fallback.apply(existential_rules, chasableData);
 
 			range_restricted_rules.addAll(existential_result.applied_rules());
 			Collection<Atom> facts = existential_result.created_facts();
@@ -92,7 +96,7 @@ public class SourceDelegatedDatalogRuleApplier implements RuleApplier {
 				return new RuleApplicationStepResult(range_restricted_rules, facts);
 			}
 		}
-		return this.fallback.apply(rules, fb);
+		return this.fallback.apply(rules, chasableData);
 	}
 
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplier.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplier.java
index 8d324c0d04a706cc663b500c81b1a673d93b6f30..cf164f934eeb19e049ff5115f035ebb9f98dc94e 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplier.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplier.java
@@ -1,5 +1,7 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_applier;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
@@ -8,15 +10,15 @@ import fr.boreal.model.rule.api.FORule;
 /**
  * A trigger applier applies an homomorphism to the rule's head and add the resulting atoms to the factbase
  */
-public interface TriggerApplier {
+public interface TriggerApplier<RW extends MaterializedData & Writable> {
 
 	/**
 	 * Applies the given substitution to the rule's head and add the result to the factbase
 	 * @param rule the rule to apply
 	 * @param substitution the trigger of the rule
-	 * @param fb the factbase
+	 * @param readWriteData Writable where to add the new facts
 	 * @return the effectively added facts
 	 */
-    FOFormula apply(FORule rule, Substitution substitution, FactBase fb);
+    FOFormula apply(FORule rule, Substitution substitution, RW readWriteData);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplierImpl.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplierImpl.java
index 2303e85b453f83ad9114f71b0c0717e6dab21607..06eadf8f6a2cf1629308a2239f9bb7364127c552 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplierImpl.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/TriggerApplierImpl.java
@@ -2,6 +2,8 @@ package fr.boreal.forward_chaining.chase.rule_applier.trigger_applier;
 
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.facts_handler.FactsHandler;
 import fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.renamer.TriggerRenamer;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.FOFormulas;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
@@ -13,7 +15,7 @@ import fr.boreal.model.rule.api.FORule;
  * image of the rule's head with the renamed homomorphism * then add the images
  * to the facts
  */
-public class TriggerApplierImpl implements TriggerApplier {
+public class TriggerApplierImpl<RW extends MaterializedData & Writable> implements TriggerApplier<RW> {
 
 	private final TriggerRenamer tr;
 	private final FactsHandler fh;
@@ -28,11 +30,11 @@ public class TriggerApplierImpl implements TriggerApplier {
 	}
 
 	@Override
-	public FOFormula apply(FORule rule, Substitution substitution, FactBase fb) {
-		Substitution full_substitution = this.tr.renameExitentials(rule, substitution);
+	public FOFormula apply(FORule rule, Substitution substitution, RW readWriteData) {
+		Substitution full_substitution = this.tr.renameExistentials(rule, substitution);
 		boolean evaluateFunctions = true;
 		FOFormula new_facts = FOFormulas.createImageWith(rule.getHead(), full_substitution, evaluateFunctions);
-		return this.fh.add(new_facts, fb);
+		return this.fh.add(new_facts, readWriteData);
 	}
 
 }
\ No newline at end of file
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DelegatedApplication.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DelegatedApplication.java
index eae0a76333a76c45647a7b9d53779367a009c90a..af81b4af0697dab45a8978bd89a69bd75ba531ff 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DelegatedApplication.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DelegatedApplication.java
@@ -3,6 +3,9 @@ package fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.facts_hand
 import java.util.Collection;
 import java.util.stream.Collectors;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.factory.FOFormulaFactory;
 import fr.boreal.model.kb.api.FactBase;
@@ -10,12 +13,13 @@ import fr.boreal.model.kb.api.FactBase;
 /**
  * Keep the new facts and delay the addition in the factbase
  */
-public class DelegatedApplication implements FactsHandler {
+public class DelegatedApplication<RW extends MaterializedData & Writable>
+		implements FactsHandler<RW> {
 
 	@Override
-	public FOFormula add(FOFormula new_facts, FactBase fb) {		
+	public FOFormula add(FOFormula new_facts, RW readWriteData) {
 		Collection<FOFormula> atoms_to_add = new_facts.asAtomSet().stream()
-				.filter(a -> !fb.contains(a))
+				.filter(a -> !readWriteData.contains(a))
 				.collect(Collectors.toSet());
 
 		if(atoms_to_add.isEmpty()) {
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DirectApplication.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DirectApplication.java
index 575da9a10cb164f9052b33ebe57aa0ffde8f7942..e99cc895f21328ff18a1c1bbc2e31769524a42cd 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DirectApplication.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/DirectApplication.java
@@ -1,16 +1,18 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.facts_handler;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 
 /**
  * Adds the created facts to the factbase
  */
-public class DirectApplication implements FactsHandler {
+public class DirectApplication<RW extends MaterializedData & Writable> implements FactsHandler<RW> {
 
 	@Override
-	public FOFormula add(FOFormula new_facts, FactBase fb) {
-		boolean added_something = fb.add(new_facts);		
+	public FOFormula add(FOFormula new_facts, RW readWriteData) {
+		boolean added_something = readWriteData.add(new_facts);
 		return added_something ? new_facts : null;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/FactsHandler.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/FactsHandler.java
index f18374ee717e11bf30a45ecc3b8db91782a4874d..34cb75d3e5fd9e70e0007eb5caf9f2e9c76d19ac 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/FactsHandler.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/facts_handler/FactsHandler.java
@@ -1,19 +1,22 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_applier.facts_handler;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 
 /**
  * Handles newly created facts
  */
-public interface FactsHandler {
+public interface FactsHandler<RW extends MaterializedData & Writable> {
 
 	/**
-	 * Adds the facts to the factbase
+	 * Adds the facts to the QueryableWritableData
 	 * @param new_facts fatcs to add
-	 * @param fb factbase
+	 * @param readWriteData Writable where to add the new facts 
 	 * @return the effectively added facts
 	 */
-    FOFormula add(FOFormula new_facts, FactBase fb);
+    FOFormula add(FOFormula new_facts, RW readWriteData);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/BodySkolem.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/BodySkolem.java
index 925d678fa283ed131083cb881cd06d5d4c06cfb7..a83371ef7d5d3a92df95c926e81be5858303f786 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/BodySkolem.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/BodySkolem.java
@@ -27,7 +27,7 @@ public class BodySkolem implements TriggerRenamer {
 	}
 
 	@Override
-	public Substitution renameExitentials(FORule rule, final Substitution substitution) {
+	public Substitution renameExistentials(FORule rule, final Substitution substitution) {
 		
 		if (!existentials_names.containsKey(rule)) {
 			existentials_names.put(rule, new HashMap<>());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FreshRenamer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FreshRenamer.java
index 00f19c6f83858a3fda719d6d69e70092155d486e..b8b4d1780d5b3a2aeb4ee6eea54720f45938390c 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FreshRenamer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FreshRenamer.java
@@ -21,7 +21,7 @@ public class FreshRenamer implements TriggerRenamer {
 	}
 
 	@Override
-	public Substitution renameExitentials(FORule rule, final Substitution substitution) {
+	public Substitution renameExistentials(FORule rule, final Substitution substitution) {
 		Substitution s = new SubstitutionImpl();
 		for(Variable v : rule.getExistentials()) {
 			s.add(v, this.tf.createOrGetFreshVariable());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierByPieceSkolem.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierByPieceSkolem.java
index 024e1fa492ffc4254e9eae5b428f29d0256e3980..3fdb994103e89573c199c1e8422b200a0dcae180 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierByPieceSkolem.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierByPieceSkolem.java
@@ -30,7 +30,7 @@ public class FrontierByPieceSkolem implements TriggerRenamer {
 	}
 
 	@Override
-	public Substitution renameExitentials(FORule rule, final Substitution substitution) {
+	public Substitution renameExistentials(FORule rule, final Substitution substitution) {
 		
 		if (!existentials_names.containsKey(rule)) {
 			existentials_names.put(rule, new HashMap<>());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierSkolem.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierSkolem.java
index ed9642df36c1857878c49d47c1bce84276aca53f..34104c9e2d06aed195904ae959ba555907260d06 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierSkolem.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/FrontierSkolem.java
@@ -27,7 +27,7 @@ public class FrontierSkolem implements TriggerRenamer {
 	}
 
 	@Override
-	public Substitution renameExitentials(FORule rule, final Substitution substitution) {
+	public Substitution renameExistentials(FORule rule, final Substitution substitution) {
 		
 		if (!existentials_names.containsKey(rule)) {
 			existentials_names.put(rule, new HashMap<>());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/TriggerRenamer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/TriggerRenamer.java
index 9a1194a2a32aac809ca3163fff93fa64d9e78ce0..6b3a58d613e33672950eabb85e34ece2ba4749fd 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/TriggerRenamer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_applier/renamer/TriggerRenamer.java
@@ -16,6 +16,6 @@ public interface TriggerRenamer {
 	 * and an additional entry for each existential of the rule
 	 * that is not in the initial substitution
 	 */
-    Substitution renameExitentials(FORule rule, final Substitution substitution);
+    Substitution renameExistentials(FORule rule, final Substitution substitution);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/AlwaysTrueChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/AlwaysTrueChecker.java
index 3de0a8dba0a4074f0cd15cc5501d487ffb3739e3..f9cfb5db8273fb2edab75e4c9293118dc883dd43 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/AlwaysTrueChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/AlwaysTrueChecker.java
@@ -1,5 +1,7 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_checker;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.rule.api.FORule;
@@ -8,10 +10,10 @@ import fr.boreal.model.rule.api.FORule;
  * Always accept the given trigger
  * For test purposes or when you are sure the trigger is new
  */
-public class AlwaysTrueChecker implements TriggerChecker {
+public class AlwaysTrueChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
 		return true;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/EquivalentChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/EquivalentChecker.java
index 0b6866bdce6f27ad9b0902f49a62283e150df68d..25de3465f08332b296f71fdf5da363ae4834a37d 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/EquivalentChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/EquivalentChecker.java
@@ -6,7 +6,9 @@ import java.util.Iterator;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import fr.boreal.model.data.readable.MaterializedData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.FOFormulas;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
@@ -24,9 +26,9 @@ import fr.boreal.query_evaluation.generic.GenericFOQueryEvaluator;
 /**
  * Checks if the factbase created with the given trigger would be equivalent to the current factbase
  */
-public class EquivalentChecker implements TriggerChecker {
+public class EquivalentChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 
-	private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
+	private final FOQueryEvaluator<FOFormula, ? super RW> evaluator;
 
 	/**
 	 * Default constructor using the generic query evaluator
@@ -39,25 +41,25 @@ public class EquivalentChecker implements TriggerChecker {
 	 * Constructor using the given query evaluator
 	 * @param evaluator the query evaluator to use
 	 */
-	public EquivalentChecker(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+	public EquivalentChecker(FOQueryEvaluator<FOFormula, ? super RW> evaluator) {
 		this.evaluator = evaluator;
 	}
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
-		FOFormulaConjunction piece = getPiecesInFactBase(rule, substitution, fb);
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
+		FOFormulaConjunction piece = getPiecesInFactBase(rule, substitution, readWriteData);
 		FOFormulaConjunction complete_formula = FOFormulaFactory.instance().createOrGetConjunction(
 				piece,
 				FOFormulas.createImageWith(rule.getHead(), substitution));
         FOQuery<FOFormulaConjunction> query = FOQueryFactory.instance().createOrGetQuery(complete_formula, null, null);
         try {
-            return !this.evaluator.existHomomorphism(query, fb);
+            return !this.evaluator.existHomomorphism(query, readWriteData);
         } catch (EvaluationException e) {
             throw new RuntimeException(e);
         }
     }
 
-	private FOFormulaConjunction getPiecesInFactBase(FORule r, Substitution h, FactBase factBase) {
+	private FOFormulaConjunction getPiecesInFactBase(FORule r, Substitution h, RW readWriteData) {
 		Collection<Variable> vars = FOFormulas.createImageWith(r.getBody(), h).getVariables().collect(Collectors.toSet());
 		Set<Variable> addedVars = new HashSet<>();
 
@@ -68,7 +70,7 @@ public class EquivalentChecker implements TriggerChecker {
 			vars.remove(v);
 			addedVars.add(v);
 
-			Iterator<Atom> it = factBase.getAtomsByTerm(v).iterator();
+			Iterator<Atom> it = readWriteData.getAtomsByTerm(v).iterator();
 			while (it.hasNext()) {
 				Atom a = it.next();
 				result.add(a);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/MultiTriggerChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/MultiTriggerChecker.java
index 0878661d9245defdad2410bcadbffb498dece35e..9f2af4fdd81ebf8a3b94423e6ba52c2e9b8b1b71 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/MultiTriggerChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/MultiTriggerChecker.java
@@ -3,6 +3,8 @@ package fr.boreal.forward_chaining.chase.rule_applier.trigger_checker;
 import java.util.Arrays;
 import java.util.Collection;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.rule.api.FORule;
@@ -10,27 +12,27 @@ import fr.boreal.model.rule.api.FORule;
 /**
  * Combines multiple checkers and checks that all of them accept the given trigger
  */
-public class MultiTriggerChecker implements TriggerChecker {
+public class MultiTriggerChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 
-	final Collection<TriggerChecker> checkers;
+	final Collection<TriggerChecker<RW>> checkers;
 	
 	/**
 	 * @param checkers all the criteria to check
 	 */
-	public MultiTriggerChecker (TriggerChecker... checkers) {
+	public MultiTriggerChecker (TriggerChecker<RW>... checkers) {
 		this.checkers = Arrays.asList(checkers);
 	}
 	
 	/**
 	 * @param checkers all the criteria to check
 	 */
-	public MultiTriggerChecker (Collection<TriggerChecker> checkers) {
+	public MultiTriggerChecker (Collection<TriggerChecker<RW>> checkers) {
 		this.checkers = checkers;
 	}
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
-		return this.checkers.stream().allMatch(checker -> checker.check(rule, substitution, fb));
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
+		return this.checkers.stream().allMatch(checker -> checker.check(rule, substitution, readWriteData));
 	}
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/ObliviousChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/ObliviousChecker.java
index 4293e7cc87582e73714ce583e6cee1bbd31f390e..157ca7cde0f5e609544009241aff58e1f85c143b 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/ObliviousChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/ObliviousChecker.java
@@ -5,6 +5,8 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.rule.api.FORule;
@@ -13,12 +15,12 @@ import fr.boreal.model.rule.api.FORule;
  * Accept the given trigger if it is the first time.
  * This is the criteria for the oblivious chase
  */
-public class ObliviousChecker implements TriggerChecker {
+public class ObliviousChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 	
 	final Map<FORule, Set<Substitution>> alreadyTreated = new HashMap<>();
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
 		Set<Substitution> rule_substitutions = this.alreadyTreated.get(rule);
 		if(rule_substitutions == null) {
 			rule_substitutions = new HashSet<>();
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/RestrictedChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/RestrictedChecker.java
index a840f8b82f23e74ba3ee1161deccc97f6186b3cd..d86fbb46007593f64ed027c784242b304f6590c9 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/RestrictedChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/RestrictedChecker.java
@@ -1,6 +1,8 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_checker;
 
+import fr.boreal.model.data.readable.MaterializedData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
@@ -16,9 +18,9 @@ import java.util.Set;
  * Accept the trigger if it cannot be extended with the head of the rule
  * This is the criteria for the restricted chase
  */
-public class RestrictedChecker implements TriggerChecker {
+public class RestrictedChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 
-	private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
+	private final FOQueryEvaluator<FOFormula, ? super RW> evaluator;
 
 	/**
 	 * Default constructor using the generic query evaluator
@@ -31,15 +33,15 @@ public class RestrictedChecker implements TriggerChecker {
 	 * Constructor using the given query evaluator
 	 * @param evaluator the query evaluator to use
 	 */
-	public RestrictedChecker(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+	public RestrictedChecker(FOQueryEvaluator<FOFormula, ? super RW> evaluator) {
 		this.evaluator = evaluator;
 	}
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
 		FOQuery<FOFormula> query = FOQueryFactory.instance().createOrGetQuery(rule.getHead(), Set.of());
         try {
-            return !this.evaluator.existHomomorphism(query, fb, substitution);
+            return !this.evaluator.existHomomorphism(query, readWriteData, substitution);
         } catch (EvaluationException e) {
             throw new RuntimeException(e);
         }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/SemiObliviousChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/SemiObliviousChecker.java
index 5aab4bb1074c11d9ccf2def9dbd71d07661f8b25..c3683f352d63766152895a5344005fd9c63735f7 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/SemiObliviousChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/SemiObliviousChecker.java
@@ -5,6 +5,8 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.rule.api.FORule;
@@ -13,12 +15,12 @@ import fr.boreal.model.rule.api.FORule;
  * Accept the trigger if it is the first time, checking only the variables from the frontier of the rule.
  * This is the criteria for the semi-oblivious chase
  */
-public class SemiObliviousChecker implements TriggerChecker {
+public class SemiObliviousChecker<RW extends MaterializedData & Writable> implements TriggerChecker<RW> {
 
 	final Map<FORule, Set<Substitution>> alreadyTreated = new HashMap<>();
 
 	@Override
-	public boolean check(FORule rule, Substitution substitution, FactBase fb) {
+	public boolean check(FORule rule, Substitution substitution, RW readWriteData) {
 		
 		Substitution frontier_limited = substitution.limitedTo(rule.getFrontier());
 		Set<Substitution> rule_substitutions = this.alreadyTreated.get(rule);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/TriggerChecker.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/TriggerChecker.java
index 7ca56943ec3671589dfae59eefab33bc04fe9154..4c1fa694a436b1c8a29fa5b78dce7d1caed63fb6 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/TriggerChecker.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_checker/TriggerChecker.java
@@ -1,20 +1,22 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_checker;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.rule.api.FORule;
 
 /**
- * Checks if the given trigger respect a criteria
+ * Checks if the given trigger respects a criteria
  */
-public interface TriggerChecker {
+public interface TriggerChecker<RW extends MaterializedData & Writable> {
 
 	/**
 	 * @param rule the rule that is triggered
 	 * @param substitution the trigger
-	 * @param fb the factbase
-	 * @return true iff the trigger respect the criteria
+	 * @param readWriteData Writable where to add the new facts
+	 * @return true iff the trigger respects the criteria
 	 */
-    boolean check(FORule rule, Substitution substitution, FactBase fb);
+    boolean check(FORule rule, Substitution substitution, RW readWriteData);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/NaiveTriggerComputer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/NaiveTriggerComputer.java
index a3167098b70ccf8e76bff441e645edec80663727..1bfccb794dbede1a4c63fd4a1166525081d493d0 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/NaiveTriggerComputer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/NaiveTriggerComputer.java
@@ -3,7 +3,11 @@ package fr.boreal.forward_chaining.chase.rule_applier.trigger_computer;
 import java.util.Iterator;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
@@ -14,9 +18,9 @@ import fr.boreal.query_evaluation.generic.GenericFOQueryEvaluator;
 /**
  * This computing method consist of only evaluating the rule's body on the factbase.
  */
-public class NaiveTriggerComputer implements TriggerComputer {
+public class NaiveTriggerComputer<RW extends MaterializedData & Writable> implements TriggerComputer<RW> {
 
-	private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
+	private final FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator;
 
 	/**
 	 * Default constructor using the generic query evaluator
@@ -29,19 +33,19 @@ public class NaiveTriggerComputer implements TriggerComputer {
 	 * Constructor using the given query evaluator
 	 * @param evaluator the query evaluator to use
 	 */
-	public NaiveTriggerComputer(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+	public NaiveTriggerComputer(FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator) {
 		this.evaluator = evaluator;
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		// Do nothing
 	}
 
 	@Override
-	public Iterator<Substitution> compute(FOQuery<?> body, FactBase fb) {
+	public Iterator<Substitution> compute(FOQuery<?> body, ChasableData<RW> chasableData) {
         try {
-            return this.evaluator.homomorphism(body, fb).iterator();
+            return this.evaluator.homomorphism(body, chasableData.getAllReadableData()).iterator();
         } catch (EvaluationException e) {
             throw new RuntimeException(e);
         }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/SemiNaiveComputer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/SemiNaiveComputer.java
index c8aee3aa070e9f537320371c880f1ce16d91c651..46479a0e2cfa7e4b0d82d7db2099be51aed11716 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/SemiNaiveComputer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/SemiNaiveComputer.java
@@ -5,14 +5,15 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
-import java.util.Spliterator;
-import java.util.Spliterators;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
 import fr.boreal.model.formula.factory.FOFormulaFactory;
@@ -22,7 +23,6 @@ import fr.boreal.model.logicalElements.api.Predicate;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.api.Variable;
-import fr.boreal.model.logicalElements.impl.AtomImpl;
 import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
 import fr.boreal.model.query.api.FOQuery;
 import fr.boreal.model.query.factory.FOQueryFactory;
@@ -36,12 +36,12 @@ import fr.boreal.query_evaluation.generic.GenericFOQueryEvaluator;
  * See <a href="https://wiki.epfl.ch/provenance2011/documents/foundations%20of%20databases-abiteboul-1995.pdf">...</a>
  * part 13.1 for more explanations
  */
-public class SemiNaiveComputer implements TriggerComputer {
+public class SemiNaiveComputer<RW extends MaterializedData & Writable> implements TriggerComputer<RW> {
 
-	private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
-	private Chase chase;
+	private final FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator;
+	private Chase<RW> chase;
 
-	private final TriggerComputer fallback;
+	private final TriggerComputer<RW> fallback;
 
 	/**
 	 * Default constructor using the generic query evaluator
@@ -54,23 +54,23 @@ public class SemiNaiveComputer implements TriggerComputer {
 	 * Constructor using the given query evaluator
 	 * @param evaluator the query evaluator to use
 	 */
-	public SemiNaiveComputer(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+	public SemiNaiveComputer(FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator) {
 		this.evaluator = evaluator;
-		this.fallback = new NaiveTriggerComputer(this.evaluator);
+		this.fallback = new NaiveTriggerComputer<RW>(this.evaluator);
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.chase = c;
 		this.fallback.init(c);
 	}
 
 	@Override
-	public Iterator<Substitution> compute(FOQuery<?> body, FactBase fb) {
+	public Iterator<Substitution> compute(FOQuery<?> body, ChasableData<RW> chasableData) {
 
 		// First step
 		if(chase.getLastStepResults().created_facts() == null) {
-			return this.fallback.compute(body, fb);
+			return this.fallback.compute(body, chasableData);
 		}
 
 		FactBase last_step_facts = chase.getLastStepResults().created_facts_as_factbase();
@@ -129,7 +129,7 @@ public class SemiNaiveComputer implements TriggerComputer {
 				possible_triggers = possible_triggers.flatMap(substitution -> {
 					FOQuery<FOFormulaConjunction> query_on_factbase = FOQueryFactory.instance().createOrGetQuery(atoms_on_factbase_formula, null);
                     try {
-                        return this.evaluator.homomorphism(query_on_factbase, fb, substitution)
+                        return this.evaluator.homomorphism(query_on_factbase, chasableData.getAllReadableData(), substitution)
                                 .map(subs -> substitution.merged(subs).orElseThrow());
                     } catch (EvaluationException e) {
                         throw new RuntimeException(e);
@@ -143,7 +143,7 @@ public class SemiNaiveComputer implements TriggerComputer {
                     try {
                         return evaluator.homomorphism(
                                 FOQueryFactory.instance().createOrGetQuery(a, a.getVariables().toList()),
-                                this.chase.getFactBase(),
+                                this.chase.getChasableData().getAllReadableData(),
                                 substitution)
 								.filter(s -> !last_step_facts.contains((Atom) s.createImageOf(a)))
 								.map(subs -> substitution.merged(subs).orElseThrow());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TriggerComputer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TriggerComputer.java
index 9f2e55d98a2047783a39fe0bbcb67a0f05e72dc0..d24eec83b0cac49cc6869bec94c5529129c804b0 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TriggerComputer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TriggerComputer.java
@@ -1,6 +1,10 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_computer;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.query.api.FOQuery;
@@ -10,20 +14,20 @@ import java.util.Iterator;
 /**
  * Computes the triggers from a rule's body on a factbase
  */
-public interface TriggerComputer {
+public interface TriggerComputer<RW extends MaterializedData & Writable> {
 
 	/**
 	 * Initialize the trigger computer for the given chase
 	 * @param c the chase object
 	 */
-    void init(Chase c);
+    void init(Chase<RW> c);
 
 	/**
 	 * Computes and returns the triggers of the body on the factbase
 	 * @param body the body of the rule to evaluate
-	 * @param fb the factbase on which to evaluate the rule
+	 * @param chasableData  the data to apply the rules on
 	 * @return the triggers of the rule on the factbase
 	 */
-	Iterator<Substitution> compute(FOQuery<?> body, FactBase fb);
+	Iterator<Substitution> compute(FOQuery<?> body, ChasableData<RW> chasableData);
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TwoStepComputer.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TwoStepComputer.java
index 3673436aac00ea3c1efe55aea906a11af36e79ee..492b7358805c8388df6c1b2c65e91498fd551e18 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TwoStepComputer.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/rule_applier/trigger_computer/TwoStepComputer.java
@@ -1,7 +1,11 @@
 package fr.boreal.forward_chaining.chase.rule_applier.trigger_computer;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.forward_chaining.chase.data.ChasableData;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
@@ -21,10 +25,10 @@ import java.util.stream.StreamSupport;
  * <p>
  * Send an atom on the new facts and extends the homomorphism to the factbase
  */
-public class TwoStepComputer implements TriggerComputer {
+public class TwoStepComputer<RW extends MaterializedData & Writable> implements TriggerComputer<RW> {
 
-	private final FOQueryEvaluator<FOFormula, ? super FactBase> evaluator;
-	private Chase chase;
+	private final FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator;
+	private Chase<RW> chase;
 
 	/**
 	 * Default constructor using the generic query evaluator
@@ -37,23 +41,23 @@ public class TwoStepComputer implements TriggerComputer {
 	 * Constructor using the given query evaluator
 	 * @param evaluator the query evaluator to use
 	 */
-	public TwoStepComputer(FOQueryEvaluator<FOFormula, ? super FactBase> evaluator) {
+	public TwoStepComputer(FOQueryEvaluator<FOFormula, ? super QueryableData> evaluator) {
 		this.evaluator = evaluator;
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.chase = c;
 	}
 
 	@Override
-	public Iterator<Substitution> compute(FOQuery<?> body, FactBase fb) {
+	public Iterator<Substitution> compute(FOQuery<?> body, ChasableData<RW> chasableData) {
 		Collection<Atom> last_step_facts = this.chase.getLastStepResults().created_facts();
 
 		// First step
 		if(last_step_facts == null) {
             try {
-                return this.evaluator.homomorphism(body, fb).iterator();
+                return this.evaluator.homomorphism(body, chasableData.getAllReadableData()).iterator();
             } catch (EvaluationException e) {
                 throw new RuntimeException(e);
             }
@@ -96,7 +100,7 @@ public class TwoStepComputer implements TriggerComputer {
 		for (Atom a : partialS.keySet()) {
 			for (Substitution s : partialS.get(a)) {
                 try {
-                    finalResult.add(this.evaluator.homomorphism(body, fb, s)
+                    finalResult.add(this.evaluator.homomorphism(body, chasableData.getAllReadableData(), s)
                             .map(subs -> s.merged(subs).orElseThrow())
                             .iterator());
                 } catch (EvaluationException e) {
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/AddCreatedFacts.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/AddCreatedFacts.java
index f3bc1115928ffedca5ad2bba79ef1b14a27256ab..a9015e6876d8a0509e57b087ae6ad2b254955663 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/AddCreatedFacts.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/AddCreatedFacts.java
@@ -1,6 +1,8 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
 
@@ -10,19 +12,19 @@ import java.util.Collection;
  * When applied, this treatment adds the facts created at the previous step to the factbase
  * This is used for parallel application of rules.
  */
-public class AddCreatedFacts implements EndTreatment {
+public class AddCreatedFacts<RW extends MaterializedData & Writable> implements EndTreatment<RW> {
 
-	private Chase c;
+	private Chase<RW> c;
 
 	@Override
 	public void apply() {
-		FactBase fb = c.getFactBase();
+		RW fb = c.getChasableData().getWritingTarget();
 		Collection<Atom> new_facts = c.getLastStepResults().created_facts();
 		new_facts.forEach(fb::add);
 	}
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.c = c;		
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeCore.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeCore.java
index 522dcfdf63ea228a462ce4b59f87fd1b4f56e160..3216c128e2cef28c5090dc6c5871aae1844ff285 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeCore.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeCore.java
@@ -2,6 +2,8 @@ package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.core.CoreProcessor;
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.logicalElements.api.Atom;
 
 import java.util.List;
@@ -11,29 +13,29 @@ import java.util.List;
  *
  * @author Guillaume Pérution-Kihli
  */
-public class ComputeCore implements EndTreatment, Pretreatment {
-    private Chase chase;
-    final private CoreProcessor processor;
+public class ComputeCore<RW extends MaterializedData & Writable> implements EndTreatment<RW>, Pretreatment<RW> {
+    private Chase<RW> chase;
+    final private CoreProcessor<RW> processor;
 
-    public ComputeCore(CoreProcessor processor)
+    public ComputeCore(CoreProcessor<RW> processor)
     {
         this.processor = processor;
     }
 
     @Override
-    public void init(Chase c) {
+    public void init(Chase<RW> c) {
         this.chase = c;
     }
 
     @Override
     public void apply() {
-        this.processor.computeCore(this.chase.getFactBase());
+        this.processor.computeCore(this.chase.getChasableData().getWritingTarget());
 
         List<Atom> toRemove = this.chase.getLastStepResults()
                 .created_facts()
                 .stream()
                 .flatMap(f -> f.asAtomSet().stream())
-                .filter(a -> !this.chase.getFactBase().contains(a))
+                .filter(a -> !this.chase.getChasableData().getWritingTarget().contains(a))
                 .toList();
 
         this.chase.getLastStepResults().created_facts().removeAll(toRemove);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeLocalCore.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeLocalCore.java
index 81a296cf2646cf3a8f63c9bc5cded403d1e2aeae..1d4c791a1fc39e69ad62094d17a7f5ab2594faaa 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeLocalCore.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/ComputeLocalCore.java
@@ -2,6 +2,8 @@ package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.core.CoreProcessor;
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Variable;
 
@@ -15,31 +17,31 @@ import java.util.stream.Collectors;
  *
  * @author Guillaume Pérution-Kihli
  */
-public class ComputeLocalCore implements EndTreatment {
-    private Chase chase;
-    final private CoreProcessor processor;
+public class ComputeLocalCore<RW extends MaterializedData & Writable> implements EndTreatment<RW> {
+    private Chase<RW> chase;
+    final private CoreProcessor<RW> processor;
     Set<Variable> frozenVariables;
 
-    public ComputeLocalCore(CoreProcessor processor)
+    public ComputeLocalCore(CoreProcessor<RW> processor)
     {
         this.processor = processor;
     }
 
     @Override
-    public void init(Chase c) {
+    public void init(Chase<RW> c) {
         this.chase = c;
-        frozenVariables = this.chase.getFactBase().getVariables().collect(Collectors.toSet());
+        frozenVariables = this.chase.getChasableData().getWritingTarget().getVariables().collect(Collectors.toSet());
     }
 
     @Override
     public void apply() {
-        this.processor.computeCore(this.chase.getFactBase(), frozenVariables);
-        this.chase.getFactBase().getVariables().forEach(frozenVariables::add);
+        this.processor.computeCore(this.chase.getChasableData().getWritingTarget(), frozenVariables);
+        this.chase.getChasableData().getWritingTarget().getVariables().forEach(frozenVariables::add);
 
         List<Atom> toRemove = this.chase.getLastStepResults()
                 .created_facts()
                 .stream()
-                .filter(a -> !this.chase.getFactBase().contains(a))
+                .filter(a -> !this.chase.getChasableData().getWritingTarget().contains(a))
                 .toList();
 
         this.chase.getLastStepResults().created_facts().removeAll(toRemove);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Debug.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Debug.java
index ff4a68c1a5a174164330875d0be9119c18982a24..07766f2663cb9c2bc726283ad3d6e2813784462d 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Debug.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Debug.java
@@ -1,13 +1,15 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * When applied, this treatment prints informations about the chase, the current step and the factbase
  */
-public class Debug implements EndTreatment {
+public class Debug<RW extends MaterializedData & Writable> implements EndTreatment<RW> {
 
-	private Chase c;
+	private Chase<RW> c;
 	
 	private long time;
 	
@@ -15,7 +17,7 @@ public class Debug implements EndTreatment {
 	public void apply() {
 		System.out.println("---");
 		System.out.println("Step : " + c.getStepCount());
-		System.out.println("Atoms : " + c.getFactBase().size());
+		System.out.println("Atoms : " + c.getChasableData().getWritingTarget().size());
 		System.out.println("Added atoms : " + c.getLastStepResults().created_facts().size());
 		System.out.println("Time : " + (System.currentTimeMillis() - time));
 		System.out.println("Last step rules : " + c.getLastStepResults().applied_rules().size());
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/EndTreatment.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/EndTreatment.java
index 6be1ffcb498f20865632dcfe923c3d2fae8704f8..b9400368e27efa344a5aefd973bd057dab34fcab 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/EndTreatment.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/EndTreatment.java
@@ -1,8 +1,11 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
+
 /**
  * These treatments can be applied at the end of a step of the chase
  */
-public interface EndTreatment extends Treatment {
+public interface EndTreatment<RW extends MaterializedData & Writable> extends Treatment<RW> {
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/PredicateFilterEndTreatment.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/PredicateFilterEndTreatment.java
index 411068b541d66370627cffee485077ee59611bd4..254ac64d6e8532605f81758d1605f83cbc03fd00 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/PredicateFilterEndTreatment.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/PredicateFilterEndTreatment.java
@@ -1,6 +1,8 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Predicate;
@@ -10,17 +12,17 @@ import java.util.*;
 /**
  * End treatment to filter out facts with predicates not in the provided list.
  */
-public class PredicateFilterEndTreatment implements EndTreatment {
+public class PredicateFilterEndTreatment<RW extends MaterializedData & Writable> implements EndTreatment<RW> {
     private static final int BATCH_SIZE = 100;
     private final Map<Integer, Set<Predicate>> predicatesToRemoveByStep;
-    private Chase chase;
+    private Chase<RW> chase;
 
     public PredicateFilterEndTreatment(Map<Integer, Set<Predicate>> predicatesToRemoveByStep) {
         this.predicatesToRemoveByStep = predicatesToRemoveByStep;
     }
 
     @Override
-    public void init(Chase chase) {
+    public void init(Chase<RW> chase) {
         this.chase = chase;
     }
 
@@ -29,7 +31,7 @@ public class PredicateFilterEndTreatment implements EndTreatment {
         int currentStep = chase.getStepCount();
         Set<Predicate> predicatesToRemove = predicatesToRemoveByStep.getOrDefault(currentStep, Set.of());
 
-        FactBase factBase = chase.getFactBase();
+        RW factBase = chase.getChasableData().getWritingTarget();
 
         for (Predicate predicate : predicatesToRemove) {
             List<Atom> batch = new ArrayList<>(BATCH_SIZE);
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Pretreatment.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Pretreatment.java
index 85459c13eff5434ebaa7b368e7828f98d05d1e79..d76f435f4511c8e5f44cc148b57c9a670542049a 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Pretreatment.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Pretreatment.java
@@ -1,8 +1,11 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
+
 /**
  * These treatments can be applied at the start of a step of the chase
  */
-public interface Pretreatment extends Treatment {
+public interface Pretreatment<RW extends MaterializedData & Writable> extends Treatment<RW> {
 
 }
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/RuleSplit.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/RuleSplit.java
index 04afeeaaa74c6335665444005717c7c050ba61c5..a0ecb96e95b80935a101ca427c9ec566091d04dc 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/RuleSplit.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/RuleSplit.java
@@ -4,6 +4,8 @@ import java.util.HashSet;
 import java.util.Set;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 import fr.boreal.model.kb.api.RuleBase;
 import fr.boreal.model.kb.impl.RuleBaseImpl;
 import fr.boreal.model.rule.api.FORule;
@@ -12,12 +14,12 @@ import fr.lirmm.boreal.util.Rules;
 /**
  * When applied, this treatment change the rulebase with an equivalent rule base containing only single piece rules.
  */
-public class RuleSplit implements Pretreatment {
+public class RuleSplit<RW extends MaterializedData & Writable> implements Pretreatment<RW> {
 
-	private Chase chase;
+	private Chase<RW> chase;
 
 	@Override
-	public void init(Chase c) {
+	public void init(Chase<RW> c) {
 		this.chase = c;
 	}
 
diff --git a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Treatment.java b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Treatment.java
index 531d5e59c29e35f53d632061029801fefb6aa37c..c249ee65d39b5eda19e9b7e744bf5a467ddceefb 100644
--- a/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Treatment.java
+++ b/integraal/integraal-forward-chaining/src/main/java/fr/boreal/forward_chaining/chase/treatment/Treatment.java
@@ -1,17 +1,19 @@
 package fr.boreal.forward_chaining.chase.treatment;
 
 import fr.boreal.forward_chaining.chase.Chase;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
 
 /**
  * Apply a given treatment
  */
-public interface Treatment {
+public interface Treatment<RW extends MaterializedData & Writable> {
 	
 	/**
 	 * Initialize the treatment for the given chase
 	 * @param c the chase object
 	 */
-    void init(Chase c);
+    void init(Chase<RW> c);
 	
 	/**
 	 * Applies the treatment
diff --git a/integraal/integraal-forward-chaining/src/main/java/module-info.java b/integraal/integraal-forward-chaining/src/main/java/module-info.java
index 67994cec8c0f21ed700317eeeedf3fedcd2b63ef..86d25a22bb868995077a6c4d6a7097b35d0f639f 100644
--- a/integraal/integraal-forward-chaining/src/main/java/module-info.java
+++ b/integraal/integraal-forward-chaining/src/main/java/module-info.java
@@ -30,4 +30,5 @@ module fr.boreal.forward_chaining {
 	exports fr.boreal.forward_chaining.chase.rule_applier.trigger_computer;
 	exports fr.boreal.forward_chaining.chase.rule_scheduler;
 	exports fr.boreal.forward_chaining.chase.treatment;
+    exports fr.boreal.forward_chaining.chase.data;
 }
\ No newline at end of file
diff --git a/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeCoreTest.java b/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeCoreTest.java
index d12ca928753630fcdf8f75fe2d44b3d717163a06..0645ac0d4ec7408a89e5f7dfbcb44331f035e1fb 100644
--- a/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeCoreTest.java
+++ b/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeCoreTest.java
@@ -3,6 +3,7 @@ package fr.boreal.forward_chaining.chase.test.treatment;
 import fr.boreal.core.*;
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.ChaseBuilder;
+import fr.boreal.forward_chaining.chase.data.ChasableDataImpl;
 import fr.boreal.forward_chaining.chase.treatment.ComputeCore;
 import fr.boreal.io.dlgp.DlgpParser;
 import fr.boreal.model.data.readable.exception.EvaluationException;
@@ -47,10 +48,10 @@ public class ComputeCoreTest {
                 .flatMap(ComputeCoreTest::addChase);
     }
 
-    private static Chase createChase (ChaseBuilder cb, Object[] testCase) {
-        return cb.addStepEndTreatments(new ComputeCore((CoreProcessor) testCase[2]))
-                .setFactBase(new SimpleInMemoryGraphStore(Objects
-                        .requireNonNull(DlgpParser.parseFile((String) testCase[0])).atoms()))
+    private static Chase<FactBase> createChase (ChaseBuilder<FactBase> cb, Object[] testCase) {
+        return cb.addStepEndTreatments(new ComputeCore<>((CoreProcessor<FactBase>) testCase[2]))
+                .setChasableData(new ChasableDataImpl<>(new SimpleInMemoryGraphStore(Objects
+                        .requireNonNull(DlgpParser.parseFile((String) testCase[0])).atoms())))
                 .setRuleBase(new RuleBaseImpl(Objects
                         .requireNonNull(DlgpParser.parseFile((String) testCase[0])).rules()))
                 .build().get();
@@ -80,10 +81,10 @@ public class ComputeCoreTest {
 
     @ParameterizedTest
     @MethodSource("provideData")
-    public void computeCoreTest(Chase chase, SimpleInMemoryGraphStore expected) {
+    public void computeCoreTest(Chase<FactBase> chase, SimpleInMemoryGraphStore expected) {
         chase.execute();
-        Assertions.assertTrue(isACore(chase.getFactBase()));
-        Assertions.assertTrue(isEquivalent(chase.getFactBase(), expected));
+        Assertions.assertTrue(isACore(chase.getChasableData().getWritingTarget()));
+        Assertions.assertTrue(isEquivalent(chase.getChasableData().getWritingTarget(), expected));
     }
 
     private static boolean isACore(FactBase fb) {
diff --git a/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeLocalCoreTest.java b/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeLocalCoreTest.java
index 2e8a8169c53f707afa18b55b9b60777413a99817..487b6c2776602bca3b10c039092ce40e963cdc60 100644
--- a/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeLocalCoreTest.java
+++ b/integraal/integraal-forward-chaining/src/test/java/fr/boreal/forward_chaining/chase/test/treatment/ComputeLocalCoreTest.java
@@ -3,6 +3,7 @@ package fr.boreal.forward_chaining.chase.test.treatment;
 import fr.boreal.core.*;
 import fr.boreal.forward_chaining.chase.Chase;
 import fr.boreal.forward_chaining.chase.ChaseBuilder;
+import fr.boreal.forward_chaining.chase.data.ChasableDataImpl;
 import fr.boreal.forward_chaining.chase.treatment.ComputeLocalCore;
 import fr.boreal.io.dlgp.DlgpParser;
 import fr.boreal.model.data.readable.exception.EvaluationException;
@@ -31,15 +32,15 @@ public class ComputeLocalCoreTest {
 
     static Stream<Object[]> provideData() {
         return Arrays.stream(new CoreProcessor[] {
-                        new MultiThreadsByPieceCoreProcessor(
+                        new MultiThreadsByPieceCoreProcessor<>(
                                 16, MultiThreadsByPieceCoreProcessor.Variant.BY_SPECIALISATION),
-                        new MultiThreadsByPieceCoreProcessor(
+                        new MultiThreadsByPieceCoreProcessor<>(
                                 16, MultiThreadsByPieceCoreProcessor.Variant.BY_DELETION),
-                        new MultiThreadsByPieceCoreProcessor(
+                        new MultiThreadsByPieceCoreProcessor<>(
                                 16, MultiThreadsByPieceCoreProcessor.Variant.EXHAUSTIVE),
-                        new ByPieceCoreProcessor(ByPieceCoreProcessor.Variant.BY_SPECIALISATION),
-                        new ByPieceCoreProcessor(ByPieceCoreProcessor.Variant.BY_DELETION),
-                        new ByPieceCoreProcessor(ByPieceCoreProcessor.Variant.EXHAUSTIVE),
+                        new ByPieceCoreProcessor<>(ByPieceCoreProcessor.Variant.BY_SPECIALISATION),
+                        new ByPieceCoreProcessor<>(ByPieceCoreProcessor.Variant.BY_DELETION),
+                        new ByPieceCoreProcessor<>(ByPieceCoreProcessor.Variant.EXHAUSTIVE),
                         new NaiveCoreProcessor(),
                         new ByPieceAndVariableCoreProcessor()
                 })
@@ -47,10 +48,10 @@ public class ComputeLocalCoreTest {
                 .flatMap(ComputeLocalCoreTest::addChase);
     }
 
-    private static Chase createChase (ChaseBuilder cb, Object[] testCase) {
-        return cb.addStepEndTreatments(new ComputeLocalCore((CoreProcessor) testCase[2]))
-                .setFactBase(new SimpleInMemoryGraphStore(Objects
-                        .requireNonNull(DlgpParser.parseFile((String) testCase[0])).atoms()))
+    private static Chase<FactBase> createChase (ChaseBuilder<FactBase> cb, Object[] testCase) {
+        return cb.addStepEndTreatments(new ComputeLocalCore<>((CoreProcessor<FactBase>) testCase[2]))
+                .setChasableData(new ChasableDataImpl<>(new SimpleInMemoryGraphStore(Objects
+                        .requireNonNull(DlgpParser.parseFile((String) testCase[0])).atoms())))
                 .setRuleBase(new RuleBaseImpl(Objects
                         .requireNonNull(DlgpParser.parseFile((String) testCase[0])).rules()))
                 .build().get();
@@ -79,10 +80,10 @@ public class ComputeLocalCoreTest {
 
     @ParameterizedTest
     @MethodSource("provideData")
-    public void computeCoreTest(Chase chase, SimpleInMemoryGraphStore expected) {
+    public void computeCoreTest(Chase<FactBase> chase, SimpleInMemoryGraphStore expected) {
         chase.execute();
-        Assertions.assertTrue(isACore(chase.getFactBase()));
-        Assertions.assertTrue(isEquivalent(chase.getFactBase(), expected));
+        Assertions.assertTrue(isACore(chase.getChasableData().getWritingTarget()));
+        Assertions.assertTrue(isEquivalent(chase.getChasableData().getWritingTarget(), expected));
     }
 
     private static boolean isACore(FactBase fb) {
diff --git a/integraal/integraal-io/src/main/java/fr/boreal/io/api/Parser.java b/integraal/integraal-io/src/main/java/fr/boreal/io/api/Parser.java
index 5612918a16f101fa7d1b8469ca14786b0a287bdb..e0676ac397f223124b64264af38db94eb1d35258 100644
--- a/integraal/integraal-io/src/main/java/fr/boreal/io/api/Parser.java
+++ b/integraal/integraal-io/src/main/java/fr/boreal/io/api/Parser.java
@@ -48,7 +48,8 @@ import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.query.api.Query;
 import fr.boreal.model.rule.api.FORule;
 import fr.boreal.views.builder.ViewBuilder;
-import fr.boreal.views.datasource.AbstractViewWrapper;
+import fr.boreal.views.datasource.AbstractDataSource;
+import fr.boreal.views.datasource.DataSource;
 import fr.lirmm.boreal.util.stream.CloseableIterator;
 
 import java.util.*;
@@ -77,7 +78,7 @@ public interface Parser<T> extends CloseableIterator<T> {
 		Collection<Atom> atoms = new ArrayList<>();
 		Collection<FORule> rules = new ArrayList<>();
 		Collection<Query> queries = new ArrayList<>();
-		Collection<AbstractViewWrapper<String, ?>> views = new LinkedHashSet<>();
+		Collection<DataSource<String, ?>> views = new LinkedHashSet<>();
 
 		while (this.hasNext()) {
 			switch (this.next()) {
@@ -85,7 +86,7 @@ public interface Parser<T> extends CloseableIterator<T> {
 			case FORule r -> rules.add(r);
 			case Query q -> queries.add(q);
 			case Directive d when d.type().equals(Directive.Type.VIEW) ->
-				views.addAll(ViewBuilder.createFactBases(d.value().toString()));
+				views.addAll(ViewBuilder.loadDataSources(d.value().toString()));
 			default -> {
 			}
 			}
diff --git a/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/InternalObjectFactory.java b/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/InternalObjectFactory.java
index 8c8118cdfa752a23ac3ac41c5bc74dce4fc33266..f0488a249b50beb92c2f7f50b06893761741dc49 100644
--- a/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/InternalObjectFactory.java
+++ b/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/InternalObjectFactory.java
@@ -51,8 +51,6 @@ import fr.boreal.model.functions.JavaMethodInvoker;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.factory.api.TermFactory;
 import fr.boreal.model.logicalElements.impl.functionalTerms.EvaluableFunctionImpl;
-import fr.boreal.model.logicalElements.impl.functionalTerms.GroundFunctionalTermImpl;
-import fr.boreal.model.logicalElements.impl.functionalTerms.SpecializableFunctionalTermImpl;
 import fr.lirmm.graphik.dlgp3.parser.ADlgpItemFactory;
 import fr.lirmm.graphik.dlgp3.parser.BuildException;
 import fr.lirmm.graphik.dlgp3.parser.InvokeManager;
diff --git a/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/ParserResult.java b/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/ParserResult.java
index 06e25a3cbace2f3e8b06203f43c9a2fc6bd0ed62..26cacd6e2eb508f0640786fb58ba5ee63d51b2a0 100644
--- a/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/ParserResult.java
+++ b/integraal/integraal-io/src/main/java/fr/boreal/io/dlgp/ParserResult.java
@@ -1,12 +1,13 @@
 package fr.boreal.io.dlgp;
 
-import java.util.Collection;
-import java.util.LinkedHashSet;
-
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.query.api.Query;
 import fr.boreal.model.rule.api.FORule;
-import fr.boreal.views.datasource.AbstractViewWrapper;
+import fr.boreal.views.datasource.AbstractDataSource;
+import fr.boreal.views.datasource.DataSource;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
 
 /**
  * Result of the DLGP parsing
@@ -19,7 +20,7 @@ public record ParserResult(
 		Collection<Atom> atoms,
 		Collection<FORule> rules,
 		Collection<Query> queries,
-		Collection<AbstractViewWrapper<String, ?>> views) {
+		Collection<DataSource<String, ?>> views) {
 
 	/**
 	 * Creates a union of two DlgpParserResult records.
@@ -33,7 +34,7 @@ public record ParserResult(
 		Collection<Atom> unionAtoms = new LinkedHashSet<>(this.atoms);
 		Collection<FORule> unionRules = new LinkedHashSet<>(this.rules);
 		Collection<Query> unionQueries = new LinkedHashSet<>(this.queries);
-		Collection<AbstractViewWrapper<String, ?>> unionViews = new LinkedHashSet<>(this.views);
+		Collection<DataSource<String, ?>> unionViews = new LinkedHashSet<>(this.views);
 
 		// Add all elements from the other DlgpParserResult to the collections
 		unionAtoms.addAll(other.atoms);
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedDataCollection.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedDataCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfdc392d1f69e3491c9c9f53cb1ccfef80f5710c
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedDataCollection.java
@@ -0,0 +1,120 @@
+package fr.boreal.model.data.collection.api;
+
+import fr.boreal.model.data.collection.impl.MaterializedDataCollectionImpl;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.logicalElements.api.*;
+
+import java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
+public interface MaterializedDataCollection<T extends MaterializedData>
+    extends QueryableDataCollection<T>, MaterializedData {
+    @Override
+    default Stream<Atom> getAtoms() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getAtoms);
+    }
+
+    @Override
+    default Set<Atom> getAtomSet() {
+        return new AbstractSet<>() { // We build a view so that it does not consume more memory
+            @Override
+            public Iterator<Atom> iterator() {
+                return getAtoms().iterator();
+            }
+
+            @Override
+            public int size() {
+                return getAllQueryableData().values().stream()
+                        .mapToInt(md -> (int) md.size())
+                        .sum();
+            }
+
+            @Override
+            public boolean contains(Object o) {
+                if (!(o instanceof Atom a)) {
+                    return false;
+                }
+                return MaterializedDataCollection.this.contains(a);
+            }
+        };
+    }
+
+    @Override
+    default Stream<Atom> getAtomsByTerm(Term term) {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(md -> md.getAtomsByTerm(term));
+    }
+
+    @Override
+    default Stream<Term> getTermsByPredicatePosition(Predicate p, int position) {
+        Optional<T> md = getQueryableData(p);
+        if (md.isPresent()) {
+            return md.get().getTermsByPredicatePosition(p, position);
+        }
+
+        return Stream.empty();
+    }
+
+    @Override
+    default boolean contains(Atom a) {
+        Optional<T> md = getQueryableData(a.getPredicate());
+        return md.map(atoms -> atoms.contains(a)).orElse(false);
+    }
+
+    @Override
+    default long size() {
+        return this.getAllQueryableData().values().stream()
+                .mapToLong(MaterializedData::size)
+                .sum();
+    }
+
+    @Override
+    default Stream<Atom> getAtomsByPredicate(Predicate predicate) {
+        Optional<T> md = getQueryableData(predicate);
+        if (md.isPresent()) {
+            return md.get().getAtomsByPredicate(predicate);
+        }
+
+        return Stream.empty();
+    }
+
+    @Override
+    default Stream<Term> getTerms() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getTerms);
+    }
+
+    @Override
+    default Stream<Variable> getVariables() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getVariables);
+    }
+
+    @Override
+    default Stream<Literal<?>> getLiterals() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getLiterals);
+    }
+
+    @Override
+    default Stream<Constant> getConstants() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getConstants);
+    }
+
+    @Override
+    default Stream<Term> getAllNestedTerms() {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(MaterializedData::getAllNestedTerms);
+    }
+
+    @Override
+    default <TT extends Term> Stream<TT> getNestedTerms(Class<TT> classType) {
+        return this.getAllQueryableData().values().stream()
+                .flatMap(md -> md.getNestedTerms(classType));
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedWritableDataCollection.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedWritableDataCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..da5b34b7094d20d1f967da39e334f10ea165cedc
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/MaterializedWritableDataCollection.java
@@ -0,0 +1,7 @@
+package fr.boreal.model.data.collection.api;
+
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
+
+public interface MaterializedWritableDataCollection<Q extends MaterializedData, W extends Writable>
+        extends MaterializedDataCollection<Q>, QueryableWritableDataCollection<Q, W> {}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableDataCollection.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableDataCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..478e009b3e07b682d9ebde1b24983cad92f2fd99
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableDataCollection.java
@@ -0,0 +1,60 @@
+package fr.boreal.model.data.collection.api;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
+import fr.boreal.model.data.readable.query.BasicQuery;
+import fr.boreal.model.logicalElements.api.Predicate;
+import fr.boreal.model.logicalElements.api.Term;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+public interface QueryableDataCollection<T extends QueryableData> extends QueryableData {
+    ImmutableMap<Predicate, T> getAllQueryableData();
+
+    default Optional<T> getQueryableData(Predicate predicate) {
+        return Optional.ofNullable(getAllQueryableData().get(predicate));
+    }
+
+    @Override
+    default Collection<Predicate> getPredicates() {
+        return getAllQueryableData().keySet();
+    }
+
+    @Override
+    default Stream<List<Term>> evaluate(BasicQuery query) throws EvaluationException {
+        Optional<T> queryableData = this.getQueryableData(query.getPredicate());
+        if (queryableData.isEmpty()) {
+            return Stream.empty();
+        }
+
+        return queryableData.get().evaluate(query);
+    }
+
+    @Override
+    default Optional<Long> estimateBound(BasicQuery query) {
+        Optional<T> queryableData = this.getQueryableData(query.getPredicate());
+        if (queryableData.isEmpty()) {
+            return Optional.of(0L);
+        }
+
+        return queryableData.get().estimateBound(query);
+    }
+
+    @Override
+    default AtomicPattern getBasicPattern(Predicate predicate) {
+        Optional<T> queryableData = this.getQueryableData(predicate);
+        if (queryableData.isEmpty()) {
+            return new AtomicPatternBuilder()
+                    .withPredicate(predicate)
+                    .withCreateQueriesFunction((p, pa) -> Stream.empty())
+                    .withIndexablePatternsFunction(p -> Set.of())
+                    .build();
+        }
+
+        return queryableData.get().getBasicPattern(predicate);
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableWritableDataCollection.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableWritableDataCollection.java
new file mode 100644
index 0000000000000000000000000000000000000000..ed9e2a939fb47c9c070d7a6fe4120aa8a5b22b66
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/api/QueryableWritableDataCollection.java
@@ -0,0 +1,80 @@
+package fr.boreal.model.data.collection.api;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
+import fr.boreal.model.logicalElements.api.Atom;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+import java.util.Map;
+import java.util.Optional;
+
+public interface QueryableWritableDataCollection<Q extends QueryableData, W extends Writable>
+        extends QueryableDataCollection<Q>, Writable {
+    /**
+     * Get all the writable data by Predicate
+     * @return a map from predicates to the writable data
+     */
+    ImmutableMap<Predicate, W> getAllWritableData();
+
+    /**
+     * Get the default-writable data, if provided
+     * The default-writable data is where atoms are written if they have a predicate not assigned to a writable
+     * @return an optional, containing the default writable, if provided
+     */
+    Optional<W> getDefaultWritableData();
+
+    /**
+     * Get a writable by predicate
+     * Return the writable bind to a predicate or, if the predicate is not bound to a writable, the default
+     * writable
+     * @param predicate the predicate for which we want to get the writable data
+     * @return an optional containing the writable bound to a predicate or the default writable if available
+     */
+    default Optional<W> getWritable(Predicate predicate) {
+        Map<Predicate, W> map = this.getAllWritableData();
+        if (map.containsKey(predicate)) {
+            return Optional.of(map.get(predicate));
+        }
+
+        return getDefaultWritableData();
+    }
+
+    @Override
+    default boolean add(Atom atom) {
+        return this.findTargetWritableOrElseThrow(atom.getPredicate()).add(atom);
+    }
+
+    @Override
+    default boolean remove(Atom atom) {
+        Optional<W> optional = this.getWritable(atom.getPredicate());
+        if (optional.isPresent()) {
+            return optional.get().remove(atom);
+        }
+
+        if (this.getQueryableData(atom.getPredicate()).isPresent()) {
+            throw new RuntimeException(String.format(
+                    "Cannot remove %s since it is in read-only data", atom));
+        }
+
+        return false;
+    }
+
+    @Override
+    default void clear() {
+        for (Q qd: this.getAllQueryableData().values()) {
+            if (!(qd instanceof Writable)) {
+                throw new RuntimeException("This data collection is not clearable as it contains read-only data.");
+            }
+        }
+
+        this.getAllWritableData().values().forEach(W::clear);
+        this.getDefaultWritableData().ifPresent(Writable::clear);
+    }
+
+    private W findTargetWritableOrElseThrow(Predicate predicate) throws RuntimeException {
+        return getWritable(predicate).orElseThrow(() -> new RuntimeException(
+                String.format("Could not find writeable target for %s", predicate)
+        ));
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadOnlyDataCollectionBuilder.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadOnlyDataCollectionBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fc2aa83c74f690d9163c0f9eae109ce106dcf04
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadOnlyDataCollectionBuilder.java
@@ -0,0 +1,129 @@
+package fr.boreal.model.data.collection.builder;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.MaterializedDataCollection;
+import fr.boreal.model.data.collection.api.QueryableDataCollection;
+import fr.boreal.model.data.collection.impl.MaterializedDataCollectionImpl;
+import fr.boreal.model.data.collection.impl.QueryableDataCollectionImpl;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+import java.util.*;
+
+/**
+ * A builder for creating read-only data collections.
+ *
+ * @param <T> the type of QueryableData to be stored in the collection
+ */
+public class ReadOnlyDataCollectionBuilder<T extends QueryableData> {
+    private final Map<Predicate, T> dataMap = new HashMap<>();
+
+    /**
+     * Adds a QueryableData instance associated with a specific Predicate.
+     *
+     * @param predicate the predicate associated with the QueryableData
+     * @param queryableData the QueryableData to be added
+     * @return this builder instance for chaining
+     * @throws IllegalArgumentException if the predicate is not present in the QueryableData
+     * @throws IllegalStateException if the predicate is already associated with another QueryableData
+     */
+    public ReadOnlyDataCollectionBuilder<T> addQueryableData(Predicate predicate, T queryableData) {
+        Objects.requireNonNull(predicate, "Predicate cannot be null");
+        Objects.requireNonNull(queryableData, "QueryableData cannot be null");
+
+        if (queryableData instanceof QueryableDataCollection<?>) {
+            QueryableDataCollection<T> collection = (QueryableDataCollection<T>) queryableData;
+            Optional<T> matchingQueryable = collection.getQueryableData(predicate);
+            if (matchingQueryable.isPresent()) {
+                return addQueryableData(predicate, matchingQueryable.get());
+            } else {
+                throw new IllegalArgumentException("The provided QueryableDataCollection does not contain the given Predicate: " + predicate);
+            }
+        }
+
+        if (dataMap.containsKey(predicate)) {
+            throw new IllegalStateException("The Predicate is already associated with another QueryableData: " + predicate);
+        }
+
+        dataMap.put(predicate, queryableData);
+        return this;
+    }
+
+    /**
+     * Adds a QueryableData instance with all its predicates.
+     *
+     * @param queryableData the QueryableData to be added
+     * @return this builder instance for chaining
+     * @throws IllegalStateException if any predicate is already associated with another QueryableData
+     */
+    public ReadOnlyDataCollectionBuilder<T> addQueryableData(T queryableData) {
+        Objects.requireNonNull(queryableData, "QueryableData cannot be null");
+
+        if (queryableData instanceof QueryableDataCollection<?>) {
+            for (T subQueryable : ((QueryableDataCollection<T>) queryableData).getAllQueryableData().values()) {
+                addQueryableData(subQueryable);
+            }
+        } else {
+            for (Predicate predicate : queryableData.getPredicates()) {
+                this.addQueryableData(predicate, queryableData);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Adds a QueryableData instance with specific predicates
+     *
+     * @param predicates the predicates associated with the QueryableData
+     * @param queryableData the QueryableData to be added
+     * @return this builder instance for chaining
+     * @throws IllegalStateException if any predicate is already associated with another QueryableData
+     */
+    public ReadOnlyDataCollectionBuilder<T> addQueryableData(Collection<Predicate> predicates, T queryableData) {
+        Objects.requireNonNull(queryableData, "QueryableData cannot be null");
+        Objects.requireNonNull(predicates, "predicates cannot be null");
+
+        for (Predicate predicate: predicates) {
+            this.addQueryableData(predicate, queryableData);
+        }
+
+        return this;
+    }
+
+    /**
+     * Builds a QueryableDataCollection instance from the added QueryableData.
+     *
+     * @return an immutable QueryableDataCollection instance
+     */
+    public QueryableDataCollection<T> build() {
+        ImmutableMap<Predicate, T> immutableMap = ImmutableMap.copyOf(dataMap);
+        return new QueryableDataCollectionImpl<>(immutableMap) {};
+    }
+
+    /**
+     * Builds a MaterializedDataCollection instance if the type supports MaterializedData.
+     *
+     * @return an immutable MaterializedDataCollection instance
+     * @throws IllegalStateException if the type is not assignable to MaterializedData
+     */
+    @SuppressWarnings("unchecked")
+    public MaterializedDataCollection<MaterializedData> buildMaterialized() {
+        if (!checkAllMaterialized()) {
+            throw new IllegalStateException("Cannot build a MaterializedDataCollection when the type is not MaterializedData");
+        }
+        ImmutableMap<Predicate, MaterializedData> immutableMap =
+                ImmutableMap.copyOf((ImmutableMap<Predicate, MaterializedData>)dataMap);
+        return new MaterializedDataCollectionImpl<>(immutableMap) {};
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean checkAllMaterialized() {
+        for (T qd: this.dataMap.values()) {
+            if (!(qd instanceof MaterializedData)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadWriteDataCollectionBuilder.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadWriteDataCollectionBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..45ccba8268a61d4a6440579d4114841c4958f723
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/builder/ReadWriteDataCollectionBuilder.java
@@ -0,0 +1,143 @@
+package fr.boreal.model.data.collection.builder;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.MaterializedWritableDataCollection;
+import fr.boreal.model.data.collection.api.QueryableDataCollection;
+import fr.boreal.model.data.collection.api.QueryableWritableDataCollection;
+import fr.boreal.model.data.collection.impl.MaterializedWritableDataCollectionImpl;
+import fr.boreal.model.data.collection.impl.QueryableWritableDataCollectionImpl;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * A builder for creating read-write data collections.
+ *
+ * @param <W> the type of Writable data associated with the collection, which also extends Q
+ */
+public class ReadWriteDataCollectionBuilder<W extends QueryableData & Writable> {
+    private final Map<Predicate, QueryableData> queryableDataMap = new HashMap<>();
+    private final Map<Predicate, W> writableDataMap = new HashMap<>();
+    private W defaultWritableData = null;
+
+
+    /**
+     * Adds a QueryableData instance associated with a specific Predicate.
+     *
+     * @param predicate the predicate associated with the QueryableData
+     * @param queryableData the QueryableData to be added
+     * @return this builder instance for chaining
+     * @throws IllegalArgumentException if the predicate is not present in the QueryableData
+     * @throws IllegalStateException if the predicate is already associated with another QueryableData
+     */
+    public ReadWriteDataCollectionBuilder<W> addQueryableData(Predicate predicate, QueryableData queryableData) {
+        Objects.requireNonNull(predicate, "Predicate cannot be null");
+        Objects.requireNonNull(queryableData, "QueryableData cannot be null");
+
+        if (queryableData instanceof QueryableDataCollection<?>) {
+            QueryableDataCollection<QueryableData> collection = (QueryableDataCollection<QueryableData>) queryableData;
+            Optional<QueryableData> matchingQueryable = collection.getQueryableData(predicate);
+            if (matchingQueryable.isPresent()) {
+                return addQueryableData(predicate, matchingQueryable.get());
+            } else {
+                throw new IllegalArgumentException("The provided QueryableDataCollection does not contain the given Predicate: " + predicate);
+            }
+        }
+
+        if (queryableDataMap.containsKey(predicate)) {
+            throw new IllegalStateException("The Predicate is already associated with another QueryableData: " + predicate);
+        }
+
+        queryableDataMap.put(predicate, queryableData);
+        return this;
+    }
+
+    /**
+     * Adds a QueryableData instance with all its predicates.
+     *
+     * @param queryableData the QueryableData to be added
+     * @return this builder instance for chaining
+     * @throws IllegalStateException if any predicate is already associated with another QueryableData
+     */
+    public ReadWriteDataCollectionBuilder<W> addQueryableData(QueryableData queryableData) {
+        Objects.requireNonNull(queryableData, "QueryableData cannot be null");
+
+        if (queryableData instanceof QueryableDataCollection<?>) {
+            for (QueryableData subQueryable : ((QueryableDataCollection<QueryableData>) queryableData).getAllQueryableData().values()) {
+                addQueryableData(subQueryable);
+            }
+        } else {
+            for (Predicate predicate : queryableData.getPredicates()) {
+                this.addQueryableData(predicate, queryableData);
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Adds a Writable instance, which is also Queryable, associated with a specific Predicate.
+     */
+    public ReadWriteDataCollectionBuilder<W> addQueryableWritableData(Predicate predicate, W writableData) {
+        addQueryableData(predicate, writableData);
+        writableDataMap.put(predicate, writableData);
+        return this;
+    }
+
+    /**
+     * Sets the default Writable instance.
+     */
+    public ReadWriteDataCollectionBuilder<W> setDefaultWritableData(W writableData) {
+        Objects.requireNonNull(writableData, "Default Writable cannot be null");
+        this.defaultWritableData = writableData;
+        return this;
+    }
+
+    /**
+     * Builds a QueryableWritableDataCollection instance from the added data.
+     */
+    public <T extends QueryableData> QueryableWritableDataCollection<T, W> build() {
+        ImmutableMap<Predicate, T> immutableQueryableMap = (ImmutableMap<Predicate, T>) ImmutableMap.copyOf(queryableDataMap);
+        ImmutableMap<Predicate, W> immutableWritableMap = ImmutableMap.copyOf(writableDataMap);
+        return new QueryableWritableDataCollectionImpl<>(immutableQueryableMap, defaultWritableData, immutableWritableMap) {};
+    }
+
+    /**
+     * Builds a MaterializedWritableDataCollection instance if the type supports MaterializedData.
+     */
+    public <T extends MaterializedData> MaterializedWritableDataCollection<T, W> buildMaterialized() {
+        if (!checkAllMaterialized()) {
+            throw new IllegalStateException("Cannot build a MaterializedDataCollection when the type is not MaterializedData");
+        }
+        ImmutableMap<Predicate, T> immutableQueryableMap =
+                ImmutableMap.copyOf(queryableDataMap.keySet().stream()
+                        .map(k -> Map.entry(k, (T)queryableDataMap.get(k)))
+                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
+        ImmutableMap<Predicate, W> immutableWritableMap = ImmutableMap.copyOf(writableDataMap);
+        return new MaterializedWritableDataCollectionImpl<>(
+                immutableQueryableMap,
+                defaultWritableData,
+                immutableWritableMap) {};
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean checkAllMaterialized() {
+        for (QueryableData qd: this.queryableDataMap.values()) {
+            if (!(qd instanceof MaterializedData)) {
+                return false;
+            }
+        }
+        for (QueryableData qd: this.writableDataMap.values()) {
+            if (!(qd instanceof MaterializedData)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedDataCollectionImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedDataCollectionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..de2f98075582d4b46e7d5b9c6145cfd1292795ea
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedDataCollectionImpl.java
@@ -0,0 +1,13 @@
+package fr.boreal.model.data.collection.impl;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.MaterializedDataCollection;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+public class MaterializedDataCollectionImpl<T extends MaterializedData>
+    extends QueryableDataCollectionImpl<T> implements MaterializedDataCollection<T> {
+    protected MaterializedDataCollectionImpl(ImmutableMap<Predicate, T> queryableData) {
+        super(queryableData);
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedWritableDataCollectionImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedWritableDataCollectionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..160e788b86dd57c050348f0ed59b3e16bfd5979a
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/MaterializedWritableDataCollectionImpl.java
@@ -0,0 +1,18 @@
+package fr.boreal.model.data.collection.impl;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.MaterializedWritableDataCollection;
+import fr.boreal.model.data.readable.MaterializedData;
+import fr.boreal.model.data.writable.Writable;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+public class MaterializedWritableDataCollectionImpl<Q extends MaterializedData, W extends Writable>
+    extends QueryableWritableDataCollectionImpl<Q, W>
+    implements MaterializedWritableDataCollection<Q, W> {
+    protected MaterializedWritableDataCollectionImpl(
+            ImmutableMap<Predicate, Q> queryableData,
+            W defaultWritableData,
+            ImmutableMap<Predicate, W> writableData) {
+        super(queryableData, defaultWritableData, writableData);
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableDataCollectionImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableDataCollectionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..8d7aa582071e823249e2975f5c11b9aad0ae4f72
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableDataCollectionImpl.java
@@ -0,0 +1,19 @@
+package fr.boreal.model.data.collection.impl;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.QueryableDataCollection;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+public class QueryableDataCollectionImpl<T extends QueryableData> implements QueryableDataCollection<T> {
+    ImmutableMap<Predicate, T> queryableData;
+
+    protected QueryableDataCollectionImpl(ImmutableMap<Predicate, T> queryableData) {
+        this.queryableData = queryableData;
+    }
+
+    @Override
+    public ImmutableMap<Predicate, T> getAllQueryableData() {
+        return this.queryableData;
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableWritableDataCollectionImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableWritableDataCollectionImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..c20c3c31edecf5d3d4986bbba4d611fbb48a34f6
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/collection/impl/QueryableWritableDataCollectionImpl.java
@@ -0,0 +1,36 @@
+package fr.boreal.model.data.collection.impl;
+
+import com.google.common.collect.ImmutableMap;
+import fr.boreal.model.data.collection.api.QueryableWritableDataCollection;
+import fr.boreal.model.data.readable.QueryableData;
+import fr.boreal.model.data.writable.Writable;
+import fr.boreal.model.logicalElements.api.Predicate;
+
+import java.util.Optional;
+
+public class QueryableWritableDataCollectionImpl<Q extends QueryableData, W extends Writable>
+        extends QueryableDataCollectionImpl<Q>
+    implements QueryableWritableDataCollection<Q, W> {
+
+    final W defaultWritableData;
+    final ImmutableMap<Predicate, W> writableData;
+
+    protected QueryableWritableDataCollectionImpl(
+            ImmutableMap<Predicate, Q> queryableData,
+            W defaultWritableData,
+            ImmutableMap<Predicate, W> writableData) {
+        super(queryableData);
+        this.defaultWritableData = defaultWritableData;
+        this.writableData = writableData;
+    }
+
+    @Override
+    public ImmutableMap<Predicate, W> getAllWritableData() {
+        return writableData;
+    }
+
+    @Override
+    public Optional<W> getDefaultWritableData() {
+        return Optional.ofNullable(defaultWritableData);
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/MaterializedData.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/MaterializedData.java
index 768de9ce31ea2e676265b44e098eb656eae82795..316f4496b0a9c4cbd7d927c2085777f47607ebed 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/MaterializedData.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/MaterializedData.java
@@ -84,12 +84,7 @@ public interface MaterializedData extends QueryableData, TermCompound, Iterable<
         try {
             return this.evaluate(
                     this.getBasicPattern(predicate)
-                            .createQueries(
-                                    IntStream.range(0, predicate.arity()).boxed()
-                                            .map(i -> (Term) SameObjectTermFactory.instance().createOrGetFreshVariable())
-                                            .toList(),
-                                    new SubstitutionImpl()
-                            ).findFirst().orElseThrow()
+                            .createQueries(Map.of()).findFirst().orElseThrow()
             ).map(termList -> new AtomImpl(predicate, termList));
         } catch (EvaluationException e) {
             throw new RuntimeException(e);
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/QueryableData.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/QueryableData.java
index 31b4413987d28b0093260c6feade8a7cdf49f94c..fd30a5ac0e1ad79ef1dda6e8bf357275cc15ad0d 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/QueryableData.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/QueryableData.java
@@ -1,12 +1,10 @@
 package fr.boreal.model.data.readable;
 
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
+import fr.boreal.model.data.readable.query.AtomicPattern;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Predicate;
-import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
-import fr.boreal.model.query.api.Query;
 
 import java.util.Collection;
 import java.util.List;
@@ -51,5 +49,5 @@ public interface QueryableData {
      * @param predicate the predicate for which we want to know the basic pattern
      * @return a basic pattern for predicate
      */
-    BasicPattern getBasicPattern(Predicate predicate);
+    AtomicPattern getBasicPattern(Predicate predicate);
 }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AbstractAtomicPattern.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AbstractAtomicPattern.java
new file mode 100644
index 0000000000000000000000000000000000000000..0653cd269881342bc07795e87ffe6c27eaf626a7
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AbstractAtomicPattern.java
@@ -0,0 +1,58 @@
+package fr.boreal.model.data.readable.query;
+
+import fr.boreal.model.logicalElements.api.Predicate;
+import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.logicalElements.api.Term;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collections;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+/**
+ * Represents a basic pattern for querying predicates with specific constraints on term positions.
+ * This pattern defines which positions must be specified (Mandatory), which can be indexed (Indexable),
+ * and what types of terms are allowed in each position.
+ */
+public abstract class AbstractAtomicPattern implements AtomicPattern {
+
+    private final Predicate predicate;
+    private final Set<Integer> mandatoryPositions;
+    private final Map<Integer, Class<? extends Term>> termConstraints;
+
+    /**
+     * Constructs an AtomicPattern with specific constraints.
+     *
+     * @param predicate         The predicate associated with this pattern.
+     * @param mandatoryPositions A list of positions that are mandatory.
+     * @param termConstraints   A map associating positions (0-based index) with allowed term types.
+     */
+    public AbstractAtomicPattern(Predicate predicate, Set<Integer> mandatoryPositions,
+                                 Map<Integer, Class<? extends Term>> termConstraints) {
+        this.predicate = predicate;
+        this.mandatoryPositions = Collections.unmodifiableSet(mandatoryPositions);
+        this.termConstraints = Collections.unmodifiableMap(termConstraints);
+    }
+
+    @Override
+    public Predicate getPredicate() {
+        return predicate;
+    }
+
+    @Override
+    public Class<? extends Term> getTermConstraint(int position) {
+        return termConstraints.get(position);
+    }
+
+    @Override
+    public Set<Integer> getMandatoryPositions() {
+        return mandatoryPositions;
+    }
+
+    @Override
+    public boolean hasAssignedMandatoryParameters(Map<Integer, Term> positionsAssignation) {
+        return positionsAssignation.keySet().containsAll(mandatoryPositions);
+    }
+}
\ No newline at end of file
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPattern.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPattern.java
new file mode 100644
index 0000000000000000000000000000000000000000..31485e4ed815d2566251c7fbe033a411c6c7daf9
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPattern.java
@@ -0,0 +1,58 @@
+package fr.boreal.model.data.readable.query;
+
+import fr.boreal.model.logicalElements.api.Predicate;
+import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.logicalElements.api.Term;
+
+import java.util.List;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+/**
+ * Represents a basic pattern for querying predicates with specific constraints on term positions.
+ * This pattern defines which positions must be specified (Mandatory), which can be indexed (Indexable),
+ * and what types of terms are allowed in each position.
+ */
+public interface AtomicPattern {
+
+    /**
+     * @return The predicate associated with this pattern.
+     */
+    Predicate getPredicate();
+
+    /**
+     * Retrieves the allowed term type for a specific position.
+     *
+     * @param position The position to check (0-based index).
+     * @return The class type of the allowed term, or null if no constraint.
+     */
+    Class<? extends Term> getTermConstraint(int position);
+
+    /**
+     * @return An unmodifiable list of positions that are mandatory.
+     */
+    Set<Integer> getMandatoryPositions();
+
+    /**
+     * @return An unmodifiable set of indexable position patterns.
+     */
+    Set<Set<Integer>> getIndexablePatterns();
+
+    /**
+     * Creates Basic Queries compatible with this atom
+     * The result can be empty if it is not possible to build a Basic Query
+     *
+     * @param positionsAssignation the assignation of the positions
+     * @return A stream containing the BasicQueries compatible with this termSequence.
+     */
+    Stream<BasicQuery> createQueries(Map<Integer, Term> positionsAssignation);
+
+    /**
+     * Checks that all mandatory parameters are assigned
+     *
+     * @param positionsAssignation the assignation of the positions
+     * @return true iff the mandatory parameters are assigned
+     */
+    boolean hasAssignedMandatoryParameters(Map<Integer, Term> positionsAssignation);
+}
\ No newline at end of file
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPatternBuilder.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPatternBuilder.java
similarity index 60%
rename from integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPatternBuilder.java
rename to integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPatternBuilder.java
index 1695e74465fcc17c9393a7cf9c782bcda1c869b4..208dc7c623afcae05e19e964d4276827ab3dddf1 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPatternBuilder.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/AtomicPatternBuilder.java
@@ -1,33 +1,33 @@
 package fr.boreal.model.data.readable.query;
 
-import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Predicate;
-import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
-import org.apache.commons.lang3.function.TriFunction;
 
-import java.util.*;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
 /**
- * Builder class for constructing instances of {@link BasicPattern}.
+ * Builder class for constructing instances of {@link AtomicPattern}.
  */
-public class BasicPatternBuilder {
+public class AtomicPatternBuilder {
     private Predicate predicate;
-    private final List<Integer> mandatoryPositions = new ArrayList<>();
+    private final Set<Integer> mandatoryPositions = new HashSet<>();
     private final Map<Integer, Class<? extends Term>> termConstraints = new HashMap<>();
-    private Function<BasicPattern, Set<Set<Integer>>> indexablePatternsFunction;
-    private TriFunction<BasicPattern, List<Term>, Substitution, Stream<BasicQuery>> createQueriesFunction;
+    private Function<AtomicPattern, Set<Set<Integer>>> indexablePatternsFunction;
+    private BiFunction<AtomicPattern, Map<Integer, Term>, Stream<BasicQuery>> createQueriesFunction;
 
     /**
-     * Sets the predicate for the {@link BasicPattern}.
+     * Sets the predicate for the {@link AtomicPattern}.
      *
      * @param predicate The predicate to be set.
      * @return The builder instance.
      */
-    public BasicPatternBuilder withPredicate(Predicate predicate) {
+    public AtomicPatternBuilder withPredicate(Predicate predicate) {
         this.predicate = predicate;
         return this;
     }
@@ -38,7 +38,7 @@ public class BasicPatternBuilder {
      * @param position The position to be added.
      * @return The builder instance.
      */
-    public BasicPatternBuilder addMandatoryPosition(int position) {
+    public AtomicPatternBuilder addMandatoryPosition(int position) {
         this.mandatoryPositions.add(position);
         return this;
     }
@@ -50,7 +50,7 @@ public class BasicPatternBuilder {
      * @param termClass The term class allowed at this position.
      * @return The builder instance.
      */
-    public BasicPatternBuilder addTermConstraint(int position, Class<? extends Term> termClass) {
+    public AtomicPatternBuilder addTermConstraint(int position, Class<? extends Term> termClass) {
         this.termConstraints.put(position, termClass);
         return this;
     }
@@ -61,7 +61,7 @@ public class BasicPatternBuilder {
      * @param function The function that modifies indexable patterns.
      * @return The builder instance.
      */
-    public BasicPatternBuilder withIndexablePatternsFunction(Function<BasicPattern, Set<Set<Integer>>> function) {
+    public AtomicPatternBuilder withIndexablePatternsFunction(Function<AtomicPattern, Set<Set<Integer>>> function) {
         this.indexablePatternsFunction = function;
         return this;
     }
@@ -72,17 +72,17 @@ public class BasicPatternBuilder {
      * @param function The function that generates queries from an Atom.
      * @return The builder instance.
      */
-    public BasicPatternBuilder withCreateQueriesFunction(TriFunction<BasicPattern, List<Term>, Substitution, Stream<BasicQuery>> function) {
+    public AtomicPatternBuilder withCreateQueriesFunction(BiFunction<AtomicPattern, Map<Integer, Term>, Stream<BasicQuery>> function) {
         this.createQueriesFunction = function;
         return this;
     }
 
     /**
-     * Builds and returns an instance of {@link BasicPattern}.
+     * Builds and returns an instance of {@link AtomicPattern}.
      *
-     * @return A new {@link BasicPattern} instance.
+     * @return A new {@link AtomicPattern} instance.
      */
-    public BasicPattern build() {
+    public AtomicPattern build() {
         if (predicate == null) {
             throw new IllegalStateException("Predicate must be set before building.");
         }
@@ -93,15 +93,15 @@ public class BasicPatternBuilder {
             throw new IllegalStateException("Create queries function must be set before building.");
         }
 
-        return new BasicPattern(predicate, mandatoryPositions, termConstraints) {
+        return new AbstractAtomicPattern(predicate, mandatoryPositions, termConstraints) {
             @Override
             public Set<Set<Integer>> getIndexablePatterns() {
                 return indexablePatternsFunction.apply(this);
             }
 
             @Override
-            public Stream<BasicQuery> createQueries(List<Term> termSequence, Substitution preHomomorphism) {
-                return createQueriesFunction.apply(this, termSequence, preHomomorphism);
+            public Stream<BasicQuery> createQueries(Map<Integer, Term> positionsAssignation) {
+                return createQueriesFunction.apply(this, positionsAssignation);
             }
         };
     }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPattern.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPattern.java
deleted file mode 100644
index 0beec5311f29ef823cf38eb65cdc54c7bd081623..0000000000000000000000000000000000000000
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicPattern.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package fr.boreal.model.data.readable.query;
-
-import fr.boreal.model.logicalElements.api.Atom;
-import fr.boreal.model.logicalElements.api.Predicate;
-import fr.boreal.model.logicalElements.api.Substitution;
-import fr.boreal.model.logicalElements.api.Term;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Collections;
-
-import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import java.util.stream.Stream;
-
-/**
- * Represents a basic pattern for querying predicates with specific constraints on term positions.
- * This pattern defines which positions must be specified (Mandatory), which can be indexed (Indexable),
- * and what types of terms are allowed in each position.
- */
-public abstract class BasicPattern {
-
-    private final Predicate predicate;
-    private final List<Integer> mandatoryPositions;
-    private final Map<Integer, Class<? extends Term>> termConstraints;
-
-    /**
-     * Constructs a BasicPattern with specific constraints.
-     *
-     * @param predicate         The predicate associated with this pattern.
-     * @param mandatoryPositions A list of positions that are mandatory.
-     * @param termConstraints   A map associating positions (0-based index) with allowed term types.
-     */
-    public BasicPattern(Predicate predicate, List<Integer> mandatoryPositions,
-                        Map<Integer, Class<? extends Term>> termConstraints) {
-        this.predicate = predicate;
-        this.mandatoryPositions = Collections.unmodifiableList(mandatoryPositions);
-        this.termConstraints = Collections.unmodifiableMap(termConstraints);
-    }
-
-    /**
-     * @return The predicate associated with this pattern.
-     */
-    public Predicate getPredicate() {
-        return predicate;
-    }
-
-    /**
-     * Retrieves the allowed term type for a specific position.
-     *
-     * @param position The position to check (0-based index).
-     * @return The class type of the allowed term, or null if no constraint.
-     */
-    public Class<? extends Term> getTermConstraint(int position) {
-        return termConstraints.get(position);
-    }
-
-    /**
-     * @return An unmodifiable list of positions that are mandatory.
-     */
-    public List<Integer> getMandatoryPositions() {
-        return mandatoryPositions;
-    }
-
-    /**
-     * @return An unmodifiable set of indexable position patterns.
-     */
-    public abstract Set<Set<Integer>> getIndexablePatterns();
-
-    /**
-     * Creates Basic Queries compatible with this atom
-     * The result can be empty if it is not possible to build a Basic Query
-     *
-     * @param termSequence the term sequence to match
-     * @param preHomomorphism a pre affectation of the variables of termSequence
-     * @return A stream containing the BasicQueries compatible with this termSequence.
-     */
-    public abstract Stream<BasicQuery> createQueries(List<Term> termSequence, Substitution preHomomorphism);
-
-    /**
-     * Checks that all mandatory parameters are assigned
-     *
-     * @param termSequence the term sequence to check
-     * @param preHomomorphism a pre affectation of the variables of termSequence
-     * @return true iff the mandatory parameters are assigned
-     */
-    public boolean hasAssignedMandatoryParameters(List<Term> termSequence, Substitution preHomomorphism) {
-        return mandatoryPositions.stream().allMatch(
-                i -> preHomomorphism.createImageOf(termSequence.get(i)).isGround());
-    }
-}
\ No newline at end of file
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicQuery.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicQuery.java
index 50d2295500aa42d59793cd2eb940cc74013425ce..a87e0ba1ec6bbc6940e7fc634f681d416f6ed32a 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicQuery.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/readable/query/BasicQuery.java
@@ -5,25 +5,24 @@ import fr.boreal.model.logicalElements.api.Predicate;
 import fr.boreal.model.logicalElements.api.Term;
 
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
 
 /**
- * Represents a query built from a BasicPattern.
+ * Represents a query built from a AtomicPattern.
  */
 public class BasicQuery {
 
-    private final BasicPattern pattern;
+    private final AtomicPattern pattern;
     private final Map<Integer, Term> assignedTerms;
 
     /**
-     * Constructs a BasicQuery from a valid BasicPattern.
+     * Constructs a BasicQuery from a valid AtomicPattern.
      *
-     * @param pattern       The BasicPattern that defines the query structure.
+     * @param pattern       The AtomicPattern that defines the query structure.
      * @param assignedTerms The terms assigned to specific positions.
      */
-    public BasicQuery(BasicPattern pattern, Map<Integer, Term> assignedTerms) {
+    public BasicQuery(AtomicPattern pattern, Map<Integer, Term> assignedTerms) {
         this.pattern = pattern;
         this.assignedTerms = Collections.unmodifiableMap(assignedTerms);
     }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/data/writable/Writable.java b/integraal/integraal-model/src/main/java/fr/boreal/model/data/writable/Writable.java
index cbdf8916098a93ff788764524b63bb3558d5b49d..17b9df6f4a782ad94764b6e3ab3f62e8cf4fecc7 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/data/writable/Writable.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/data/writable/Writable.java
@@ -26,7 +26,9 @@ public interface Writable {
 	 * @param atoms to add
 	 * @return true iff at least one atom is new
 	 */
-	boolean add(FOFormula atoms);
+	default boolean add(FOFormula atoms) {
+		return addAll(atoms.asAtomSet());
+	}
 
 	/**
 	 * Stores the given atoms
@@ -34,7 +36,9 @@ public interface Writable {
 	 * @param atoms to add
 	 * @return true iff at least one atom is new
 	 */
-	boolean addAll(Collection<Atom> atoms);
+	default boolean addAll(Collection<Atom> atoms) {
+		return addAll(atoms.stream());
+	}
 
 	/**
 	 * Stores the given atoms
@@ -60,7 +64,9 @@ public interface Writable {
 	 * @param atoms to remove
 	 * @return true iff at least one atom is removed
 	 */
-	boolean remove(FOFormula atoms);
+	default boolean remove(FOFormula atoms) {
+		return removeAll(atoms.asAtomSet());
+	}
 
 	/**
 	 * Removes the given atoms
@@ -68,7 +74,9 @@ public interface Writable {
 	 * @param atoms to remove
 	 * @return true iff at least one atom is removed
 	 */
-	boolean removeAll(Collection<Atom> atoms);
+	default boolean removeAll(Collection<Atom> atoms) {
+		return removeAll(atoms.stream());
+	}
 
 	/**
 	 * Removes the given atoms
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityConstantImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityConstantImpl.java
index 8403de81093737ec437e6df96f8a7429fd03d308..1666f14f84adecc607e93dda8d8cfee9881774c6 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityConstantImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityConstantImpl.java
@@ -9,10 +9,19 @@ import fr.boreal.model.logicalElements.api.Constant;
  *
  * @author Florent Tornil
  */
-public record IdentityConstantImpl(String label) implements Constant {
+public final class IdentityConstantImpl extends IdentityTermImpl implements Constant {
+    private final String label;
 
-	@Override
-	public String toString() {
-		return this.label;
-	}
+    /**
+	 * Constructor using a label
+	 * @param label string representation
+     */
+    public IdentityConstantImpl(String label) {
+        this.label = label;
+    }
+
+    @Override
+    public String label() {
+        return label;
+    }
 }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityFreshVariableImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityFreshVariableImpl.java
index c036fdac58faff52069789575fb7ebb23c860aa3..0db9850442a35a63fdd25913bd5fafffd11c835a 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityFreshVariableImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityFreshVariableImpl.java
@@ -9,11 +9,6 @@ package fr.boreal.model.logicalElements.impl.identityObjects;
  *
  */
 public class IdentityFreshVariableImpl extends IdentityVariableImpl {
-
-	/////////////////////////////////////////////////
-	// Constructors
-	/////////////////////////////////////////////////
-
 	/**
 	 * Constructor using a label
 	 * @param label string representation 
@@ -21,5 +16,4 @@ public class IdentityFreshVariableImpl extends IdentityVariableImpl {
 	public IdentityFreshVariableImpl(String label) {
 		super(label);
 	}
-
 }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityLiteralImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityLiteralImpl.java
index b1c30621c9ee8941a85dac332dc8adc5f46c36c1..a7d304c4e8525a2d325fdf6a72d0cb3608fddc7e 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityLiteralImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityLiteralImpl.java
@@ -10,22 +10,25 @@ import fr.boreal.model.logicalElements.api.Literal;
  * @param <T> the native type of the Literal
  * @author Florent Tornil
  */
-public record IdentityLiteralImpl<T>(T value) implements Literal<T> {
+public class IdentityLiteralImpl<T> extends IdentityTermImpl implements Literal<T> {
 
-	@Override
-	public String label() {
-		return this.value.toString();
+	private final T value;
+
+	/**
+	 * Constructor using a label
+	 * @param value the value contained in the literal
+	 */
+	public IdentityLiteralImpl(T value) {
+		this.value = value;
 	}
 
 	@Override
-	public String toString() {
+	public String label() {
 		return this.value == null ? "null" : this.value.toString();
 	}
 
-	public boolean equals(Object o){
-		if (this == o) {
-			return true;
-		};
-		return false;
+	@Override
+	public T value() {
+		return value;
 	}
 }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityPredicateImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityPredicateImpl.java
index f98413d3e3b3230d9f038333d6984918eecda5dd..992111dea4da4a2ab5362ed1813f47ae7d42f022 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityPredicateImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityPredicateImpl.java
@@ -10,10 +10,24 @@ import fr.boreal.model.logicalElements.api.Predicate;
  * @author Florent Tornil
  */
 public record IdentityPredicateImpl(String label, int arity) implements Predicate {
-
 	@Override
 	public String toString() {
 		return this.label;
 	}
 
+	@Override
+	public boolean equals(Object obj) {
+		if (obj instanceof IdentityPredicateImpl) {
+			return this == obj; // Reference equality
+		} else {
+			// Use the equals method of the other object to do the comparison
+			// This ensures that the comparison with non-identity objects will work
+			return obj != null && obj.equals(this);
+		}
+	}
+
+	@Override
+	public int hashCode() {
+		return System.identityHashCode(this); // Ensures consistency with equals()
+	}
 }
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityTermImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityTermImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8ab0a02a81a448f6094b220f03615449959d03a
--- /dev/null
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityTermImpl.java
@@ -0,0 +1,27 @@
+package fr.boreal.model.logicalElements.impl.identityObjects;
+
+import fr.boreal.model.logicalElements.api.Term;
+
+public abstract class IdentityTermImpl implements Term {
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof IdentityTermImpl) {
+            return this == obj; // Reference equality
+        } else {
+            // Use the equals method of the other object to do the comparison
+            // This ensures that the comparison with non-identity objects will work
+            return obj != null && obj.equals(this);
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        return System.identityHashCode(this); // Ensures consistency with equals()
+    }
+
+    @Override
+    public String toString() {
+        return this.label();
+    }
+}
diff --git a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityVariableImpl.java b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityVariableImpl.java
index 03e9d63ce0ab5faf48106dd65dcef594c842aa81..0693a02e20d9fee07bbf1c634ef300b3d39f64ca 100644
--- a/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityVariableImpl.java
+++ b/integraal/integraal-model/src/main/java/fr/boreal/model/logicalElements/impl/identityObjects/IdentityVariableImpl.java
@@ -10,7 +10,7 @@ import fr.boreal.model.logicalElements.api.Variable;
  * @author Florent Tornil
  *
  */
-public class IdentityVariableImpl implements Variable {
+public class IdentityVariableImpl extends IdentityTermImpl implements Variable {
 
 	private final String label;
 
@@ -26,9 +26,4 @@ public class IdentityVariableImpl implements Variable {
 	public String label() {
 		return this.label;
 	}
-
-	@Override
-	public String toString() {
-		return this.label;
-	}
 }
diff --git a/integraal/integraal-model/src/main/java/module-info.java b/integraal/integraal-model/src/main/java/module-info.java
index 4ab7c5ff528f453ad59344beb3021f4b0d88f0d8..3e96aac276c7337426f36fbdb7cc93b078df4d8b 100644
--- a/integraal/integraal-model/src/main/java/module-info.java
+++ b/integraal/integraal-model/src/main/java/module-info.java
@@ -14,7 +14,11 @@ module fr.boreal.model {
     requires com.google.errorprone.annotations;
 	requires jdk.jdi; // Java compiler for the unary tests
 
+	exports fr.boreal.model.data.collection.api;
+	exports fr.boreal.model.data.collection.builder;
 	exports fr.boreal.model.data.readable;
+	exports fr.boreal.model.data.readable.query;
+	exports fr.boreal.model.data.readable.exception;
 	exports fr.boreal.model.data.writable;
 
 	exports fr.boreal.model.logicalElements.api;
@@ -45,7 +49,5 @@ module fr.boreal.model {
 	exports fr.boreal.model.ruleCompilation.api;
 	exports fr.boreal.model.ruleCompilation.id;
     exports fr.boreal.model.logicalElements.impl.functionalTerms;
-    exports fr.boreal.model.data.readable.query;
-    exports fr.boreal.model.data.readable.exception;
 
 }
\ No newline at end of file
diff --git a/integraal/integraal-model/src/test/java/fr/boreal/test/model/terms/TermEqualityTest.java b/integraal/integraal-model/src/test/java/fr/boreal/test/model/terms/TermEqualityTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..663c98ecd053f3ef757e4979ad1ccbbbf93bc95d
--- /dev/null
+++ b/integraal/integraal-model/src/test/java/fr/boreal/test/model/terms/TermEqualityTest.java
@@ -0,0 +1,63 @@
+package fr.boreal.test.model.terms;
+
+import fr.boreal.model.logicalElements.api.Constant;
+import fr.boreal.model.logicalElements.api.Literal;
+import fr.boreal.model.logicalElements.api.Term;
+import fr.boreal.model.logicalElements.api.Variable;
+import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
+import fr.boreal.model.logicalElements.impl.ConstantImpl;
+import fr.boreal.model.logicalElements.impl.LiteralImpl;
+import fr.boreal.model.logicalElements.impl.VariableImpl;
+import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+public class TermEqualityTest {
+    @Test
+    public void testEquality() {
+        Variable varNonIdentity = new VariableImpl("term");
+        Variable varIdentity = SameObjectTermFactory.instance().createOrGetVariable("term");;
+        Variable varIdentity2 = SameObjectTermFactory.instance().createOrGetVariable("term");
+        List<Variable> variables = List.of(varNonIdentity, varIdentity, varIdentity2);
+
+        assertAllEquals(variables);
+
+        Constant constNonIdentity = new ConstantImpl("term");
+        Constant constIdentity = SameObjectTermFactory.instance().createOrGetConstant("term");;
+        Constant constIdentity2 = SameObjectTermFactory.instance().createOrGetConstant("term");
+        List<Constant> constants = List.of(constNonIdentity, constIdentity, constIdentity2);
+
+        assertAllEquals(constants);
+        assertNotEquals(constants, variables);
+
+        Literal<String> litNonIdentity = new LiteralImpl<>("term");
+        Literal<String> litIdentity = SameObjectTermFactory.instance().createOrGetLiteral("term");;
+        Literal<String> litIdentity2 = SameObjectTermFactory.instance().createOrGetLiteral("term");
+        List<Literal<String>> literals = List.of(litNonIdentity, litIdentity, litIdentity2);
+
+        assertAllEquals(literals);
+        assertNotEquals(literals, variables, constants);
+    }
+
+    private void assertAllEquals(Collection<?> collection) {
+        collection.forEach(o1 ->
+                collection.forEach(o2 -> {
+                    Assertions.assertEquals(o1, o2);
+                    Assertions.assertEquals(o2, o1);
+        }));
+    }
+
+    private void assertNotEquals(Collection<?> collection, Collection<?> ...otherCollections) {
+        for (Collection<?> collection2 : otherCollections) {
+            for (Object o1 : collection) {
+                for (Object o2 : collection2) {
+                    Assertions.assertNotEquals(o1, o2);
+                    Assertions.assertNotEquals(o2, o1);
+                }
+            }
+        }
+    }
+}
diff --git a/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/atomic/AtomicFOQueryEvaluator.java b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/atomic/AtomicFOQueryEvaluator.java
index 7a62fcd9dca51734de9d4ad0fc3de978e26f1f04..d3c5f9dfca313a6cddfb99d71d70bb021582896e 100644
--- a/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/atomic/AtomicFOQueryEvaluator.java
+++ b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/atomic/AtomicFOQueryEvaluator.java
@@ -2,7 +2,7 @@ package fr.boreal.query_evaluation.atomic;
 
 import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
+import fr.boreal.model.data.readable.query.AtomicPattern;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.*;
 import fr.boreal.model.logicalElements.impl.AtomImpl;
@@ -11,8 +11,8 @@ import fr.boreal.model.partition.TermPartition;
 import fr.boreal.model.query.api.FOQuery;
 import fr.boreal.model.queryEvaluation.api.FOQueryEvaluator;
 import fr.boreal.query_evaluation.utils.filters.GroundTermAtPositionFilter;
+import fr.boreal.query_evaluation.utils.filters.PositionsAssignationFilter;
 import fr.boreal.query_evaluation.utils.transformers.TermSequenceToSubstitutionTransformer;
-import org.apache.commons.lang3.tuple.Pair;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -31,7 +31,11 @@ public class AtomicFOQueryEvaluator<QD extends QueryableData> implements FOQuery
 	/////////////////////////////////////////////////
 
 	@Override
-	public Stream<Substitution> evaluate(FOQuery<? extends Atom> query, QD queryableData, Collection<Variable> vars, Substitution preHomomorphism) throws EvaluationException {
+	public Stream<Substitution> evaluate(
+			FOQuery<? extends Atom> query,
+			QD queryableData,
+			Collection<Variable> vars,
+			Substitution preHomomorphism) throws EvaluationException {
 		Atom atom = query.getFormula();
 
 		if (!query.getVariableEqualities().getElements().isEmpty()) {
@@ -44,6 +48,7 @@ public class AtomicFOQueryEvaluator<QD extends QueryableData> implements FOQuery
 		}
 
 		Stream<List<Term>> stream = null;
+
 		if (atom instanceof ComputedAtom ca && ca.isEvaluableWith(preHomomorphism)) {
 			Atom result = ca.eval(preHomomorphism);
 			if (ca.getPredicate().equals(Predicate.TOP)) {
@@ -61,13 +66,22 @@ public class AtomicFOQueryEvaluator<QD extends QueryableData> implements FOQuery
 						} else {
 							return t;
 						}}).toList());
-			BasicQuery bq = selectBasicQuery(queryableData, atom, preHomomorphism).orElseThrow(
+
+			Map<Integer, Term> positionsAffectation = computePositionsAssignation(atom, preHomomorphism);
+			BasicQuery bq = selectBasicQuery(queryableData, atom.getPredicate(), positionsAffectation).orElseThrow(
 					() -> new EvaluationException(String.format(
 							"The query %s is unsupported by the QueryableData %s",
 							query,
 							queryableData.getClass().getSimpleName())
 					)); // TODO: improve the exception so that it is more informative
-			stream = queryableData.evaluate(bq);
+			stream = queryableData.evaluate(bq)
+					.filter(new PositionsAssignationFilter( // Filter values with the assignation
+						positionsAffectation.keySet().stream()
+								// We don't need to filter by the values that were already in the query
+								.filter(i -> !bq.getAssignedTerms().containsKey(i))
+								.map(i -> Map.entry(i, positionsAffectation.get(i)))
+								.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
+					));
 		}
 
 		if (!vars.isEmpty()) {
@@ -81,6 +95,23 @@ public class AtomicFOQueryEvaluator<QD extends QueryableData> implements FOQuery
 				.map(s -> makeSubstitutionOnAnswerVariables(s, query.getAnswerVariables(), query.getVariableEqualities()));
 	}
 
+	private Map<Integer, Term> computePositionsAssignation(
+			Atom atom,
+			Substitution preHomomorphism) {
+		Map<Integer, Term> positions = new HashMap<>();
+
+		for (int i = 0; i < atom.getTermSequence().size(); i++) {
+			Term t = atom.getTermSequence().get(i);
+			if (t.isGround()) {
+				positions.put(i, t);
+			} else if (preHomomorphism.keys().contains(t)) {
+				positions.put(i, preHomomorphism.createImageOf(t));
+			}
+		}
+
+		return positions;
+	}
+
 	private static Substitution makeSubstitutionOnAnswerVariables (
 			Substitution result,
 			Collection<Variable> answerVariables,
@@ -100,14 +131,14 @@ public class AtomicFOQueryEvaluator<QD extends QueryableData> implements FOQuery
 
 	private static Optional<BasicQuery> selectBasicQuery(
 			QueryableData queryableData,
-			Atom atom,
-			Substitution preHomomorphism) {
+			Predicate predicate,
+			Map<Integer, Term> positionsAffectation) {
 		long minBound = Long.MAX_VALUE;
-		BasicPattern basicPattern = queryableData.getBasicPattern(atom.getPredicate());
+		AtomicPattern atomicPattern = queryableData.getBasicPattern(predicate);
 		BasicQuery best = null;
 
 		for (BasicQuery bq: (Iterable<BasicQuery>)
-				basicPattern.createQueries(atom.getTermSequence(), preHomomorphism)::iterator) {
+				atomicPattern.createQueries(positionsAffectation)::iterator) {
 			Optional<Long> estimation = queryableData.estimateBound(bq);
 			if (estimation.isPresent()) {
 				if (estimation.get() < minBound) {
diff --git a/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/generic/GenericFOQueryEvaluator.java b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/generic/GenericFOQueryEvaluator.java
index f6d97ea55009adeceb321f5b998412c65607f534..6f52569a508de2a3e1fd1dae44f1722fd4c8cbb4 100644
--- a/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/generic/GenericFOQueryEvaluator.java
+++ b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/generic/GenericFOQueryEvaluator.java
@@ -44,9 +44,9 @@ public class GenericFOQueryEvaluator<QD extends QueryableData> implements FOQuer
 	 * one doesn't want to configure it.
 	 * @return the default instance of the evaluator
 	 */
-	public static GenericFOQueryEvaluator<QueryableData> defaultInstance() {
-		GenericFOQueryEvaluator<QueryableData> instance = new GenericFOQueryEvaluator<>();
-		return instance.setAtomicEvaluator(new AtomicFOQueryEvaluator())
+	public static <QD extends QueryableData> GenericFOQueryEvaluator<QD> defaultInstance() {
+		GenericFOQueryEvaluator<QD> instance = new GenericFOQueryEvaluator<>();
+		return instance.setAtomicEvaluator(new AtomicFOQueryEvaluator<>())
 				.setConjunctionEvaluator(new BacktrackEvaluator<>(instance))
 				.setNegationEvaluator(new NegationFOQueryEvaluator<>(instance));
 	}
@@ -56,9 +56,11 @@ public class GenericFOQueryEvaluator<QD extends QueryableData> implements FOQuer
 	 * @return an instance of the evaluator using compilation with unfold evaluation
 	 *         strategy
 	 */
-	public static GenericFOQueryEvaluator<QueryableData> defaultInstanceWithUnfoldCompilation(RuleCompilation compilation) {
-		GenericFOQueryEvaluator<QueryableData> instance = GenericFOQueryEvaluator.defaultInstance();
-		return instance.setAtomicEvaluator(new UnfoldingAtomicFOQueryEvaluator(compilation))
+	public static <QD extends QueryableData>
+		GenericFOQueryEvaluator<QD> defaultInstanceWithUnfoldCompilation(RuleCompilation compilation) {
+		GenericFOQueryEvaluator<QD> instance =
+				GenericFOQueryEvaluator.defaultInstance();
+		return instance.setAtomicEvaluator(new UnfoldingAtomicFOQueryEvaluator<>(compilation))
 				.setConjunctionEvaluator(new BacktrackEvaluator<>(instance))
 				.setNegationEvaluator(new NegationFOQueryEvaluator<>(instance));
 	}
diff --git a/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/utils/filters/PositionsAssignationFilter.java b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/utils/filters/PositionsAssignationFilter.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e3163d8aaac2fa9f666d8c324f2f3b0f4778cd4
--- /dev/null
+++ b/integraal/integraal-query-evaluation/src/main/java/fr/boreal/query_evaluation/utils/filters/PositionsAssignationFilter.java
@@ -0,0 +1,21 @@
+package fr.boreal.query_evaluation.utils.filters;
+
+import fr.boreal.model.logicalElements.api.Term;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Predicate;
+
+public class PositionsAssignationFilter implements Predicate<List<Term>> {
+    private final Map<Integer, Term> positionsAssignation;
+
+    public PositionsAssignationFilter(Map<Integer, Term> positionsAssignation) {
+        this.positionsAssignation = positionsAssignation;
+    }
+
+    @Override
+    public boolean test(List<Term> terms) {
+        return positionsAssignation.keySet().stream()
+                .allMatch(position -> positionsAssignation.get(position).equals(terms.get(position)));
+    }
+}
diff --git a/integraal/integraal-query-evaluation/src/test/java/fr/boreal/test/query_evaluation/AtomicFOQueryEvaluatorBenchmark.java b/integraal/integraal-query-evaluation/src/test/java/fr/boreal/test/query_evaluation/AtomicFOQueryEvaluatorBenchmark.java
index ff7f97b3c999102d54cb70084984bd748af0816b..07a0062ee53c5930bfbefa924031ab446bf694f8 100644
--- a/integraal/integraal-query-evaluation/src/test/java/fr/boreal/test/query_evaluation/AtomicFOQueryEvaluatorBenchmark.java
+++ b/integraal/integraal-query-evaluation/src/test/java/fr/boreal/test/query_evaluation/AtomicFOQueryEvaluatorBenchmark.java
@@ -13,7 +13,9 @@ import fr.boreal.model.queryEvaluation.api.FOQueryEvaluator;
 import fr.boreal.query_evaluation.atomic.AtomicFOQueryEvaluator;
 import fr.boreal.storage.natives.SimpleInMemoryGraphStore;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
@@ -27,21 +29,34 @@ public class AtomicFOQueryEvaluatorBenchmark {
                 null
         );
         FOQueryEvaluator<Atom, MaterializedData> evaluator = new AtomicFOQueryEvaluator<>();
+        long start, end;
+        List<Long> times = new ArrayList<>();
 
         // Sequential execution benchmark
-        long start = System.nanoTime();
-        System.out.println(evaluator.evaluate(query, factBase, Set.of(TestData.x), new fr.boreal.model.logicalElements.impl.SubstitutionImpl())
-                .collect(Collectors.toSet()));
-        long end = System.nanoTime();
-        System.out.println("Sequential execution time: " + (end - start) / 1_000_000 + " ms");
+        for (int i = 0; i < 1000; i++) {
+            start = System.nanoTime();
+            //System.out.println(
+                    evaluator.evaluate(query, factBase, Set.of(TestData.x), new fr.boreal.model.logicalElements.impl.SubstitutionImpl())
+                    .collect(Collectors.toSet());
+            end = System.nanoTime();
+            times.add(end - start);
+            //System.out.println("Sequential execution time: " + (end - start) / 1_000_000 + " ms");
+        }
+        System.out.println("Sequential execution time: " + times.stream().mapToLong(i -> i).average().getAsDouble() / 1_000_000L + " ms");
+        times.clear();
 
         // Parallel execution benchmark
-        start = System.nanoTime();
-        System.out.println(evaluator.evaluate(query, factBase, Set.of(TestData.x), new fr.boreal.model.logicalElements.impl.SubstitutionImpl())
-                .parallel()
-                .collect(Collectors.toSet()));
-        end = System.nanoTime();
-        System.out.println("Parallel execution time: " + (end - start) / 1_000_000 + " ms");
+        for (int i = 0; i < 1000; i++) {
+            start = System.nanoTime();
+            //System.out.println(
+                    evaluator.evaluate(query, factBase, Set.of(TestData.x), new fr.boreal.model.logicalElements.impl.SubstitutionImpl())
+                    .parallel()
+                    .collect(Collectors.toSet());
+            end = System.nanoTime();
+            times.add(end - start);
+            //System.out.println("Parallel execution time: " + (end - start) / 1_000_000 + " ms");
+        }
+        System.out.println("Parallel execution time: " + times.stream().mapToLong(i -> i).average().getAsDouble() / 1_000_000L + " ms");
     }
 
     private static FactBase generateFactBase() {
diff --git a/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/rdbms/RDBMSStore.java b/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/rdbms/RDBMSStore.java
index cbc49e119ff45ece9d707817814ff7e2a77eeeb0..15a29c77625ad891ece45a4a5d8b3d6829380fa7 100644
--- a/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/rdbms/RDBMSStore.java
+++ b/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/rdbms/RDBMSStore.java
@@ -4,8 +4,8 @@ import com.github.jsonldjava.shaded.com.google.common.collect.Sets;
 import fr.boreal.model.data.readable.DatalogDelegable;
 import fr.boreal.model.data.readable.QueryDelegatableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
@@ -102,18 +102,13 @@ public class RDBMSStore implements FactBase, QueryDelegatableData, DatalogDelega
 	}
 
 	@Override
-	public BasicPattern getBasicPattern(Predicate predicate) {
-		BasicPatternBuilder bpb = new BasicPatternBuilder().withPredicate(predicate);
+	public AtomicPattern getBasicPattern(Predicate predicate) {
+		AtomicPatternBuilder bpb = new AtomicPatternBuilder().withPredicate(predicate);
 
 		bpb.withIndexablePatternsFunction(basicPattern ->
 				Sets.powerSet(IntStream.range(0, predicate.arity()).boxed().collect(Collectors.toSet())));
-		bpb.withCreateQueriesFunction((basicPattern, termSequence, preHomomorphism) ->
-				Stream.of(new BasicQuery(basicPattern, IntStream.range(0, predicate.arity()).boxed()
-						.filter(i -> termSequence.get(i).isGround()
-								|| preHomomorphism.keys().contains(termSequence.get(i)))
-						.map(i -> Map.entry(i, preHomomorphism.createImageOf(termSequence.get(i))))
-						.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
-				)));
+		bpb.withCreateQueriesFunction((basicPattern, positionsAssignation) ->
+				Stream.of(new BasicQuery(basicPattern, positionsAssignation)));
 
 		return bpb.build();
 	}
diff --git a/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/triplestore/TripleStoreStore.java b/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/triplestore/TripleStoreStore.java
index 6ff4d9fa6ecafeff546929c88d39ff7539b69001..08ca1f70ef2401c857890a56bc292467e531e8d7 100644
--- a/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/triplestore/TripleStoreStore.java
+++ b/integraal/integraal-storage/src/main/java/fr/boreal/storage/external/triplestore/TripleStoreStore.java
@@ -2,8 +2,8 @@ package fr.boreal.storage.external.triplestore;
 
 import com.github.jsonldjava.shaded.com.google.common.collect.Sets;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
@@ -22,12 +22,9 @@ import fr.boreal.model.query.api.FOQuery;
 import fr.boreal.model.query.factory.FOQueryFactory;
 import fr.boreal.model.rule.api.FORule;
 import fr.boreal.storage.external.evaluator.SparqlQueryEvaluator;
-import fr.lirmm.boreal.util.stream.filter.FilterIteratorWithoutException;
-import fr.lirmm.boreal.util.stream.filter.MatchFilter;
 import fr.lirmm.boreal.util.validator.rule.ConjunctionFormulaValidator;
 import fr.lirmm.boreal.util.validator.rule.PositiveFormulaValidator;
 import org.apache.commons.lang3.NotImplementedException;
-import org.checkerframework.checker.units.qual.C;
 import org.eclipse.rdf4j.model.Literal;
 import org.eclipse.rdf4j.model.*;
 import org.eclipse.rdf4j.query.TupleQueryResult;
@@ -168,22 +165,17 @@ public class TripleStoreStore implements FactBase, DatalogDelegable {
 	}
 
 	@Override
-	public BasicPattern getBasicPattern(Predicate predicate) {
-		BasicPatternBuilder bpb = new BasicPatternBuilder().withPredicate(predicate);
+	public AtomicPattern getBasicPattern(Predicate predicate) {
+		AtomicPatternBuilder bpb = new AtomicPatternBuilder().withPredicate(predicate);
 
 		if(predicate.arity() > 2) { // No supported pattern for predicates with a too big arity
 			bpb.withIndexablePatternsFunction(basicPattern -> Set.of());
-			bpb.withCreateQueriesFunction((basicPattern, termSequence, preHomomorphism) -> Stream.of());
+			bpb.withCreateQueriesFunction((basicPattern, positionsAssignation) -> Stream.of());
 		} else {
 			bpb.withIndexablePatternsFunction(basicPattern ->
 					Sets.powerSet(IntStream.range(0, predicate.arity()).boxed().collect(Collectors.toSet())));
-			bpb.withCreateQueriesFunction((basicPattern, termSequence, preHomomorphism) ->
-					Stream.of(new BasicQuery(basicPattern, IntStream.range(0, predicate.arity()).boxed()
-							.filter(i -> termSequence.get(i).isGround()
-									|| preHomomorphism.keys().contains(termSequence.get(i)))
-							.map(i -> Map.entry(i, preHomomorphism.createImageOf(termSequence.get(i))))
-							.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
-					)));
+			bpb.withCreateQueriesFunction((basicPattern, positionsAssignation) ->
+					Stream.of(new BasicQuery(basicPattern, positionsAssignation)));
 		}
 
 		return bpb.build();
diff --git a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/DefaultInMemoryAtomSet.java b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/DefaultInMemoryAtomSet.java
index 79a39f62c9c9615128789d0763748cce022af89a..acc7344a04b6ee71a639322dcb3fed590d98adf1 100644
--- a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/DefaultInMemoryAtomSet.java
+++ b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/DefaultInMemoryAtomSet.java
@@ -4,18 +4,14 @@
 package fr.boreal.storage.natives;
 
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.kb.api.FactBaseType;
 import fr.boreal.model.kb.impl.FactBaseDescription;
 import fr.boreal.model.logicalElements.api.*;
-import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
-import fr.lirmm.boreal.util.AtomType;
-import fr.lirmm.boreal.util.stream.filter.FilterIteratorWithoutException;
-import fr.lirmm.boreal.util.stream.filter.TypeFilter;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -89,11 +85,11 @@ public class DefaultInMemoryAtomSet implements FactBase {
 	}
 
 	@Override
-	public BasicPattern getBasicPattern(Predicate predicate) {
-		BasicPatternBuilder builder = new BasicPatternBuilder().withPredicate(predicate);
+	public AtomicPattern getBasicPattern(Predicate predicate) {
+		AtomicPatternBuilder builder = new AtomicPatternBuilder().withPredicate(predicate);
 		builder.withIndexablePatternsFunction(basicPattern -> (Set<Set<Integer>>) Stream.of(Set.of()));
 		builder.withCreateQueriesFunction(
-				(basicPattern, termSequence, preHomomorphism) -> Stream.of(new BasicQuery(basicPattern, Map.of())));
+				(basicPattern, positionsAssignation) -> Stream.of(new BasicQuery(basicPattern, Map.of())));
 		return builder.build();
 	}
 
diff --git a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/FactBaseDelAtomsWrapper.java b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/FactBaseDelAtomsWrapper.java
index 74dedb2f0429d0bad290e83df153bffcd33526b0..950a4f7a7f71aa66e3e58fdd5ba298b0fc3f0f38 100644
--- a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/FactBaseDelAtomsWrapper.java
+++ b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/FactBaseDelAtomsWrapper.java
@@ -1,7 +1,7 @@
 package fr.boreal.storage.natives;
 
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
+import fr.boreal.model.data.readable.query.AtomicPattern;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.ColumnType;
@@ -167,7 +167,7 @@ public class FactBaseDelAtomsWrapper implements FactBase {
     }
 
     @Override
-    public BasicPattern getBasicPattern(Predicate predicate) {
+    public AtomicPattern getBasicPattern(Predicate predicate) {
         return this.factBase.getBasicPattern(predicate);
     }
 
diff --git a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/SimpleInMemoryGraphStore.java b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/SimpleInMemoryGraphStore.java
index 50b81c3a755b1e63da32d66c3be245de9a8dc6ca..a88418fd372599c7617121af03633a0b8f228999 100644
--- a/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/SimpleInMemoryGraphStore.java
+++ b/integraal/integraal-storage/src/main/java/fr/boreal/storage/natives/SimpleInMemoryGraphStore.java
@@ -1,22 +1,14 @@
 package fr.boreal.storage.natives;
 
-import com.google.common.collect.Sets;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
 import fr.boreal.model.kb.api.FactBaseType;
 import fr.boreal.model.kb.impl.FactBaseDescription;
 import fr.boreal.model.logicalElements.api.*;
-import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
-import fr.boreal.model.query.api.Query;
-import fr.lirmm.boreal.util.AtomType;
-import fr.lirmm.boreal.util.stream.CloseableIteratorAdapter;
-import fr.lirmm.boreal.util.stream.CloseableIteratorWithoutException;
-import fr.lirmm.boreal.util.stream.filter.FilterIteratorWithoutException;
-import fr.lirmm.boreal.util.stream.filter.TypeFilter;
 import fr.lirmm.boreal.util.validator.rule.ConjunctionFormulaValidator;
 import fr.lirmm.boreal.util.validator.rule.PositiveFormulaValidator;
 
@@ -347,18 +339,16 @@ public class SimpleInMemoryGraphStore implements FactBase {
     }
 
     @Override
-    public BasicPattern getBasicPattern(Predicate predicate) {
-        BasicPatternBuilder bpb = new BasicPatternBuilder().withPredicate(predicate);
+    public AtomicPattern getBasicPattern(Predicate predicate) {
+        AtomicPatternBuilder bpb = new AtomicPatternBuilder().withPredicate(predicate);
         bpb.withIndexablePatternsFunction(basicPattern -> Stream.concat(
                         Stream.of(new HashSet<Integer>()),
                         IntStream.range(0, predicate.arity()).boxed().map(Set::of))
                 .collect(Collectors.toSet()));
-        bpb.withCreateQueriesFunction((basicPattern, termSequence, preHomomorphism) ->
+        bpb.withCreateQueriesFunction((basicPattern, positionsAssignation) ->
             Stream.concat(Stream.of(new BasicQuery(basicPattern, Map.of())),
-                    IntStream.range(0, predicate.arity()).boxed()
-                            .filter(i -> termSequence.get(i).isGround()
-                                    || preHomomorphism.keys().contains(termSequence.get(i)))
-                            .map(i -> Map.of(i, preHomomorphism.createImageOf(termSequence.get(i))))
+                    positionsAssignation.keySet().stream()
+                            .map(i -> Map.of(i, positionsAssignation.get(i)))
                             .map(assignation -> new BasicQuery(basicPattern, assignation))
             ));
 
diff --git a/integraal/integraal-storage/src/test/java/fr/boreal/test/storage/FactBaseCommonTests.java b/integraal/integraal-storage/src/test/java/fr/boreal/test/storage/FactBaseCommonTests.java
index 775d03bf68611f2af588acf0486a203648379122..ea757d302fe37fe2a07fc837b7baa7c3c1d800cb 100644
--- a/integraal/integraal-storage/src/test/java/fr/boreal/test/storage/FactBaseCommonTests.java
+++ b/integraal/integraal-storage/src/test/java/fr/boreal/test/storage/FactBaseCommonTests.java
@@ -1,7 +1,7 @@
 package fr.boreal.test.storage;
 
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
+import fr.boreal.model.data.readable.query.AtomicPattern;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormulaConjunction;
 import fr.boreal.model.formula.factory.FOFormulaFactory;
@@ -19,6 +19,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import java.util.stream.Stream;
 
 // TODO: this class was quickly adapted from the tests for FactBaseDelAtomsWrapper, more test cases should be added
@@ -659,12 +660,17 @@ public class FactBaseCommonTests {
     @MethodSource("provideFactBases")
     public void testEvaluate(FactBase base) throws EvaluationException {
         for (Atom a: base) {
-            BasicPattern basicPattern = base.getBasicPattern(a.getPredicate());
-            if (!basicPattern.hasAssignedMandatoryParameters(a.getTermSequence(), new SubstitutionImpl())) {
+            AtomicPattern atomicPattern = base.getBasicPattern(a.getPredicate());
+            Map<Integer, Term> positions = IntStream.range(0, a.getTermSequence().size()).boxed()
+                    .filter(i -> a.getTerm(i).isGround())
+                    .map(i -> Map.entry(i, a.getTerm(i)))
+                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+            if (!atomicPattern.hasAssignedMandatoryParameters(positions)) {
                 continue;
             }
 
-            Collection<BasicQuery> queries = basicPattern.createQueries(a.getTermSequence(), new SubstitutionImpl())
+            Collection<BasicQuery> queries = atomicPattern.createQueries(positions)
                     .toList();
             Assertions.assertFalse(queries.isEmpty());
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java b/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
index b81c6b9c07fb11dd1c04b665b27d0337d29ecddb..d55a108f8bafc77c71229c0b2de77d4b2ac4f24b 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/FederatedFactBase.java
@@ -1,10 +1,8 @@
 package fr.boreal.views;
 
-import com.google.common.collect.Iterators;
 import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.formula.api.FOFormula;
 import fr.boreal.model.kb.api.FactBase;
@@ -12,9 +10,8 @@ import fr.boreal.model.kb.api.FactBaseType;
 import fr.boreal.model.kb.impl.FactBaseDescription;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Predicate;
-import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
-import fr.boreal.views.datasource.AbstractViewWrapper;
+import fr.boreal.views.datasource.DataSource;
 
 import java.util.*;
 import java.util.stream.Collectors;
@@ -28,6 +25,7 @@ import java.util.stream.Stream;
  * @author Florent Tornil
  *
  */
+@Deprecated
 public class FederatedFactBase implements FactBase {
 
 	private final Map<Predicate, QueryableData> facts_by_storage;
@@ -64,9 +62,9 @@ public class FederatedFactBase implements FactBase {
 	 * @param default_base the default storage in writing mode
 	 * @param views        the views
 	 */
-	public FederatedFactBase(FactBase default_base, Collection<AbstractViewWrapper<String, ?>> views) {
+	public FederatedFactBase(FactBase default_base, Collection<DataSource<String, ?>> views) {
 		this(default_base);
-		for (AbstractViewWrapper<String, ?> view : views) {
+		for (DataSource<String, ?> view : views) {
             for (Iterator<Predicate> it = view.getPredicates().iterator(); it.hasNext(); ) {
                 Predicate p = it.next();
                 this.addStorage(p, view);
@@ -203,7 +201,7 @@ public class FederatedFactBase implements FactBase {
 	}
 
 	@Override
-	public BasicPattern getBasicPattern(Predicate predicate) {
+	public AtomicPattern getBasicPattern(Predicate predicate) {
 		return this.chooseStorage(predicate).getBasicPattern(predicate);
 	}
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/builder/ViewBuilder.java b/integraal/integraal-views/src/main/java/fr/boreal/views/builder/ViewBuilder.java
index 7ca63f762eadd0a993465328829025c2e9b4a5b9..ed09ed3be103085f2989062b889cfe49b6925b5f 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/builder/ViewBuilder.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/builder/ViewBuilder.java
@@ -8,6 +8,8 @@ import fr.boreal.storage.external.rdbms.driver.MySQLDriver;
 import fr.boreal.storage.external.rdbms.driver.PostgreSQLDriver;
 import fr.boreal.storage.external.rdbms.driver.SQLiteDriver;
 import fr.boreal.views.datasource.*;
+import fr.boreal.views.view.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameters;
 import fr.inria.integraal.view_parser.parser.*;
 
 import java.io.FileNotFoundException;
@@ -27,7 +29,7 @@ import java.util.Optional;
  */
 public class ViewBuilder {
 
-	private AbstractViewWrapper<String, ?> source;
+	private AbstractDataSource<String, ?> source;
 	private final List<ViewRegistration> views = new ArrayList<>();
 
 	private static final PredicateFactory pf = FactoryConstants.DEFAULT_PREDICATE_FACTORY;
@@ -51,7 +53,7 @@ public class ViewBuilder {
 	 * @param source the source to set
 	 * @return the current builder instance
 	 */
-	public ViewBuilder setWrapper(AbstractViewWrapper<String, ?> source) {
+	public ViewBuilder setWrapper(AbstractDataSource<String, ?> source) {
 		this.source = source;
 		return this;
 	}
@@ -64,7 +66,7 @@ public class ViewBuilder {
 	 * @return the current builder instance
 	 */
 	public ViewBuilder useHSQLDBSource(String url, String database) throws SQLException {
-		this.source = new SQLWrapper(new HSQLDBDriver(url, database));
+		this.source = new SQLDataSource(new HSQLDBDriver(url, database));
 		return this;
 	}
 
@@ -78,7 +80,7 @@ public class ViewBuilder {
 	 * @return the current builder instance
 	 */
 	public ViewBuilder useMySQLSource(String url, String database, String user, String password) throws SQLException {
-		this.source = new SQLWrapper(new MySQLDriver(url, database, user, password));
+		this.source = new SQLDataSource(new MySQLDriver(url, database, user, password));
 		return this;
 	}
 
@@ -92,7 +94,7 @@ public class ViewBuilder {
 	 * @return the current builder instance
 	 */
 	public ViewBuilder usePostgreSQLSource(String url, String database, String user, String password) throws SQLException {
-		this.source = new SQLWrapper(new PostgreSQLDriver(url, database, user, password));
+		this.source = new SQLDataSource(new PostgreSQLDriver(url, database, user, password));
 		return this;
 	}
 
@@ -103,7 +105,7 @@ public class ViewBuilder {
 	 * @return the current builder instance
 	 */
 	public ViewBuilder useSQLiteSource(String url) throws SQLException {
-		this.source = new SQLWrapper(new SQLiteDriver(url));
+		this.source = new SQLDataSource(new SQLiteDriver(url));
 		return this;
 	}
 
@@ -139,7 +141,7 @@ public class ViewBuilder {
 	 *
 	 * @return the configured source
 	 */
-	public AbstractViewWrapper<String, ?> build() {
+	public AbstractDataSource<String, ?> build() {
 		if (this.source == null) {
 			throw new IllegalStateException("Source must be set before building.");
 		}
@@ -220,8 +222,8 @@ public class ViewBuilder {
 	 * @return the wrappers
 	 * @throws ViewBuilderException if an exception occurs
 	 */
-	public static Collection<AbstractViewWrapper<String, ?>> createFactBases(String filename) throws ViewBuilderException {
-		Collection<AbstractViewWrapper<String, ?>> views = new ArrayList<>();
+	public static Collection<DataSource<String, ?>> loadDataSources(String filename) throws ViewBuilderException {
+		Collection<DataSource<String, ?>> views = new ArrayList<>();
 		try {
 			ViewDocument document = ViewParser.parse(filename);
 
@@ -231,42 +233,42 @@ public class ViewBuilder {
 					throw new ViewBuilderException("Unknown datasource for type " + d.getType());
 				}
 
-				AbstractViewWrapper<String, ?> wrapper = switch (typeOpt.get()) {
+				AbstractDataSource<String, ?> wrapper = switch (typeOpt.get()) {
 					case HSQLDB -> {
 						String url = d.getParameters().get("url");
 						String database = d.getParameters().get("database");
-						yield new SQLWrapper(new HSQLDBDriver(url, database));
+						yield new SQLDataSource(new HSQLDBDriver(url, database));
 					}
 					case SQLITE -> {
 						String url = d.getParameters().get("url");
-						yield new SQLWrapper(new SQLiteDriver(url));
+						yield new SQLDataSource(new SQLiteDriver(url));
 					}
 					case MYSQL -> {
 						String url = d.getParameters().get("url");
 						String database = d.getParameters().get("database");
 						String user = d.getParameters().get("user");
 						String password = d.getParameters().get("password");
-						yield new SQLWrapper(new MySQLDriver(url, database, user, password));
+						yield new SQLDataSource(new MySQLDriver(url, database, user, password));
 					}
 					case POSTGRESQL -> {
 						String url = d.getParameters().get("url");
 						String database = d.getParameters().get("database");
 						String user = d.getParameters().get("user");
 						String password = d.getParameters().get("password");
-						yield new SQLWrapper(new PostgreSQLDriver(url, database, user, password));
+						yield new SQLDataSource(new PostgreSQLDriver(url, database, user, password));
 					}
 					case SPARQLENDPOINT -> {
 						String url = d.getParameters().get("url");
-						yield new SPARQLWrapper(url);
+						yield new SPARQLDataSource(url);
 					}
 					case MONGODB -> {
 						// TODO Get parameters
-						yield new MongoDBWrapper("lot of params", "", "", List.of(""));
+						yield new MongoDBDataSource("lot of params", "", "", List.of(""));
 					}
 					case WEBAPI -> {
 						String user = d.getParameters().get("user");
 						String password = d.getParameters().get("password");
-						yield new WebAPIWrapper(user, password);
+						yield new WebAPIDataSource(user, password);
 					}
 				};
 
@@ -310,10 +312,10 @@ public class ViewBuilder {
 	 * @return the wrappers
 	 * @throws ViewBuilderException if an exception occur
 	 */
-	public static Collection<AbstractViewWrapper<String, ?>> createFactBases(Collection<String> filePaths) throws ViewBuilderException {
-		Collection<AbstractViewWrapper<String, ?>> views = new ArrayList<>();
+	public static Collection<DataSource<String, ?>> loadDataSources(Collection<String> filePaths) throws ViewBuilderException {
+		Collection<DataSource<String, ?>> views = new ArrayList<>();
 		for (String filename : filePaths) {
-			views.addAll(ViewBuilder.createFactBases(filename));
+			views.addAll(ViewBuilder.loadDataSources(filename));
 		}
 		return views;
 	}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractViewWrapper.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractDataSource.java
similarity index 50%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractViewWrapper.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractDataSource.java
index a1dcea31e2b6b488e533d976a067f5de9147ccae..d88d9aa33857e5fe470fb3fcb917bf13fb8946a2 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractViewWrapper.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/AbstractDataSource.java
@@ -1,10 +1,8 @@
 package fr.boreal.views.datasource;
 
-import com.mongodb.internal.operation.MapReduceToCollectionOperation;
-import fr.boreal.model.data.readable.QueryableData;
 import fr.boreal.model.data.readable.exception.EvaluationException;
-import fr.boreal.model.data.readable.query.BasicPattern;
-import fr.boreal.model.data.readable.query.BasicPatternBuilder;
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.data.readable.query.AtomicPatternBuilder;
 import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.*;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
@@ -13,32 +11,33 @@ import fr.boreal.model.logicalElements.impl.SubstitutionImpl;
 import fr.boreal.storage.external.evaluator.NativeQueryEvaluator;
 import fr.boreal.views.specializer.Specializer;
 import fr.boreal.views.transformer.Transformer;
+import fr.boreal.views.view.View;
+import fr.boreal.views.view.ViewImpl;
+import fr.boreal.views.view.ViewParameters;
 import fr.lirmm.boreal.util.stream.filter.FilterIteratorWithoutException;
 import fr.lirmm.boreal.util.stream.filter.MatchFilter;
 
 import java.util.*;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
 /**
  * This wrapper represents data-sources accessed using mappings.
- * Theses are sources queried by user-given queries with read-only rights
+ * These sources are queried by user-given queries with read-only rights
  * <br/>
  * A data-source can define several relational views, which associate a Predicate (of the relational view) to a specification of this view 
  *
  * @param <NativeQueryType> the type used to represent the native query
  * @param <NativeResultType> the type used to represent the results as the native format
  */
-public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> implements QueryableData {
+public abstract class AbstractDataSource<NativeQueryType, NativeResultType> implements DataSource<NativeQueryType, NativeResultType> {
 
 	private String name; 
 	private final Specializer<NativeQueryType> specializer;
 	private final NativeQueryEvaluator<NativeQueryType, NativeResultType> evaluator;
 	private final Transformer<NativeResultType> transformer;
 
-	private final Map<Predicate, ViewParameters<NativeQueryType>> viewByPredicate;
+	private final Map<Predicate, View<NativeQueryType>> viewByPredicate;
 
 	/**
 	 * Create a new wrapper over a data-source with a relational view
@@ -46,8 +45,8 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param evaluator to evaluate the native query
 	 * @param transformer to transform the native result into atoms
 	 */
-	public AbstractViewWrapper(Specializer<NativeQueryType> specializer, NativeQueryEvaluator<NativeQueryType, NativeResultType> evaluator, Transformer<NativeResultType> transformer) {
-		this(null, specializer,evaluator,transformer);
+	protected AbstractDataSource(Specializer<NativeQueryType> specializer, NativeQueryEvaluator<NativeQueryType, NativeResultType> evaluator, Transformer<NativeResultType> transformer) {
+		this(null, specializer, evaluator, transformer);
 	}
 	
 	/**
@@ -57,7 +56,7 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param evaluator to evaluate the native query
 	 * @param transformer to transform the native result into atoms
 	 */
-	public AbstractViewWrapper(String name, Specializer<NativeQueryType> specializer, NativeQueryEvaluator<NativeQueryType, NativeResultType> evaluator, Transformer<NativeResultType> transformer) {
+	protected AbstractDataSource(String name, Specializer<NativeQueryType> specializer, NativeQueryEvaluator<NativeQueryType, NativeResultType> evaluator, Transformer<NativeResultType> transformer) {
 		this.name = name;
 		this.specializer = specializer;
 		this.evaluator = evaluator;
@@ -72,22 +71,22 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param viewParameters associated to this view predicate
 	 */
 	public void registerView(Predicate p, ViewParameters<NativeQueryType> viewParameters) {
-		this.viewByPredicate.put(p, viewParameters);
+		this.viewByPredicate.put(p, new ViewImpl<>(p, Map.of(), viewParameters));
 	}
 
 	/**
 	 * @param p the predicate representing the relational view
 	 * @return the native query associated to the view predicate p
 	 */
-	public ViewParameters<NativeQueryType> getViewParameters(Predicate p) {
-		return this.viewByPredicate.get(p);
+	private ViewParameters<NativeQueryType> getViewParameters(Predicate p) {
+		return this.viewByPredicate.get(p).getViewParameters();
 	}
 
 	/**
 	 * @param p the predicate representing the relational view
 	 * @return the native query specializer associated to the view predicate p
 	 */
-	public Specializer<NativeQueryType> getSpecializer(Predicate p) {
+	private Specializer<NativeQueryType> getSpecializer(Predicate p) {
 		return this.specializer;
 	}
 
@@ -95,7 +94,7 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param p the predicate representing the relational view
 	 * @return the native query evaluator associated to the view predicate p
 	 */
-	public NativeQueryEvaluator<NativeQueryType, NativeResultType> getEvaluator(Predicate p) {
+	private NativeQueryEvaluator<NativeQueryType, NativeResultType> getEvaluator(Predicate p) {
 		return this.evaluator;
 	}
 
@@ -103,73 +102,43 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param p the predicate representing the relational view
 	 * @return the native result transformer associated to the view predicate p
 	 */
-	public Transformer<NativeResultType> getTransformer(Predicate p) {
+	private Transformer<NativeResultType> getTransformer(Predicate p) {
 		return this.transformer;
 	}
 
 	/**
 	 * @return the predicates corresponding to the relational views of the datasource
 	 */
+	@Override
 	public Collection<Predicate> getPredicates() {
 		return this.viewByPredicate.keySet();
 	}
 
 	@Override
 	public Stream<List<Term>> evaluate(BasicQuery query) throws EvaluationException {
-		List<Term> terms = new ArrayList<>(query.getPredicate().arity());
-		Substitution substitution = new SubstitutionImpl();
-		for (int i = 0; i < query.getPredicate().arity(); i++) {
-			Variable v = SameObjectTermFactory.instance().createOrGetFreshVariable();
-			terms.add(v);
-			if (query.getAssignedTerms().containsKey(i)) {
-				substitution.add(v, query.getAssignedTerms().get(i));
-			}
-		}
-
-		return StreamSupport.stream(
-				Spliterators.spliteratorUnknownSize(
-						this.match(new AtomImpl(query.getPredicate(), terms), substitution),
-						0),
-				false)
-				.map(Atom::getTermSequence);
-	}
-
-	@Override
-	public Optional<Long> estimateBound(BasicQuery query) {
-		return Optional.empty();
-	}
-
-	@Override
-	public BasicPattern getBasicPattern(Predicate predicate) {
-		return new BasicPatternBuilder()
-				.withPredicate(predicate)
-				.withIndexablePatternsFunction((basicPattern -> Set.of()))
-				.withCreateQueriesFunction(((basicPattern, terms, substitution) -> Stream.of(new BasicQuery(
-						basicPattern,
-						IntStream.range(0, predicate.arity()).boxed()
-						.filter(i -> terms.get(i).isGround() || substitution.keys().contains(terms.get(i)))
-								.map(i -> Map.entry(i, substitution.createImageOf(terms.get(i))))
-								.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
-				))))
-				.build();
-	}
-
-	public Iterator<Atom> match(Atom a, Substitution s) {
-		Predicate p = a.getPredicate();
+		Predicate p = query.getPredicate();
 		ViewParameters<NativeQueryType> viewParameters = this.getViewParameters(p);
 
-		ViewParameters<NativeQueryType> specializedViewParameters = this.getSpecializer(p).specialize(viewParameters, a, s);
+		ViewParameters<NativeQueryType> specializedViewParameters =
+				this.getSpecializer(p).specialize(viewParameters, query);
 
 		Optional<NativeResultType> nativeResult = this.getEvaluator(p).evaluate(specializedViewParameters.nativeQuery());
 		if(nativeResult.isEmpty()) {
-			return Collections.emptyIterator();
+			return Stream.empty();
 		} else {
-			Iterator<Atom> matched_atoms = this.getTransformer(p).transform(nativeResult.get(), specializedViewParameters, a, s);
-			return new FilterIteratorWithoutException<>(matched_atoms, new MatchFilter(a, s));
+			return this.getTransformer(p).transform(nativeResult.get(), specializedViewParameters, query);
 		}
+	}
 
+	@Override
+	public Optional<Long> estimateBound(BasicQuery query) {
+		return Optional.empty();
 	}
 
+	@Override
+	public AtomicPattern getBasicPattern(Predicate predicate) {
+		return this.viewByPredicate.get(predicate);
+	}
 
 	/**
 	 * @return an optional that contains the datasource name if there is one
@@ -182,35 +151,6 @@ public abstract class AbstractViewWrapper<NativeQueryType, NativeResultType> imp
 	 * @param name the new datasource name
 	 */
 	public void setName(String name) {
-		this.name=name;
-	}
-	
-
-
-	/////////////////////////////////////////////////
-	// FactStorage methods
-	/////////////////////////////////////////////////
-
-	/*@Override
-	public Iterator<Atom> match(Atom a, Substitution s) {
-		Predicate p = a.getPredicate();
-		ViewParameters<NativeQueryType> viewParameters = this.getViewParameters(p);
-
-		ViewParameters<NativeQueryType> specializedViewParameters = this.getSpecializer(p).specialize(viewParameters, a, s);
-
-		Optional<NativeResultType> nativeResult = this.getEvaluator(p).evaluate(specializedViewParameters.nativeQuery());
-		if(nativeResult.isEmpty()) {
-			return Collections.emptyIterator();
-		} else {
-			Iterator<Atom> matched_atoms = this.getTransformer(p).transform(nativeResult.get(), specializedViewParameters, a, s);
-			return new FilterIteratorWithoutException<>(matched_atoms, new MatchFilter(a, s));
-		}
-
+		this.name = name;
 	}
-
-	@Override
-	public Iterator<Atom> match(Atom a) {
-		return this.match(a, new SubstitutionImpl());
-	}*/
-
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/DataSource.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/DataSource.java
new file mode 100644
index 0000000000000000000000000000000000000000..d4e7b9be293949961150feec966077f6a7cda997
--- /dev/null
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/DataSource.java
@@ -0,0 +1,10 @@
+package fr.boreal.views.datasource;
+
+import fr.boreal.model.data.readable.QueryableData;
+
+import java.util.Optional;
+
+public interface DataSource<NativeQueryType, NativeResultType>
+        extends QueryableData {
+    Optional<String> getName();
+}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBWrapper.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBDataSource.java
similarity index 80%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBWrapper.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBDataSource.java
index dfeb11e2bb421ceff1a48c8888bd9f930753f778..21e3795dc59feab6d255e8344f697b35a1f19bc5 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBWrapper.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/MongoDBDataSource.java
@@ -16,7 +16,7 @@ import fr.boreal.views.transformer.MongoDocumentTransformer;
  * @author Florent Tornil
  *
  */
-public class MongoDBWrapper extends AbstractViewWrapper<String, MongoCursor<Document>> {
+public class MongoDBDataSource extends AbstractDataSource<String, MongoCursor<Document>> {
 
 	/**
 	 * Create a new datasource over a mongodb server
@@ -25,7 +25,7 @@ public class MongoDBWrapper extends AbstractViewWrapper<String, MongoCursor<Docu
 	 * @param collection the mongodb collection
 	 * @param projectionPaths the paths to project results
 	 */
-	public MongoDBWrapper(String url, String database, String collection, List<String> projectionPaths) {
+	public MongoDBDataSource(String url, String database, String collection, List<String> projectionPaths) {
 		super(new MandatoryParameterStringReplacement(), new MongoDBQueryEvaluator(url, database, collection), new MongoDocumentTransformer(projectionPaths));
 	}
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLWrapper.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLDataSource.java
similarity index 84%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLWrapper.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLDataSource.java
index edf6f0f8dbb81844aec49a9f7f38417f3db3e8c3..5d77d3ace95baac53ce1dccefee68ce963597e4c 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLWrapper.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SPARQLDataSource.java
@@ -13,13 +13,13 @@ import fr.boreal.views.transformer.SparqlTuplesTransformer;
  * @author Florent Tornil
  *
  */
-public class SPARQLWrapper extends AbstractViewWrapper<String, TupleQueryResult> {
+public class SPARQLDataSource extends AbstractDataSource<String, TupleQueryResult> {
 
 	/**
 	 * Create a new datasource on the endpoint
 	 * @param endpointUrl the url of the SPARQL endpoint
 	 */
-	public SPARQLWrapper(String endpointUrl) {		
+	public SPARQLDataSource(String endpointUrl) {
 		super(new MandatoryParameterStringReplacement(), new SparqlQueryEvaluator(new SPARQLRepository(endpointUrl)), new SparqlTuplesTransformer());
 	}
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLWrapper.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLDataSource.java
similarity index 82%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLWrapper.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLDataSource.java
index 7dcee8cfbc35280af15ed123ddca2fecfd39e55f..8ef3f209798fab185bf0c44c9922829274e914e3 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLWrapper.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/SQLDataSource.java
@@ -14,14 +14,14 @@ import fr.boreal.views.transformer.SQLTuplesTransformer;
  * @author Florent Tornil
  *
  */
-public class SQLWrapper extends AbstractViewWrapper<String, List<Object[]>> {
+public class SQLDataSource extends AbstractDataSource<String, List<Object[]>> {
 
 	/**
 	 * Create a new datasource on a RDBMS
 	 * @param driver the SQL driver
 	 * @throws SQLException if an error occur
 	 */
-	public SQLWrapper(RDBMSDriver driver) throws SQLException {
+	public SQLDataSource(RDBMSDriver driver) throws SQLException {
 		super(new MandatoryParameterStringReplacement(), new SQLQueryEvaluator(driver), new SQLTuplesTransformer());
 	}
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIWrapper.java b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIDataSource.java
similarity index 81%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIWrapper.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIDataSource.java
index 15ccf4d36e297aa34491bc007526f96c947b5a15..17723aa030238c94bfa027f71cbcc26e0ef777e6 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIWrapper.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/WebAPIDataSource.java
@@ -10,14 +10,14 @@ import fr.boreal.views.transformer.JSONStringTransformer;
  * @author Florent Tornil
  *
  */
-public class WebAPIWrapper extends AbstractViewWrapper<String, String> {
+public class WebAPIDataSource extends AbstractDataSource<String, String> {
 
 	/**
 	 * Create a new datasource on a web api
 	 * @param username the user login name
 	 * @param password the user login password
 	 */
-	public WebAPIWrapper(String username, String password) {
+	public WebAPIDataSource(String username, String password) {
 		super(	new MandatoryParameterStringReplacement(),
 				new HttpQueryEvaluator(username, password),
 				new JSONStringTransformer());
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/MandatoryParameterStringReplacement.java b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/MandatoryParameterStringReplacement.java
index ccfcd473075cbed9551f37a15fd5fce5c0bb10c2..c61f178d409227a3159e857248d50d3b543b3c54 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/MandatoryParameterStringReplacement.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/MandatoryParameterStringReplacement.java
@@ -4,10 +4,11 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
-import fr.boreal.views.datasource.ViewParameterSignature;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameters;
 
 /**
  * This specializer replaces all occurrences of specifics substrings from the initial String query
@@ -20,19 +21,19 @@ import fr.boreal.views.datasource.ViewParameters;
 public class MandatoryParameterStringReplacement implements Specializer<String> {
 
 	@Override
-	public ViewParameters<String> specialize(ViewParameters<String> parameters, Atom a, Substitution s) {
+	public ViewParameters<String> specialize(ViewParameters<String> parameters, BasicQuery basicQuery) {
 		String specializedQuery = parameters.nativeQuery();
 		Optional<String> specializedPosition = parameters.position();
 		List<ViewParameterSignature> specializedViewElements = new ArrayList<>();
 		
 		List<ViewParameterSignature> viewElements = parameters.viewElements();
-		for(int i = 0; i < a.getPredicate().arity(); ++i) {
+		for(int i = 0; i < basicQuery.getPredicate().arity(); ++i) {
 			ViewParameterSignature element = viewElements.get(i);
 			Optional<String> specializedSelection = element.selection();
 			if(element.isMandatory()) {
-				if(s.createImageOf(a.getTerm(i)).isFrozen(s)) {
+				if(basicQuery.getAssignedTerms().containsKey(i)) {
 					String pattern = element.mandatoryAs().orElseThrow();
-					String value = s.createImageOf(a.getTerm(i)).label();
+					String value = basicQuery.getTerm(i).orElseThrow().label();
 					
 					specializedQuery = specializedQuery.replaceAll(pattern, value);
 					if(specializedPosition.isPresent()) {
@@ -42,7 +43,7 @@ public class MandatoryParameterStringReplacement implements Specializer<String>
 						specializedSelection = Optional.of(specializedSelection.get().replaceAll(pattern, value));
 					}
 				} else {
-					throw new IllegalArgumentException("The view " + a.getPredicate() + " was called without a mandatory value for the parameter "
+					throw new IllegalArgumentException("The view " + basicQuery.getPredicate() + " was called without a mandatory value for the parameter "
 							+ element.mandatoryAs().orElseThrow());
 				}
 			}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/NoSpecializer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/NoSpecializer.java
index 32f982b985047a4684537e61efa5917ed3a1c4ad..9e417a44e9b41ad556ca265f4c336af9b0ce668f 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/NoSpecializer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/NoSpecializer.java
@@ -1,8 +1,9 @@
 package fr.boreal.views.specializer;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameters;
 
 /**
  * This specializer do nothing.
@@ -14,7 +15,7 @@ import fr.boreal.views.datasource.ViewParameters;
 public class NoSpecializer<NativeQueryType> implements Specializer<NativeQueryType> {
 
 	@Override
-	public ViewParameters<NativeQueryType> specialize(ViewParameters<NativeQueryType> parameters, Atom filter, Substitution s) {
+	public ViewParameters<NativeQueryType> specialize(ViewParameters<NativeQueryType> parameters, BasicQuery basicQuery) {
 		return parameters;
 	}
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/OrderedStringReplacementSpecializer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/OrderedStringReplacementSpecializer.java
index 15539f0d6952fd5e17b1d6ab319c69a3522cbade..8679978f395e7c562fb5c2be6ab05ce547e90b22 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/OrderedStringReplacementSpecializer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/OrderedStringReplacementSpecializer.java
@@ -1,9 +1,12 @@
 package fr.boreal.views.specializer;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameters;
+
+import java.util.Optional;
 
 /**
  * This specializer replaces a given placeholder from the initial String query by the frozen positions of the given atom.
@@ -33,13 +36,13 @@ public class OrderedStringReplacementSpecializer implements Specializer<String>
 	/////////////////////////////////////////////////
 
 	@Override
-	public ViewParameters<String> specialize(ViewParameters<String> parameters, Atom a, Substitution s) {
+	public ViewParameters<String> specialize(ViewParameters<String> parameters, BasicQuery basicQuery) {
 		String query = parameters.nativeQuery();
 		int i = 0;
-		while(i < a.getPredicate().arity() && query.contains(this.placeholder)) {
-			Term t_a = a.getTerm(i);
-			if(t_a.isFrozen(s)) {
-				String replacement = s.createImageOf(t_a).label();
+		while(i < basicQuery.getPredicate().arity() && query.contains(this.placeholder)) {
+			Optional<Term> t_a = basicQuery.getTerm(i);
+			if(t_a.isPresent()) {
+				String replacement = t_a.get().label();
 				query = query.replaceFirst(this.placeholder, replacement);
 				++i;
 			}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/Specializer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/Specializer.java
index 3fdac708c86327ea3b6b0e97f5afd7248c479569..ef360d6ac5c0e37c1f8c7de82fef1ae9add2fdfb 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/Specializer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/specializer/Specializer.java
@@ -1,8 +1,9 @@
 package fr.boreal.views.specializer;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameters;
 
 /**
  * Specialize the native query in order to take into account the given parameters.
@@ -19,5 +20,5 @@ public interface Specializer<NativeQueryType> {
 	 * @param s substitution that specializes the given atom
 	 * @return the specialized view parameters
 	 */
-	ViewParameters<NativeQueryType> specialize(ViewParameters<NativeQueryType> parameters, Atom a, Substitution s);
+	ViewParameters<NativeQueryType> specialize(ViewParameters<NativeQueryType> parameters, BasicQuery basicQuery);
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/AbstractTransformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/AbstractTransformer.java
index 4dc052ac14d7ba9b87a2f6c2174c195920d3758f..ca01941895cfafb2590cd7f8b7f436c260493230 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/AbstractTransformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/AbstractTransformer.java
@@ -1,20 +1,18 @@
 package fr.boreal.views.transformer;
 
-import fr.boreal.model.logicalElements.api.Atom;
-import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Term;
-import fr.boreal.model.logicalElements.impl.AtomImpl;
-import fr.boreal.views.datasource.ViewParameterSignature;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameters;
 import fr.boreal.views.transformer.missingValue.FreezeHandler;
 import fr.boreal.views.transformer.missingValue.IgnoreHandler;
 import fr.boreal.views.transformer.missingValue.MissingValueHandler;
 import fr.boreal.views.transformer.missingValue.OptionalHandler;
 
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
+import java.util.stream.Stream;
 
 /**
  * @author Florent Tornil
@@ -24,10 +22,10 @@ import java.util.Optional;
 public abstract class AbstractTransformer<NativeResultType> implements Transformer<NativeResultType> {
 
 	@Override
-	public Iterator<Atom> transform(NativeResultType nativeResults,
-			ViewParameters<?> parameters,
-			Atom a, Substitution s) {
-		return this.transform(nativeResults, parameters.viewElements(), a, s);
+	public Stream<List<Term>> transform(NativeResultType nativeResults,
+										ViewParameters<?> parameters,
+										BasicQuery basicQuery) {
+		return this.transform(nativeResults, parameters.viewElements(), basicQuery);
 	}
 
 	/**
@@ -35,34 +33,31 @@ public abstract class AbstractTransformer<NativeResultType> implements Transform
 	 * Some implementations may compute a filter using the given atom when converting the results
 	 * @param nativeResults the native results representing atoms
 	 * @param viewElements the signature of the view's tuples
-	 * @param a the atom used for filtering / instantiation
-	 * @param s the pre-affectation from variables of <code>a</code> to terms
-	 * @return all the atoms represented by the native results
+	 * @param basicQuery the query to answer
+	 * @return all the term sequences represented by the native results
 	 */
-	public abstract Iterator<Atom> transform(NativeResultType nativeResults, List<ViewParameterSignature> viewElements, Atom a,
-			Substitution s);
+	protected abstract Stream<List<Term>> transform(NativeResultType nativeResults, List<ViewParameterSignature> viewElements, BasicQuery basicQuery);
 
 	/**
 	 * Convert a native object into the corresponding atom
 	 * @param nativeResult the native object
 	 * @param signatures the signature of the view's tuples
-	 * @param a atom used for filtering
-	 * @param s pre affectation
-	 * @return the Term corresponding to the given object with respect to the signature
+	 * @param basicQuery the query to answer
+	 * @return the term sequence represented by the native results
 	 */
-	public Optional<Atom> transformAtom(Object nativeResult, List<ViewParameterSignature> signatures, Atom a, Substitution s) {
-		int arity = a.getPredicate().arity();
+	protected Optional<List<Term>> transformNativeResult(Object nativeResult, List<ViewParameterSignature> signatures, BasicQuery basicQuery) {
+		int arity = basicQuery.getPredicate().arity();
 
 		List<Term> terms = new ArrayList<>(arity);
 		int nativeResultIndex = 0;
 		for(int signatureIndex = 0; signatureIndex < signatures.size(); ++signatureIndex) {
 			ViewParameterSignature signature = signatures.get(signatureIndex);
 			if(signature.isMandatory()) {
-				Term givenValue = s.createImageOf(a.getTerm(signatureIndex));
+				Term givenValue = basicQuery.getTerm(signatureIndex).orElseThrow();
 				terms.add(givenValue);
 			} else {
 				Object o = this.getObjectAtIndex(nativeResult, nativeResultIndex, signature);
-				Optional<Term> opt_t = this.transformTerm(o, signature, a, s);
+				Optional<Term> opt_t = this.transformTerm(o, signature);
 				if(opt_t.isEmpty()) {
 					return Optional.empty();
 				} else {
@@ -71,10 +66,10 @@ public abstract class AbstractTransformer<NativeResultType> implements Transform
 				}
 			}
 		}
-		return Optional.of(new AtomImpl(a.getPredicate(), terms));
+		return Optional.of(terms);
 	}
 
-	private Optional<Term> transformTerm(Object o, ViewParameterSignature signature, Atom a, Substitution s) {
+	private Optional<Term> transformTerm(Object o, ViewParameterSignature signature) {
 		if(this.isMissingValue(o)) {
 			MissingValueHandler missingHandler = switch (signature.missingValueHandling()) {
 			case "IGNORE" -> new IgnoreHandler();
@@ -84,7 +79,7 @@ public abstract class AbstractTransformer<NativeResultType> implements Transform
 			};
 			return missingHandler.handle();
 		} else {
-			return this.convertType(o, signature, a, s);
+			return this.convertType(o, signature);
 		}
 	}
 
@@ -95,23 +90,21 @@ public abstract class AbstractTransformer<NativeResultType> implements Transform
 	 * @param signature signature of the element of the tuple to get
 	 * @return the native object at the given position of the native result
 	 */
-	public abstract Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature);
+	protected abstract Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature);
 
 	/**
 	 * Does the given object represents the native datasource missing (NULL) value
 	 * @param o a native element
 	 * @return true iff o represents the native type missing value
 	 */
-	public abstract boolean isMissingValue(Object o);
+	protected abstract boolean isMissingValue(Object o);
 
 	/**
 	 * Convert a native object into the corresponding term
 	 * @param o the native object
 	 * @param signature the signature of the view's tuple for the position of o
-	 * @param a atom used for filtering
-	 * @param s pre affectation
 	 * @return the Term corresponding to the given object with respect to the signature
 	 */
-	public abstract Optional<Term> convertType(Object o, ViewParameterSignature signature, Atom a, Substitution s);
+	protected abstract Optional<Term> convertType(Object o, ViewParameterSignature signature);
 
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/JSONStringTransformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/JSONStringTransformer.java
index 50849bc4f41b74666642fa1b3dcff5ef88851a69..79863a8d1a18a986dde860454be8d96a93cac30b 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/JSONStringTransformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/JSONStringTransformer.java
@@ -2,15 +2,15 @@ package fr.boreal.views.transformer;
 
 import com.jayway.jsonpath.Configuration;
 import com.jayway.jsonpath.JsonPath;
-import fr.boreal.model.logicalElements.api.Atom;
-import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.factory.api.TermFactory;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
-import fr.boreal.views.datasource.ViewParameterSignature;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.views.view.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameters;
 
 import java.util.*;
+import java.util.stream.Stream;
 
 /**
  * Transform a String representing a JSON object into atoms.
@@ -42,38 +42,37 @@ public class JSONStringTransformer extends AbstractTransformer<String> {
 	/////////////////////////////////////////////////
 
 	@Override
-	public Iterator<Atom> transform(String nativeResults, ViewParameters<?> parameters, Atom a, Substitution s) {
-
-		Collection<Atom> atoms = new ArrayList<>();
+	public Stream<List<Term>> transform(String nativeResults, ViewParameters<?> parameters, BasicQuery basicQuery) {
 		Object document = Configuration.defaultConfiguration().jsonProvider().parse(nativeResults);
 		List<Object> jsonEntries = JsonPath.read(document, parameters.position().orElseThrow());
 		List<ViewParameterSignature> signatures = parameters.viewElements();
-		for(Object jsonEntry : jsonEntries) {
-			Optional<Atom> opt_viewAtom = this.transformAtom(jsonEntry, signatures, a, s);
-			opt_viewAtom.ifPresent(atoms::add);
-		}
-		return atoms.iterator();
+
+		return jsonEntries.stream()
+				.map(jsonEntry -> this.transformNativeResult(jsonEntry, signatures, basicQuery).orElse(null))
+				.filter(Objects::nonNull);
 	}
 
 	@Override
-	public Iterator<Atom> transform(String nativeResults, List<ViewParameterSignature> viewElements, Atom a,
-									Substitution s) {
+	protected Stream<List<Term>> transform(
+			String nativeResults,
+			List<ViewParameterSignature> viewElements,
+			BasicQuery basicQuery) {
 		throw new UnsupportedOperationException("[JSON Transformer] This transform method should not be called,"
 				+ " please use the one with the whole parameters object");
 	}
 
 	@Override
-	public boolean isMissingValue(Object o) {
+	protected boolean isMissingValue(Object o) {
 		return o == null;
 	}
 
 	@Override
-	public Optional<Term> convertType(Object o, ViewParameterSignature signature, Atom a, Substitution s) {
+	protected Optional<Term> convertType(Object o, ViewParameterSignature signature) {
 		return Optional.of(this.tf.createOrGetLiteral(o));
 	}
 
 	@Override
-	public Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
+	protected Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
 		return JsonPath.read(nativeResult, signature.selection().orElseThrow());
 	}
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/MongoDocumentTransformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/MongoDocumentTransformer.java
index 7077645c25bd163cef22afd7c7c82fc9c7ac01f7..486f623a119f54fd1e303996f3a8fcdad7bdf788 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/MongoDocumentTransformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/MongoDocumentTransformer.java
@@ -1,11 +1,11 @@
 package fr.boreal.views.transformer;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.Optional;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import org.bson.Document;
 
 import com.mongodb.client.MongoCursor;
@@ -18,7 +18,7 @@ import fr.boreal.model.logicalElements.factory.api.TermFactory;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectPredicateFactory;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
 import fr.boreal.model.logicalElements.impl.AtomImpl;
-import fr.boreal.views.datasource.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameterSignature;
 
 /**
  * Ignores results with no values for an asked path
@@ -28,7 +28,7 @@ public class MongoDocumentTransformer extends AbstractTransformer<MongoCursor<Do
 
 	private final TermFactory tf;
 
-	final List<String> projection_paths;
+	final List<String> projectionPaths;
 
 
 	/**
@@ -41,120 +41,129 @@ public class MongoDocumentTransformer extends AbstractTransformer<MongoCursor<Do
 	
 	/**
 	 * Create a new transformer for mongodb documents
-	 * @param projection_paths the paths to project data
+	 * @param projectionPaths the paths to project data
 	 * @param pf the predicate factory
 	 * @param tf the term factory
 	 */
-	public MongoDocumentTransformer(List<String> projection_paths, PredicateFactory pf, TermFactory tf) {
-		this.projection_paths = projection_paths;
+	public MongoDocumentTransformer(List<String> projectionPaths, PredicateFactory pf, TermFactory tf) {
+		this.projectionPaths = projectionPaths;
 		this.tf = tf;
 	}
 
 	@Override
-	public Iterator<Atom> transform(MongoCursor<Document> nativeResults, List<ViewParameterSignature> signatures, Atom a, Substitution s) {
-		return new DocumentToAtomIterator(nativeResults, a);
+	protected Stream<List<Term>> transform(
+			MongoCursor<Document> nativeResults,
+			List<ViewParameterSignature> signatures,
+			BasicQuery basicQuery) {
+		return StreamSupport.stream(new DocumentToAtomSplitIterator(nativeResults, basicQuery), false);
 	}
 
-	class DocumentToAtomIterator implements Iterator<Atom> {
-
-		final MongoCursor<Document> it;
-		final Atom filter_atom;
+	class DocumentToAtomSplitIterator implements Spliterator<List<Term>> {
 
-		Atom next_element = null;
+		private final MongoCursor<Document> it;
+		private final BasicQuery basicQuery;
 
-		DocumentToAtomIterator(MongoCursor<Document> nativeResults, Atom a) {
+		DocumentToAtomSplitIterator(MongoCursor<Document> nativeResults, BasicQuery basicQuery) {
 			this.it = nativeResults;
-			this.filter_atom = a;
+			this.basicQuery = basicQuery;
 		}
 
 		@Override
-		public boolean hasNext() {
-			if(next_element != null) {
+		public boolean tryAdvance(Consumer<? super List<Term>> action) {
+			while (it.hasNext()) {
+				Document d = it.next();
+				List<Term> terms = extractTerms(d);
+
+				if (terms == null || !matchesFilter(terms)) {
+					continue;
+				}
+
+				action.accept(terms);
 				return true;
-			} else if(! this.it.hasNext()) {
-				return false;
-			} else {
-				this.computeNext();
-				return next_element != null;
 			}
+			return false;
 		}
 
 		@Override
-		public Atom next() {
-			if(hasNext()) {
-				Atom tmp = this.next_element;
-				this.next_element = null;
-				return tmp;
-			}
-			throw new NoSuchElementException();
+		public Spliterator<List<Term>> trySplit() {
+			return null; // Splitting is not implemented in this version
+		}
 
+		@Override
+		public long estimateSize() {
+			return Long.MAX_VALUE; // Unknown size
 		}
 
-		public void computeNext() {
+		@Override
+		public int characteristics() {
+			return ORDERED | NONNULL;
+		}
 
-			List<Term> terms = new ArrayList<>();
+		private List<Term> extractTerms(Document document) {
+			List<Term> terms = new ArrayList<>(basicQuery.getPredicate().arity());
 
-			if(!this.it.hasNext()) {
-				return;
-			}
-			Document d = this.it.next();
-			
-			int diff = filter_atom.getPredicate().arity() - projection_paths.size();
-			for(int i = 0; i < diff; i++) {
-				terms.add(filter_atom.getTerm(i));
+			for (int i = 0; i < basicQuery.getPredicate().arity(); i++) {
+				if (basicQuery.getTerm(i).isPresent()) {
+					terms.add(basicQuery.getTerm(i).get());
+				} else {
+					terms.add(null);
+				}
 			}
 
-			// create terms
-			for(String path : projection_paths) {
-				String[] keys =  path.split("\\.");
-				for(int i = 0; i < keys.length -1; i++) {
+
+			int index = 0;
+			for (String path : projectionPaths) {
+				Document currentDoc = document;
+				String[] keys = path.split("\\.");
+
+				for (int i = 0; i < keys.length - 1; i++) {
 					String key = keys[i];
-					if(d.containsKey(key) && d.get(key) instanceof Document) {
-						d = d.get(key, Document.class);
+					if (currentDoc.containsKey(key) && currentDoc.get(key) instanceof Document) {
+						currentDoc = currentDoc.get(key, Document.class);
 					} else {
-						this.computeNext();
+						return null;
 					}
 				}
-				String key = keys[keys.length-1];
-				if (d.get(key) != null) {
-					String value = d.get(key).toString();
-					Term t = tf.createOrGetLiteral(value);
-					terms.add(t);
+
+				String key = keys[keys.length - 1];
+				if (currentDoc.get(key) != null) {
+					String value = currentDoc.get(key).toString();
+					while(terms.get(index) != null) ++index;
+					terms.set(index, tf.createOrGetLiteral(value));
 				} else {
-					this.computeNext();
+					return null;
 				}
 			}
+			return terms;
+		}
 
-			// filter
-			for(int i = 0; i < filter_atom.getPredicate().arity(); i++) {
-				Term filter_term = filter_atom.getTerm(i);
-				Term result_term = terms.get(i);
+		private boolean matchesFilter(List<Term> terms) {
+			for (int i = 0; i < basicQuery.getPredicate().arity(); i++) {
+				Term filterTerm = basicQuery.getTerm(i).orElse(null);
+				Term resultTerm = terms.get(i);
 
-				if(!filter_term.isVariable() && !filter_term.equals(result_term)) {
-					this.computeNext();
+				if (filterTerm != null && !filterTerm.equals(resultTerm)) {
+					return false;
 				}
 			}
-			
-			// create atom
-			this.next_element = new AtomImpl(this.filter_atom.getPredicate(), terms);
+			return true;
 		}
-
 	}
 
 	@Override
-	public Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
+	protected Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
 	@Override
-	public boolean isMissingValue(Object o) {
+	protected boolean isMissingValue(Object o) {
 		// TODO Auto-generated method stub
 		return false;
 	}
 
 	@Override
-	public Optional<Term> convertType(Object o, ViewParameterSignature signature, Atom a, Substitution s) {
+	protected Optional<Term> convertType(Object o, ViewParameterSignature signature) {
 		// TODO Auto-generated method stub
 		return Optional.empty();
 	}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SQLTuplesTransformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SQLTuplesTransformer.java
index 8ff31da6f0a9fda04c028070a83fff42fcd64c06..dbc465329a2ad75394410101ff406c7d488bc834 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SQLTuplesTransformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SQLTuplesTransformer.java
@@ -1,17 +1,13 @@
 package fr.boreal.views.transformer;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
+import java.util.stream.Stream;
 
-import fr.boreal.model.logicalElements.api.Atom;
-import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.factory.api.TermFactory;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
-import fr.boreal.views.datasource.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameterSignature;
 
 /**
  * Transform SQL tuples (java.net List&lt;Object[]&lt;) to Atoms
@@ -47,27 +43,27 @@ public class SQLTuplesTransformer extends AbstractTransformer<List<Object[]>> {
 	/////////////////////////////////////////////////
 
 	@Override
-	public Iterator<Atom> transform(List<Object[]> nativeResults, List<ViewParameterSignature> signatures, Atom a, Substitution s) {
-		Collection<Atom> atoms = new ArrayList<>();
-		for(Object[] nativeResult : nativeResults) {
-			Optional<Atom> opt_viewAtom = this.transformAtom(nativeResult, signatures, a, s);
-            opt_viewAtom.ifPresent(atoms::add);
-		}
-		return atoms.iterator();
+	protected Stream<List<Term>> transform(
+			List<Object[]> nativeResults,
+			List<ViewParameterSignature> signatures,
+			BasicQuery basicQuery) {
+		return nativeResults.stream()
+				.map(nativeResult -> this.transformNativeResult(nativeResult, signatures, basicQuery).orElse(null))
+				.filter(Objects::nonNull);
 	}
 
 	@Override
-	public boolean isMissingValue(Object o) {
+	protected boolean isMissingValue(Object o) {
 		return o == null;
 	}
 
 	@Override
-	public Optional<Term> convertType(Object o, ViewParameterSignature signature, Atom a, Substitution s) {
+	protected Optional<Term> convertType(Object o, ViewParameterSignature signature) {
 		return Optional.of(this.tf.createOrGetLiteral(o));
 	}
 
 	@Override
-	public Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
+	protected Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
 		return ((Object[])nativeResult)[nativeResultIndex];
 	}
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SparqlTuplesTransformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SparqlTuplesTransformer.java
index d80d3a30b7829e46956daf1ebbeaf01c95566b81..dcb5733843df1f4015a92eb17966e84d0a60667c 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SparqlTuplesTransformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/SparqlTuplesTransformer.java
@@ -1,22 +1,18 @@
 package fr.boreal.views.transformer;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
+import java.util.stream.Stream;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import org.eclipse.rdf4j.model.Literal;
 import org.eclipse.rdf4j.model.Value;
 import org.eclipse.rdf4j.query.BindingSet;
 import org.eclipse.rdf4j.query.TupleQueryResult;
 
-import fr.boreal.model.logicalElements.api.Atom;
-import fr.boreal.model.logicalElements.api.Substitution;
 import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.factory.api.TermFactory;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
-import fr.boreal.views.datasource.ViewParameterSignature;
+import fr.boreal.views.view.ViewParameterSignature;
 
 /**
  * Transform Sparql tuples (rdf4j {@link TupleQueryResult}) to Atoms
@@ -57,18 +53,19 @@ public class SparqlTuplesTransformer extends AbstractTransformer<TupleQueryResul
 	/////////////////////////////////////////////////
 
 	@Override
-	public Iterator<Atom> transform(TupleQueryResult nativeResults, List<ViewParameterSignature> signatures, Atom a, Substitution s) {
-		Collection<Atom> atoms = new ArrayList<>();
+	public Stream<List<Term>> transform(
+			TupleQueryResult nativeResults,
+			List<ViewParameterSignature> signatures,
+			BasicQuery basicQuery) {
 		this.ordered_binding_names = nativeResults.getBindingNames();
-		for(BindingSet nativeResult : nativeResults) {
-			Optional<Atom> opt_viewAtom = this.transformAtom(nativeResult, signatures, a, s);
-            opt_viewAtom.ifPresent(atoms::add);
-		}
-		return atoms.iterator();
+
+		return nativeResults.stream()
+				.map(nativeResult -> this.transformNativeResult(nativeResult, signatures, basicQuery).orElse(null))
+				.filter(Objects::nonNull);
 	}
 
 	@Override
-	public boolean isMissingValue(Object o) {
+	protected boolean isMissingValue(Object o) {
         return !(o instanceof Value);
 	}
 
@@ -81,7 +78,7 @@ public class SparqlTuplesTransformer extends AbstractTransformer<TupleQueryResul
 	// TODO: For now we only handle String and Integer values
 	// TODO: Other values will be handled as String
 	// We can also compute a first filter here according to constants of the atom
-	public Optional<Term> convertType(Object o, ViewParameterSignature signature, Atom a, Substitution s) {
+	protected Optional<Term> convertType(Object o, ViewParameterSignature signature) {
 		if(o instanceof Value rdf4j_value) {
 			if(rdf4j_value.isBNode()) {
 				return Optional.of(this.tf.createOrGetVariable(rdf4j_value.stringValue()));
@@ -104,7 +101,7 @@ public class SparqlTuplesTransformer extends AbstractTransformer<TupleQueryResul
 	}
 
 	@Override
-	public Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
+	protected Object getObjectAtIndex(Object nativeResult, int nativeResultIndex, ViewParameterSignature signature) {
 		return ((BindingSet)nativeResult).getBinding(this.ordered_binding_names.get(nativeResultIndex)).getValue();
 	}
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/Transformer.java b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/Transformer.java
index ddab0615436c7aad2740d77f97ecab3cfbfce4a3..dece2866590ccbd97789fe7b8591a434d75d4269 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/Transformer.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/transformer/Transformer.java
@@ -1,10 +1,14 @@
 package fr.boreal.views.transformer;
 
 import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Stream;
 
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Atom;
 import fr.boreal.model.logicalElements.api.Substitution;
-import fr.boreal.views.datasource.ViewParameters;
+import fr.boreal.model.logicalElements.api.Term;
+import fr.boreal.views.view.ViewParameters;
 
 /**
  * Transform a native result into Atoms
@@ -18,10 +22,9 @@ public interface Transformer<NativeResultType> {
 	 * Some implementations may compute a filter using the given atom when converting the results
 	 * @param nativeResults the native results representing atoms
 	 * @param parameters the parameters of the view
-	 * @param a the atom used for filtering / instantiation
-	 * @param s the pre-affectation from variables of <code>a</code> to terms
-	 * @return all the atoms represented by the native results
+	 * @param basicQuery the query to answer
+	 * @return all the term sequences represented by the native results
 	 */
-	Iterator<Atom> transform(NativeResultType nativeResults, ViewParameters<?> parameters, Atom a, Substitution s);
+	Stream<List<Term>> transform(NativeResultType nativeResults, ViewParameters<?> parameters, BasicQuery basicQuery);
 
 }
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/view/View.java b/integraal/integraal-views/src/main/java/fr/boreal/views/view/View.java
new file mode 100644
index 0000000000000000000000000000000000000000..cc263646d122ad0f3d5fd804605710f0d6e775f1
--- /dev/null
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/view/View.java
@@ -0,0 +1,9 @@
+package fr.boreal.views.view;
+
+import fr.boreal.model.data.readable.query.AtomicPattern;
+import fr.boreal.model.logicalElements.api.Predicate;
+import fr.boreal.views.datasource.DataSource;
+
+public interface View<NativeQueryType> extends AtomicPattern {
+    ViewParameters<NativeQueryType> getViewParameters();
+}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewImpl.java b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..6069e441f7a4de0856ba77d8edd68b15037c0721
--- /dev/null
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewImpl.java
@@ -0,0 +1,63 @@
+package fr.boreal.views.view;
+
+import com.github.jsonldjava.shaded.com.google.common.collect.Sets;
+import fr.boreal.model.data.readable.query.AbstractAtomicPattern;
+import fr.boreal.model.data.readable.query.BasicQuery;
+import fr.boreal.model.logicalElements.api.Predicate;
+import fr.boreal.model.logicalElements.api.Substitution;
+import fr.boreal.model.logicalElements.api.Term;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class ViewImpl<NativeQueryType>
+    extends AbstractAtomicPattern
+        implements View<NativeQueryType> {
+    private final ViewParameters<NativeQueryType> viewParameters;
+
+    /**
+     * Constructs an AtomicPattern with specific constraints.
+     *
+     * @param predicate          The predicate associated with this pattern.
+     * @param termConstraints    A map associating positions (0-based index) with allowed term types.
+     */
+    public ViewImpl(
+            Predicate predicate,
+            Map<Integer, Class<? extends Term>> termConstraints,
+            ViewParameters<NativeQueryType> viewParameters) {
+        super(
+                predicate,
+                IntStream.range(0, predicate.arity()).boxed()
+                        .filter(i -> viewParameters.viewElements().get(i).isMandatory())
+                        .collect(Collectors.toSet()),
+                termConstraints);
+        this.viewParameters = viewParameters;
+    }
+
+    @Override
+    public Set<Set<Integer>> getIndexablePatterns() {
+        return Set.of(this.getMandatoryPositions());
+    }
+
+    @Override
+    public Stream<BasicQuery> createQueries(Map<Integer, Term> positionsAssignation) {
+        if (this.hasAssignedMandatoryParameters(positionsAssignation)) {
+            return Stream.of(new BasicQuery(
+                    this,
+                    this.getMandatoryPositions().stream()
+                            .map(i -> Map.entry(i, positionsAssignation.get(i)))
+                            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
+            ));
+        }
+
+        return Stream.empty();
+    }
+    @Override
+    public ViewParameters<NativeQueryType> getViewParameters() {
+        return viewParameters;
+    }
+}
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameterSignature.java b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameterSignature.java
similarity index 94%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameterSignature.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameterSignature.java
index 7f92fd413b6deaddb40f6f993925b571e7ebfc8a..11eb9c20090291aff1d8e22e4f1246a6d318cb6b 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameterSignature.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameterSignature.java
@@ -1,4 +1,4 @@
-package fr.boreal.views.datasource;
+package fr.boreal.views.view;
 
 import java.util.Optional;
 
diff --git a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameters.java b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameters.java
similarity index 93%
rename from integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameters.java
rename to integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameters.java
index 964a08efe342d32ffbc61b3636fe80bdecd07229..f0c928b31f7279f77b82e444218e8eb7d2e4e94f 100644
--- a/integraal/integraal-views/src/main/java/fr/boreal/views/datasource/ViewParameters.java
+++ b/integraal/integraal-views/src/main/java/fr/boreal/views/view/ViewParameters.java
@@ -1,4 +1,4 @@
-package fr.boreal.views.datasource;
+package fr.boreal.views.view;
 
 import java.util.List;
 import java.util.Optional;
diff --git a/integraal/integraal-views/src/main/java/module-info.java b/integraal/integraal-views/src/main/java/module-info.java
index 954c8479d424c66061ef0889837b57b86a1004fe..aa17c8880a9d25f94f3caefba540ddc3adc323e9 100644
--- a/integraal/integraal-views/src/main/java/module-info.java
+++ b/integraal/integraal-views/src/main/java/module-info.java
@@ -19,6 +19,7 @@ module fr.boreal.views {
 	requires rdf4j.repository.sparql;
 	requires rdf4j.model.api;
     requires org.mongodb.driver.core;
+    requires jsonld.java;
 
     exports fr.boreal.views;
 	exports fr.boreal.views.builder;
diff --git a/integraal/integraal-views/src/test/java/fr/boreal/test/views/ViewTest.java b/integraal/integraal-views/src/test/java/fr/boreal/test/views/ViewTest.java
index c20ab1dad9915a20a831866b56a96f819adbaf4a..daf66eaf9eb75c0fea5119b0b823310c690f333d 100644
--- a/integraal/integraal-views/src/test/java/fr/boreal/test/views/ViewTest.java
+++ b/integraal/integraal-views/src/test/java/fr/boreal/test/views/ViewTest.java
@@ -1,13 +1,12 @@
 package fr.boreal.test.views;
 
-import fr.boreal.model.logicalElements.api.Atom;
+import fr.boreal.model.data.readable.exception.EvaluationException;
+import fr.boreal.model.data.readable.query.BasicQuery;
 import fr.boreal.model.logicalElements.api.Predicate;
-import fr.boreal.model.logicalElements.api.Variable;
+import fr.boreal.model.logicalElements.api.Term;
 import fr.boreal.model.logicalElements.factory.impl.SameObjectPredicateFactory;
-import fr.boreal.model.logicalElements.factory.impl.SameObjectTermFactory;
-import fr.boreal.model.logicalElements.impl.AtomImpl;
 import fr.boreal.views.builder.ViewBuilder;
-import fr.boreal.views.datasource.AbstractViewWrapper;
+import fr.boreal.views.datasource.DataSource;
 import org.junit.Assert;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -17,7 +16,8 @@ import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
 import java.util.Collection;
-import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.stream.Stream;
 
 @RunWith(Parameterized.class)
@@ -27,37 +27,27 @@ class ViewTest {
     public static final Predicate cityZip = SameObjectPredicateFactory.instance().createOrGetPredicate("cityZip", 2);
     public static final Predicate concept = SameObjectPredicateFactory.instance().createOrGetPredicate("concept", 1);
 
-    // Terms
-    public static final Variable x = SameObjectTermFactory.instance().createOrGetVariable("X");
-    public static final Variable y = SameObjectTermFactory.instance().createOrGetVariable("Y");
-
-    // Atoms
-    public static final Atom cityZipQuery = new AtomImpl(cityZip, x, y);
-    public static final Atom conceptQuery = new AtomImpl(concept, x);
-
 
     @Parameterized.Parameters
     static Stream<Arguments> data() {
         return Stream.of(
-                Arguments.of("./src/test/resources/wikidata_web_api.vd", cityZipQuery),
-                Arguments.of("./src/test/resources/dbpedia_sparql_endpoint.vd", conceptQuery)
+                Arguments.of("./src/test/resources/wikidata_web_api.vd", cityZip),
+                Arguments.of("./src/test/resources/dbpedia_sparql_endpoint.vd", concept)
         );
     }
 
-    /*@DisplayName("Test querying views from a view declaration file")
+    @DisplayName("Test querying views from a view declaration file")
     @ParameterizedTest(name = "{index}: querying {1} on {0} should work ...")
     @MethodSource("data")
-    public void dlgpViewImport(String vdFilePath, Atom query) throws ViewBuilder.ViewBuilderException {
-        Collection<AbstractViewWrapper<String, ?>> wrappers = ViewBuilder.createFactBases(vdFilePath);
-        AbstractViewWrapper<String, ?> wrapper = wrappers.stream().findAny().orElseThrow();
-        Iterator<Atom> results = wrapper.match(query);
-        int count = 0;
-        while (results.hasNext()) {
-            results.next();
-            count++;
-        }
-        Assert.assertTrue(count>0);
-    }*/
+    public void dlgpViewImport(String vdFilePath, Predicate predicate) throws ViewBuilder.ViewBuilderException, EvaluationException {
+        Collection<? extends DataSource<String, ?>> dataSources = ViewBuilder.loadDataSources(vdFilePath);
+        DataSource<String, ?> dataSource = dataSources.stream().findAny().orElseThrow();
+        BasicQuery basicQuery = dataSource.getBasicPattern(predicate).createQueries(Map.of()).findAny().orElseThrow();
+        List<List<Term>> results = dataSource.evaluate(basicQuery).toList();
+
+        results.stream().forEach(l -> Assert.assertEquals(l.size(), predicate.arity()));
+        Assert.assertFalse(results.isEmpty());
+    }
 
 
 }