Les bases

Les bases – Rechercher plusieurs informations

Dans Generic System, il est possible de rechercher spécifiquement un Generic (recherche simple), ou bien un ensemble de Generic (recherche avancée). Quand un ensemble de résultats doit être retourné, Generic System ne renvoie pas de liste de Generic, mais un Snapshot.

Introduction

Qu’est-ce qu’un Snapshot ?

D’un point de vue fonctionnel, un Snapshot est un ensemble de résultats qui est conscient de son contexte. Le Snapshot est directement en relation avec le modèle de persistence des données, contrairement aux Collections Java qui possèdent un cache en interne contenant les informations.

D’un point de vue technique, un Snapshot est d’une part un fournisseur de Stream et d’autre part un aware Iterable. Comme nous allons le voir par la suite, un Snapshot peut être requêté directement en utilisant des filtres de Stream.

Comparaison Snapshot / Collection

Pour prendre un exemple simple, nous allons créer une instance de Vehicle puis la stocker soit dans une Collection, soit dans un Snapshot. Nous allons ensuite vérifier que notre Collection et notre Snapshot contiennent bien cette instance. Puis nous ajoutons une nouvelle instance de Vehicle, et nous vérifions que notre Collection et notre Snapshot contiennent bien les deux instances.

SnapshotCollection

// (1)
Engine engine = new Engine();

Generic vehicle = engine.setInstance("Vehicle");
Generic myFirstVehicle = vehicle.setInstance("myFirstVehicle");

// (2)
Snapshot<Generic> instances = vehicle.getInstances();

// (3)
assert instances.size() == 1;
assert instances.contains(myFirstVehicle);

// (4)
Generic mySecondVehicle = vehicle.setInstance("mySecondVehicle");

// (5)

// (6)
assert instances.size() == 2;
assert instances.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle));

Voici la synthèse des différences :

Ref Collection Snapshot

(1) Crée la classe Vehicle et une instance de Vehicle. Crée le type Vehicle et une instance de Vehicle.

(2) Crée une liste de Vehicle et ajoute l’instance. Récupère les instances de Vehicle via un Snapshot.

(3) Vérifie que la liste de Vehicle contient l’instance myFirstVehicle. Vérifie que le Snapshot d’instances contient l’instance myFirstVehicle.

(4) Crée une seconde instance de Vehicle. Crée une seconde instance de Vehicle.

(5) Ajoute la seconde instance à la liste de Vehicle. Rien à faire.

(6) Vérifie que la liste de Vehicle contient toutes les instances. Vérifie que le Snapshot d’instances contient toutes les instances.

Vous remarquez qu’il est nécessaire de mettre à jour notre Collection pour qu’elle connaisse l’état de nos instances, alors que le Snapshot est en relation directe avec le modèle de persistance, et reste informé des changements.

Recherche avec résultats multiples

Comme nous l’avons vu dans l’article sur les recherches de base, il est possible de rechercher un Generic grâce aux méthodes get — getInstance, getAttribute, getRelation, getHolder, getLink —. De la même façon, il existe des méthodes get au pluriel — getInstances, getAttributes, getRelations, getLinks, getHolders — qui permettent de demander à Generic System de nous renvoyer un ensemble de résultats.

Afin de mieux illustrer cet article, nous allons utiliser le code suivant pour initialiser notre moteur (cliquez pour déplier) :

Cliquez pour déplier le code

// (1)
public static class Vehicle {
}
Vehicle myFirstVehicle = new Vehicle();

// (2)
List<Vehicle> instances = new ArrayList<>();
instances.add(myFirstVehicle);

// (3)
assert instances.size() == 1;
assert instances.contains(myFirstVehicle);

// (4)
Vehicle mySecondVehicle = new Vehicle();

// (5)
instances.add(mySecondVehicle);

// (6)
assert instances.size() == 2;
assert instances.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle));

Rechercher des types

La recherche de types fait appel à la méthode getInstances(). Voyons cela en exemple :

