/** * EntitySet - A set of entities supporting set operations * * EntitySet provides set operations (union, intersection, difference) * for working with collections of entities. * * @version 0.1 * @since 0.1 */ namespace Implexus.Core { /** * A set of entities supporting set operations. * * EntitySet wraps a collection of entities and provides * operations for combining and filtering entity collections. * * Example usage: * {{{ * var active_users = engine.query_by_expression("User", "status == 'active'"); * var admins = engine.query_by_expression("User", "role == 'admin'"); * var active_admins = active_users.as_set().intersect(admins.as_set()); * }}} */ public class EntitySet : Object, Invercargill.Element { private Invercargill.DataStructures.HashSet _entities; /** * Creates an empty EntitySet. */ public EntitySet.empty() { _entities = new Invercargill.DataStructures.HashSet(); } /** * Creates an EntitySet containing a single entity. * * @param entity The entity to wrap */ public EntitySet(Entity entity) { _entities = new Invercargill.DataStructures.HashSet(); _entities.add(entity); } /** * Creates an EntitySet from a collection of entities. * * @param entities The entities to include */ public EntitySet.from_enumerable(Invercargill.Enumerable entities) { _entities = new Invercargill.DataStructures.HashSet(); foreach (var entity in entities) { _entities.add(entity); } } /** * The number of entities in this set. * * @return The count */ public int count { get { return (int) _entities.count; } } /** * Checks if this set is empty. * * @return true if empty */ public bool is_empty { get { return _entities.peek_count() == 0; } } /** * Checks if this set contains an entity. * * @param entity The entity to check * @return true if the entity is in this set */ public bool contains(Entity entity) { return _entities.contains(entity); } /** * Gets the entities as an enumerable collection. * * @return The entities */ public Invercargill.Enumerable entities { owned get { return _entities.as_enumerable(); } } // === Set Operations === /** * Creates a new set that is the union of this set and another. * * @param other The other set * @return A new EntitySet containing entities from both sets */ public EntitySet union(EntitySet other) { var result = new Invercargill.DataStructures.HashSet(); foreach (var entity in _entities) { result.add(entity); } foreach (var entity in other._entities) { result.add(entity); } var set = new EntitySet.empty(); set._entities = result; return set; } /** * Creates a new set that is the intersection of this set and another. * * @param other The other set * @return A new EntitySet containing entities in both sets */ public EntitySet intersect(EntitySet other) { var result = new Invercargill.DataStructures.HashSet(); foreach (var entity in _entities) { if (other.contains(entity)) { result.add(entity); } } var set = new EntitySet.empty(); set._entities = result; return set; } /** * Creates a new set that is the difference of this set and another. * * @param other The other set * @return A new EntitySet containing entities in this set but not other */ public EntitySet difference(EntitySet other) { var result = new Invercargill.DataStructures.HashSet(); foreach (var entity in _entities) { if (!other.contains(entity)) { result.add(entity); } } var set = new EntitySet.empty(); set._entities = result; return set; } /** * Creates a new set that is the symmetric difference of this set and another. * * @param other The other set * @return A new EntitySet containing entities in either set but not both */ public EntitySet symmetric_difference(EntitySet other) { return this.difference(other).union(other.difference(this)); } // === Filtering === /** * Delegate for filtering entities. */ public delegate bool FilterPredicate(Entity entity); /** * Filters this set to entities matching a predicate. * * @param predicate The filter predicate * @return A new EntitySet with matching entities */ public EntitySet filter(FilterPredicate predicate) { var result = new Invercargill.DataStructures.HashSet(); foreach (var entity in _entities) { if (predicate(entity)) { result.add(entity); } } var set = new EntitySet.empty(); set._entities = result; return set; } /** * Filters this set to entities of a specific type. * * @param type The entity type to filter by * @return A new EntitySet with matching entities */ public EntitySet filter_by_type(EntityType type) { return filter(e => e.entity_type == type); } /** * Filters this set to entities with a specific type label. * * @param type_label The type label to filter by * @return A new EntitySet with matching entities */ public EntitySet filter_by_type_label(string type_label) { return filter(e => e.type_label == type_label); } // === Invercargill.Element === /** * Returns the GLib.Type for EntitySet. * * @return The EntitySet type */ public Type? type() { return typeof(EntitySet); } /** * Returns the type name string. * * @return "EntitySet" */ public string type_name() { return "EntitySet"; } /** * EntitySets are never null. * * @return false */ public bool is_null() { return false; } /** * Checks if this set is of the specified type. * * @param t The type to check * @return true if this set is of type t */ public bool is_type(Type t) { return t.is_a(typeof(EntitySet)); } /** * Checks if this set can be assigned to the specified type. * * @return true if assignable */ public bool assignable_to() { return typeof(T).is_a(typeof(EntitySet)); } /** * Checks if this set can be assigned to the specified type. * * @param t The target type * @return true if assignable */ public bool assignable_to_type(Type t) { return is_type(t); } /** * Casts this set to type T. * * @return This set as type T, or null if not possible */ public T? @as() throws Invercargill.ElementError { return this; } /** * Asserts and casts this set to type T. * * @return This set as type T */ public T assert_as() { return (T) this; } /** * Casts this set to type T, returning a default if not possible. * * @return This set as type T, or the default */ public T? as_or_default() { return this; } /** * Attempts to get this set as type T. * * @param result Output parameter for the result * @return true if successful */ public bool try_get_as(out T result) { result = this; return true; } /** * Converts this set to a value of the requested type. * * @param requested_type The type to convert to * @return The value */ public GLib.Value to_value(GLib.Type requested_type) throws GLib.Error { var v = Value(typeof(EntitySet)); v.set_object(this); return v; } /** * Returns a string representation of this set. * * @return A string in the form "EntitySet(count)" */ public new string to_string() { return "EntitySet(%d)".printf(count); } } } // namespace Implexus.Core