EntitySet.vala 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /**
  2. * EntitySet - A set of entities supporting set operations
  3. *
  4. * EntitySet provides set operations (union, intersection, difference)
  5. * for working with collections of entities.
  6. *
  7. * @version 0.1
  8. * @since 0.1
  9. */
  10. namespace Implexus.Core {
  11. /**
  12. * A set of entities supporting set operations.
  13. *
  14. * EntitySet wraps a collection of entities and provides
  15. * operations for combining and filtering entity collections.
  16. *
  17. * Example usage:
  18. * {{{
  19. * var active_users = engine.query_by_expression("User", "status == 'active'");
  20. * var admins = engine.query_by_expression("User", "role == 'admin'");
  21. * var active_admins = active_users.as_set().intersect(admins.as_set());
  22. * }}}
  23. */
  24. public class EntitySet : Object, Invercargill.Element {
  25. private Invercargill.DataStructures.HashSet<Entity> _entities;
  26. /**
  27. * Creates an empty EntitySet.
  28. */
  29. public EntitySet.empty() {
  30. _entities = new Invercargill.DataStructures.HashSet<Entity>();
  31. }
  32. /**
  33. * Creates an EntitySet containing a single entity.
  34. *
  35. * @param entity The entity to wrap
  36. */
  37. public EntitySet(Entity entity) {
  38. _entities = new Invercargill.DataStructures.HashSet<Entity>();
  39. _entities.add(entity);
  40. }
  41. /**
  42. * Creates an EntitySet from a collection of entities.
  43. *
  44. * @param entities The entities to include
  45. */
  46. public EntitySet.from_enumerable(Invercargill.Enumerable<Entity> entities) {
  47. _entities = new Invercargill.DataStructures.HashSet<Entity>();
  48. foreach (var entity in entities) {
  49. _entities.add(entity);
  50. }
  51. }
  52. /**
  53. * The number of entities in this set.
  54. *
  55. * @return The count
  56. */
  57. public int count { get { return (int) _entities.count; } }
  58. /**
  59. * Checks if this set is empty.
  60. *
  61. * @return true if empty
  62. */
  63. public bool is_empty { get { return _entities.peek_count() == 0; } }
  64. /**
  65. * Checks if this set contains an entity.
  66. *
  67. * @param entity The entity to check
  68. * @return true if the entity is in this set
  69. */
  70. public bool contains(Entity entity) {
  71. return _entities.contains(entity);
  72. }
  73. /**
  74. * Gets the entities as an enumerable collection.
  75. *
  76. * @return The entities
  77. */
  78. public Invercargill.Enumerable<Entity> entities {
  79. owned get { return _entities.as_enumerable(); }
  80. }
  81. // === Set Operations ===
  82. /**
  83. * Creates a new set that is the union of this set and another.
  84. *
  85. * @param other The other set
  86. * @return A new EntitySet containing entities from both sets
  87. */
  88. public EntitySet union(EntitySet other) {
  89. var result = new Invercargill.DataStructures.HashSet<Entity>();
  90. foreach (var entity in _entities) {
  91. result.add(entity);
  92. }
  93. foreach (var entity in other._entities) {
  94. result.add(entity);
  95. }
  96. var set = new EntitySet.empty();
  97. set._entities = result;
  98. return set;
  99. }
  100. /**
  101. * Creates a new set that is the intersection of this set and another.
  102. *
  103. * @param other The other set
  104. * @return A new EntitySet containing entities in both sets
  105. */
  106. public EntitySet intersect(EntitySet other) {
  107. var result = new Invercargill.DataStructures.HashSet<Entity>();
  108. foreach (var entity in _entities) {
  109. if (other.contains(entity)) {
  110. result.add(entity);
  111. }
  112. }
  113. var set = new EntitySet.empty();
  114. set._entities = result;
  115. return set;
  116. }
  117. /**
  118. * Creates a new set that is the difference of this set and another.
  119. *
  120. * @param other The other set
  121. * @return A new EntitySet containing entities in this set but not other
  122. */
  123. public EntitySet difference(EntitySet other) {
  124. var result = new Invercargill.DataStructures.HashSet<Entity>();
  125. foreach (var entity in _entities) {
  126. if (!other.contains(entity)) {
  127. result.add(entity);
  128. }
  129. }
  130. var set = new EntitySet.empty();
  131. set._entities = result;
  132. return set;
  133. }
  134. /**
  135. * Creates a new set that is the symmetric difference of this set and another.
  136. *
  137. * @param other The other set
  138. * @return A new EntitySet containing entities in either set but not both
  139. */
  140. public EntitySet symmetric_difference(EntitySet other) {
  141. return this.difference(other).union(other.difference(this));
  142. }
  143. // === Filtering ===
  144. /**
  145. * Delegate for filtering entities.
  146. */
  147. public delegate bool FilterPredicate(Entity entity);
  148. /**
  149. * Filters this set to entities matching a predicate.
  150. *
  151. * @param predicate The filter predicate
  152. * @return A new EntitySet with matching entities
  153. */
  154. public EntitySet filter(FilterPredicate predicate) {
  155. var result = new Invercargill.DataStructures.HashSet<Entity>();
  156. foreach (var entity in _entities) {
  157. if (predicate(entity)) {
  158. result.add(entity);
  159. }
  160. }
  161. var set = new EntitySet.empty();
  162. set._entities = result;
  163. return set;
  164. }
  165. /**
  166. * Filters this set to entities of a specific type.
  167. *
  168. * @param type The entity type to filter by
  169. * @return A new EntitySet with matching entities
  170. */
  171. public EntitySet filter_by_type(EntityType type) {
  172. return filter(e => e.entity_type == type);
  173. }
  174. /**
  175. * Filters this set to entities with a specific type label.
  176. *
  177. * @param type_label The type label to filter by
  178. * @return A new EntitySet with matching entities
  179. */
  180. public EntitySet filter_by_type_label(string type_label) {
  181. return filter(e => e.type_label == type_label);
  182. }
  183. // === Invercargill.Element ===
  184. /**
  185. * Returns the GLib.Type for EntitySet.
  186. *
  187. * @return The EntitySet type
  188. */
  189. public Type? type() { return typeof(EntitySet); }
  190. /**
  191. * Returns the type name string.
  192. *
  193. * @return "EntitySet"
  194. */
  195. public string type_name() { return "EntitySet"; }
  196. /**
  197. * EntitySets are never null.
  198. *
  199. * @return false
  200. */
  201. public bool is_null() { return false; }
  202. /**
  203. * Checks if this set is of the specified type.
  204. *
  205. * @param t The type to check
  206. * @return true if this set is of type t
  207. */
  208. public bool is_type(Type t) { return t.is_a(typeof(EntitySet)); }
  209. /**
  210. * Checks if this set can be assigned to the specified type.
  211. *
  212. * @return true if assignable
  213. */
  214. public bool assignable_to<T>() { return typeof(T).is_a(typeof(EntitySet)); }
  215. /**
  216. * Checks if this set can be assigned to the specified type.
  217. *
  218. * @param t The target type
  219. * @return true if assignable
  220. */
  221. public bool assignable_to_type(Type t) { return is_type(t); }
  222. /**
  223. * Casts this set to type T.
  224. *
  225. * @return This set as type T, or null if not possible
  226. */
  227. public T? @as<T>() throws Invercargill.ElementError { return this; }
  228. /**
  229. * Asserts and casts this set to type T.
  230. *
  231. * @return This set as type T
  232. */
  233. public T assert_as<T>() { return (T) this; }
  234. /**
  235. * Casts this set to type T, returning a default if not possible.
  236. *
  237. * @return This set as type T, or the default
  238. */
  239. public T? as_or_default<T>() { return this; }
  240. /**
  241. * Attempts to get this set as type T.
  242. *
  243. * @param result Output parameter for the result
  244. * @return true if successful
  245. */
  246. public bool try_get_as<T>(out T result) { result = this; return true; }
  247. /**
  248. * Converts this set to a value of the requested type.
  249. *
  250. * @param requested_type The type to convert to
  251. * @return The value
  252. */
  253. public GLib.Value to_value(GLib.Type requested_type) throws GLib.Error {
  254. var v = Value(typeof(EntitySet));
  255. v.set_object(this);
  256. return v;
  257. }
  258. /**
  259. * Returns a string representation of this set.
  260. *
  261. * @return A string in the form "EntitySet(count)"
  262. */
  263. public new string to_string() {
  264. return "EntitySet(%d)".printf(count);
  265. }
  266. }
  267. } // namespace Implexus.Core