// Create an Engine
Engine engine = new Engine();

// Create new types
Generic vehicle = engine.setInstance("Vehicle");
Generic color = engine.setInstance("Color");
Generic car = engine.setInstance(vehicle, "Car");
Generic bike = engine.setInstance(vehicle, "Bike");

// Add new attributes
Generic options = vehicle.setAttribute("Options");
Generic wheels = vehicle.setAttribute("Wheels");
Generic power = vehicle.setAttribute("Power").enablePropertyConstraint();

// Add new relations
Generic vehicleColor = vehicle.setRelation("VehicleColor", color);
Generic betterThan = vehicle.setRelation("betterThan", vehicle);

// Add new instances
Generic red = color.setInstance("red");
Generic yellow = color.setInstance("yellow");
Generic myFirstVehicle = vehicle.setInstance("myfirstVehicle");
Generic mySecondVehicle = vehicle.setInstance("mySecondVehicle");
Generic myThirdVehicle = vehicle.setInstance("myThirdVehicle");
Generic myCar = car.setInstance("myCar");
Generic yourCar = car.setInstance("yourCar");
Generic myBike = bike.setInstance("myBike");
Generic yourBike = bike.setInstance("yourBike");

// Add new links
myCar.setLink(vehicleColor, "myCarRed", red);
yourCar.setLink(vehicleColor, "yourCarYellow", yellow);
myBike.setLink(vehicleColor, "myBikeRed", red);
yourBike.setLink(vehicleColor, "yourBikeRed", red);
myCar.setLink(betterThan, "my car is better than yours", yourCar);
myCar.setLink(betterThan, "my car is better than my bike", myBike);

// Add new holders
myFirstVehicle.setHolder(options, "music player");
myFirstVehicle.setHolder(options, "ABS");
mySecondVehicle.setHolder(options, "air conditioning");
myThirdVehicle.setHolder(options, "air conditioning");
myCar.setHolder(power, 136);
yourCar.setHolder(power, 110);

// Persist changes
engine.getCurrentCache().flush();

Nous pouvons vérifier que notre Snapshot contient bien les types que nous avons créé :

// Get all the types from the Engine
Snapshot<Generic> types = engine.getInstances();

Rechercher des attributs ou des propriétés

La recherche d’attributs et de propriétés fait appel à la méthode getAttributes() :

// types should at least contain Vehicle, Color
Generic vehicle = engine.getInstance("Vehicle");
Generic color = engine.getInstance("Color");
Generic car = vehicle.getInheriting("Car");
Generic bike = vehicle.getInheriting("Bike");
assert types.size() >= 4;
assert types.containsAll(Arrays.asList(vehicle, color, car, bike));

Nous pouvons vérifier que notre Snapshot contiennent bien Options, Wheels et Power :

// Get all Vehicle attributes
Snapshot<Generic> attributes = vehicle.getAttributes();

Rechercher des relations ou des links

La recherche de relations ou de links fait appel respectivement aux méthodes getRelations() et getLinks() :

// Vehicle contains at least Options, Wheels and Power attributes
Generic options = vehicle.getAttribute("Options");
Generic wheels = vehicle.getAttribute("Wheels");
Generic power = vehicle.getAttribute("Power");
assert attributes.size() >= 3;
assert attributes.containsAll(Arrays.asList(options, wheels, power));

Là encore, nous pouvons vérifier que les relations que nous avions créés pour l’occasion sont bien contenus dans le Snapshot :

// Get all relations from Vehicle
Snapshot<Generic> relations = vehicle.getRelations();

// Get the links from the relation betterThan for myCar
Snapshot<Generic> links = myCar.getLinks(betterThan);

Comme lors d’une recherche simple, il existe une petite subtilité pour rechercher des links. Il faut en effet préciser à quelle relation ils appartiennent :

// Vehicle has at least VehicleColor and betterThan relations
Generic vehicleColor = vehicle.getRelation("VehicleColor");
Generic betterThan = vehicle.getRelation("betterThan");
assert relations.size() >= 2;
assert relations.contains(Arrays.asList(vehicleColor, betterThan));

Info

Il est possible de récupérer les relations depuis n’importe quel type impliqué, et les links depuis n’importe quelle instance impliquée.

Rechercher des instances

La recherche d’instances fait logiquement appel à la méthode getInstances() :

// The links should at least contain 2 links
Generic myCarRocks = myCar.getLink(betterThan, "my car is better than yours");
Generic iLoveMyCar = myCar.getLink(betterThan, "my car is better than my bike");
assert links.size() >= 2;
assert links.containsAll(Arrays.asList(myCarRocks, iLoveMyCar));

Nous pouvons ensuite attester qu’il existe bien au moins trois instances pour notre type Vehicle :

// Get all Vehicle instances
Snapshot<Generic> vehicles = vehicle.getInstances();

Rechercher des sous-instances

Vous avez peut-être lu dans un article précédent qu’il était possible de créer des sous-types, qui héritent d’un type.

ll est donc possible de rechercher les instances de ces sous-types grâce à la méthode getSubInstances() :

// We should have at least 3 instances of Vehicle
Generic myFirstVehicle = vehicle.getInstance("myFirstVehicle");
Generic mySecondVehicle = vehicle.getInstance("mySecondVehicle");
Generic myThirdVehicle = vehicle.getInstance("myThirdVehicle");
assert vehicles.size() >= 3;
assert vehicles.containsAll(Arrays.asList(myFirstVehicle, mySecondVehicle, myThirdVehicle));

Nous pouvons vérifier que ce Snapshot contient bien les instances de Vehicle ainsi que de ces sous-types Car et Bike :

// Get all Vehicle sub-instances (i.e., instances of sub-types)
Snapshot<Generic> subinstances = vehicle.getSubInstances();

Rechercher des holders

La recherche de holders fait appel à la méthode getHolders. Mais comme lors de la recherche de base, il faut indiquer à Generic System sur quel attribut rechercher les holders :

// We should have at least 4 sub-instances
Generic myCar = car.getInstance("myCar");
Generic yourCar = car.getInstance("yourCar");
Generic myBike = bike.getInstance("myBike");
Generic yourBike = bike.getInstance("yourBike");
Generic myFirstVehicle = vehicle.getInstance("myFirstVehicle");
assert subinstances.size() >= 4;
assert subinstances.containsAll(Arrays.asList(myCar, yourCar, myBike, yourBike, myFirstVehicle));

Dans ce cas, notre Snapshot contient tous les holders de l’attribut Options :

// Get the holders from myFisrstVehicle
Snapshot<Generic> holders = myFirstVehicle.getHolders(options);

Filtrer les recherches

Quand vous effectuez une recherche qui renvoie un ensemble de résultats, vous souhaitez peut-être limiter le nombre de résultats obtenus en fonction de critères prédéfinis.

Avec un Snapshot, c’est très simple de filtrer les résultats, puisque que Snapshot est un fournisseur de Stream ! Vous bénéficiez donc de toute la puissance de l’API Stream Java 8.

Reprenons notre exemple, et imaginons que l’on souhaite récupérer toutes les instances de Vehicle ayant l'Options “air conditioning” :

// myFirstVehicle has at least the air conditioning and ABS
Generic musicPlayer = myFirstVehicle.getHolder(options, "music player");
Generic abs = myFirstVehicle.getHolder(options, "ABS");
assert holders.size() >= 2;
assert holders.containsAll(Arrays.asList(musicPlayer, abs));

En résumé

Generic System permet d’effectuer des recherches retournant un ensemble de résultats sous la forme d’un Snapshot ;

Un Snapshot est toujours conscient des modifications du modèle de données. Il s’agit d’un fournisseur de Stream et d’un aware Iterable.

Enfin, il est possible de filtrer les recherches en utilisant un Stream. Les critères de sélection se font via la méthode filter.