/* * This file is part of the HyperGraphDB source distribution. This is copyrighted * software. For permitted uses, licensing options and redistribution, please see * the LicensingInformation file at the root level of the distribution. * * Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved. */ package org.hypergraphdb; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.regex.Pattern; import org.hypergraphdb.atom.HGSubgraph; import org.hypergraphdb.atom.HGSubsumes; import org.hypergraphdb.atom.HGTypeStructuralInfo; import org.hypergraphdb.indexing.ByPartIndexer; import org.hypergraphdb.indexing.HGIndexer; import org.hypergraphdb.query.And; import org.hypergraphdb.query.AnyAtomCondition; import org.hypergraphdb.query.ArityCondition; import org.hypergraphdb.query.AtomPartCondition; import org.hypergraphdb.query.AtomPartRegExPredicate; import org.hypergraphdb.query.AtomTypeCondition; import org.hypergraphdb.query.AtomValueCondition; import org.hypergraphdb.query.AtomValueRegExPredicate; import org.hypergraphdb.query.BFSCondition; import org.hypergraphdb.query.ComparisonOperator; import org.hypergraphdb.query.DFSCondition; import org.hypergraphdb.query.DisconnectedPredicate; import org.hypergraphdb.query.HGAtomPredicate; import org.hypergraphdb.query.HGQueryCondition; import org.hypergraphdb.query.IncidentCondition; import org.hypergraphdb.query.IsCondition; import org.hypergraphdb.query.LinkCondition; import org.hypergraphdb.query.MapCondition; import org.hypergraphdb.query.Not; import org.hypergraphdb.query.Or; import org.hypergraphdb.query.OrderedLinkCondition; import org.hypergraphdb.query.PositionedIncidentCondition; import org.hypergraphdb.query.SubgraphContainsCondition; import org.hypergraphdb.query.SubgraphMemberCondition; import org.hypergraphdb.query.SubsumedCondition; import org.hypergraphdb.query.SubsumesCondition; import org.hypergraphdb.query.TargetCondition; import org.hypergraphdb.query.TypePlusCondition; import org.hypergraphdb.query.cond2qry.ExpressionBasedQuery; import org.hypergraphdb.query.impl.DerefMapping; import org.hypergraphdb.query.impl.LinkProjectionMapping; import org.hypergraphdb.transaction.HGTransactionConfig; import org.hypergraphdb.type.HGAtomType; import org.hypergraphdb.type.HGCompositeType; import org.hypergraphdb.type.HGTypedValue; import org.hypergraphdb.type.TypeUtils; import org.hypergraphdb.util.CompositeMapping; import org.hypergraphdb.util.Constant; import org.hypergraphdb.util.HGUtils; import org.hypergraphdb.util.Mapping; import org.hypergraphdb.util.Ref; import org.hypergraphdb.util.Var; import org.hypergraphdb.util.VarContext; /** * <p> * The <code>HGQuery</code> class represents an arbitrary query to the {@link HyperGraph} * database. Queries can be constructed out of {@link HGQueryCondition}s via the static {@link make} * method and then executed through the {@link execute} method. * </p> * * <p> * Queries can be parametarized by a set of variables. You can get and set variables for a * given query execution with the {@link #var(String)} and {@link #var(String, Object)} methods. * Queries that used variables must be "pre-compiled" by first calling the {@link #make(Class, HyperGraph)} * method and then {@link #compile(HGQueryCondition)} with the query condition right away. Multiple * calls to {@link #compile(HGQueryCondition)} on the same <code>HGQuery</code> instance are not * advised. * </p> * * <p> * To ensure thread-safety and allow a single <code>HGQuery</code> instance to be pre-compiled and * reused from multiple threads, each thread of execution will get its own copy of the set of * variables, cloned from the initial set that was created during the compilation of the query. * This initial set of variables remains untouched by the <code>var</code> methods, but can be modified * by the analogous {@link #initialVar(String)} and {@link #initialVar(String, Object)}. * </p> * * @author Borislav Iordanov */ @SuppressWarnings("unchecked") public abstract class HGQuery<SearchResult> implements HGGraphHolder { protected HyperGraph graph; protected VarContext ctx = VarContext.ctx(); /** * <p> * Return the thread-local copy of a given variable. Use this method to * obtain the value of a variable that will be used when executing this query * in the current thread. * </p> */ public <T> Var<T> var(String name) { return (Var<T>)ctx.get(name); } /** * <p>Modify the thread-local copy of a given variable. Use this method to * modify the value of a variable that will be used when executing this query * in the current thread. * </p> */ public <T> HGQuery<SearchResult> var(String name, T value) { ctx.get(name).set(value); return this; } public <T> T initialValue(String name) { return (T)ctx.getGlobalValue(name); } public <T> HGQuery<SearchResult> initialVar(String name, T value) { ctx.setGlobalValue(name, value); return this; } /** * A query that return the empty result set. */ public final static HGQuery<Object> NOP = new HGQuery<Object>() { public HGSearchResult<Object> execute() { return (HGSearchResult<Object>)HGSearchResult.EMPTY; } }; /** * <p> * Create a new query returning all atoms matching the given {@link HGQueryCondition}. The query condition * can be constructed directly from classes implementing the {@link HGQueryCondition} interface or * by using the expression building static methods of the {@link hg} class nested here. * </p> * * <p> * The result of this method can be executed repeatedly. In place where performance is critical and * a given query is executed often, it is beneficial to construct it before hand and reuse. The * performance gain will depend on how complex the condition is. Constructing a query involves * creating an execution plan based on indices etc. Therefore, a trivial condition that only * constraints the type of the atoms doesn't take much time to translate into a query, while a more * complex one involving some structural pattern will burn valuable extra cycles in building a query plan. * </p> * * <p> * <b>IMPORTANT NOTE:</b> This method does not support variables in the query condition. If your * condition contains variables created by one of the {@link #var(String)} methods, please use * the {@link #make(Class, HyperGraph)} to create the query and then invoke its {@link #compile(HGQueryCondition)} * method to specify the condition. * </p> * * @param <SearchResult> The type of the return result. * @param graph The {@link HyperGraph} instance against which the query will be executed. * @param condition The {@link HGQueryCondition} specifying which atoms to return from the graph. * @return An executable <code>HGQuery</code> object. */ public static <SearchResult> HGQuery<SearchResult> make(HyperGraph graph, HGQueryCondition condition) { return (HGQuery<SearchResult>)new ExpressionBasedQuery(graph, condition); } /** * <p> * Compile the passed in condition as <code>this</code> query object and return <code>this</code>. * </p> */ public HGQuery<SearchResult> compile(HGQueryCondition condition) { return this; } /** * <p> * Create a new query with the given result type and bound to the given {@link HyperGraph} instance. * </p> * @param type The type of the result objects. This parameter is only necessary to avoid type casts. * @param graph The database instance. * @return A new, empty <code>HGQuery</code> object. The returned query doesn't have a condition yet. * Please call its {@link #compile(HGQueryCondition)} method in order to specify a condition. */ public static <SearchResult> HGQuery<SearchResult> make(Class<SearchResult> type, HyperGraph graph) { return new ExpressionBasedQuery(graph, true); } /** * <p>Return the {@link HyperGraph} instance against which this query is executed.</p> */ public HyperGraph getHyperGraph() { return graph; } /** * <p>Specify the HyperGraph instance against which this method is executed. This method is intended * mostly for internal use. A <code>HGQuery</code> object is normally constructed by using * information from a specific graph instance (e.g. available indices). Therefore, changing * the graph instance and executing it again may fail if the metadata used in building the query * differs between the two graphs. * </p> */ public void setHyperGraph(HyperGraph graph) { this.graph = graph; } /** * <p> * Execute the query and return the result set. Note that queries are lazily executed so that * results are actually obtained when one iterates (using the <code>next</code> and <code>prev</code> * of the returned object). * </p> */ public abstract HGSearchResult<SearchResult> execute(); /** * <p> * Execute the query and return the first result, if any. Otherwise return <code>null</code>. * </p> */ public SearchResult findOne() { return getHyperGraph().getTransactionManager().ensureTransaction(new Callable<SearchResult>() { public SearchResult call() { HGSearchResult<SearchResult> rs = null; try { rs = execute(); return rs.hasNext() ? rs.next() : null; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Execute the query and accumulate the results in a <code>List</code>. * </p> */ public List<SearchResult> findAll() { return getHyperGraph().getTransactionManager().ensureTransaction(new Callable<List<SearchResult>>() { public List<SearchResult> call() { ArrayList<SearchResult> result = new ArrayList<SearchResult>(); HGSearchResult<SearchResult> rs = null; try { rs = execute(); while (rs.hasNext()) result.add(rs.next()); return result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Execute the query and accumulate the results in a <code>Set</code>. * </p> */ public Set<SearchResult> findInSet() { return getHyperGraph().getTransactionManager().ensureTransaction(new Callable<Set<SearchResult>>() { public Set<SearchResult> call() { HashSet<SearchResult> result = new HashSet<SearchResult>(); HGSearchResult<SearchResult> rs = null; try { rs = execute(); while (rs.hasNext()) result.add(rs.next()); return result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * This class serves as a namespace to a set of syntactically concise functions * for constructing HyperGraph query conditions and performing HyperGraph queries. * With a Java 5+ compiler, you can import the class into your file's namespace * and build HG condition with a much * simpler syntax than constructing the expression tree explicitly. For example: * </p> * * <p> * <code> * <pre> * ...other imports ... * import org.hypergraphdb.HGQuery.hg; * * public void f(HyperGraph graph) * { * // find all link with weight > 1.5 * HGSearchResult rs = graph.find(hg.and(hg.type(MyLink.class), hg.gt("weight", 1.5))); * } * </pre> * </code> * </p> * <p> * or, even more concisely, if there is no naming conflict, import all the function names * directly: * </p> * <p> * <code> * <pre> * ...other imports ... * import org.hypergraphdb.HGQuery.hg.*; * * public void f(HyperGraph graph) * { * // find all link with weight > 1.5 * HGSearchResult rs = graph.find(and(type(MyLink.class), gt("weight", 1.5))); * } * </pre> * </code> * </p> * * <p> * In addition, several methods names <code>get*</code> and <code>find*</code> will * execute queries and return their results in the form of individual objects or Java * collections, thus saving you from the burden of paying attention to always properly * close result sets. * </p> * * @author Borislav Iordanov * */ public static final class hg { public static <T> HGQuery<T> make(Class<T> type, HyperGraph graph) { return HGQuery.make(type, graph); } /** * <p> * Return <code>assertAtom(graph, instance, false)</code>. * </p> */ public static HGHandle assertAtom(final HyperGraph graph, final Object instance) { return assertAtom(graph, instance, false); } /** * <p> * Return the atom handle if <code>instance</code> is already a loaded atom in the cache. * Otherwise, get the default type corresponding to <code>instance.getClass</code> and * return <code>assertAtom(graph, instance, type, ignoreValue)</code>. * </p> */ public static HGHandle assertAtom(final HyperGraph graph, final Object instance, boolean ignoreValue) { if (instance == null) throw new NullPointerException("Can't assert a null atom without specifying a type for it."); HGHandle existing = graph.getHandle(instance); if (existing != null) return existing; HGHandle typeHandle = graph.getTypeSystem().getTypeHandle(instance.getClass()); return assertAtomImpl(graph, instance, typeHandle, ignoreValue); } /** * <p> * Return <code>assertAtom(graph, instance, type, false)</code>. * </p> */ public static HGHandle assertAtom(final HyperGraph graph, final Object instance, final HGHandle type) { return assertAtom(graph, instance, type, false); } /** * <p> * Add a new atom to the specified graph only if it is not already there. An object * is considered in the graph if: * * <ul> * <li>It is associated with a {@link HGHandle} in the graph's cache; or</li> * <li>A lookup for an * atom with the specified type, value and target set returns * a non-empty set. In this case the first atom from the query result is returned.</li> * </ul> * </p> * * @param graph The {@link HyperGraph} database instance. * @param instance The object to be <em>asserted</em> as an atom. * @param type The type of the atom. * @param ignoreValue Whether to ignore the atom value while performing the lookup. The value * of the atom is compared with <code>Object.equals</code> * so it is important that that method be implemented properly for your Java object. The default * implementation in the standard <code>Object</code> class won't work. If the object class * doesn't implement this method and there are no other way to uniquely identify the atom's * value known to HyperGraph, then please use the {@link addUnique} method to specify a condition * for lookup. If the value is not important, which is frequently the case with Java-type links, * then set this parameter to <code>true</code>. * @return The {@link HGHandle} of the asserted atom (either existing or newly added). */ public static HGHandle assertAtom(final HyperGraph graph, final Object instance, final HGHandle type, final boolean ignoreValue) { if (instance != null) { HGHandle existing = graph.getHandle(instance); if (existing != null) { if (graph.getType(existing).equals(type)) return existing; } } return assertAtomImpl(graph, instance, type, ignoreValue); } private static HGHandle assertAtomImpl(final HyperGraph graph, final Object instance, final HGHandle type, final boolean ignoreValue) { return graph.getTransactionManager().ensureTransaction(new Callable<HGHandle>() { public HGHandle call() { And and = new And(); and.add(type(type)); if (instance instanceof HGLink) { HGTypeStructuralInfo typeMeta = graph.getTypeSystem().getTypeMetaData(type); if (typeMeta != null && !typeMeta.isOrdered()) and.add(link((HGLink)instance)); else and.add(orderedLink(HGUtils.toHandleArray((HGLink)instance))); } List<HGIndexer> indexers = graph.getIndexManager().getIndexersForType(type); boolean skipValue = false; if (indexers != null) { HashSet<String> dimensions = new HashSet<String>(); for (HGIndexer idx : indexers) { if (idx instanceof ByPartIndexer) { ByPartIndexer byPart = (ByPartIndexer)idx; HGTypedValue prop = TypeUtils.project(graph, type, instance, byPart.getDimensionPath(), true); and.add(new AtomPartCondition(byPart.getDimensionPath(), prop.getValue())); if (byPart.getDimensionPath().length == 1) dimensions.add(byPart.getDimensionPath()[0]); } } // if we have a complex type where all dimensions are covered by indices,we don't need // to include the full atom value in the condition HGAtomType T = graph.get(type); if (!dimensions.isEmpty() && T instanceof HGCompositeType) { for (Iterator<String> dimIter = ((HGCompositeType)T).getDimensionNames(); dimIter.hasNext(); ) dimensions.remove(dimIter.next()); if (dimensions.isEmpty()) skipValue = true; } } if (!ignoreValue && !skipValue) and.add(eq(instance)); HGHandle h = findOne(graph, and); return h == null ? graph.add(instance, type) : h; } }); } /** * <p> * Construct a {@link HGQueryCondition} that uniquely identifies an atom based on * the passed in <code>Object</code> instance. * </p> * * @param graph The {@link HyperGraph} database instance. * @param instance The object for which an unique atom condition must be constructed. * @return <code>null</code> if <code>instance == null</code>, otherwise a query condition * identifying <code>instance</code> in the database. */ public static HGQueryCondition guessUniquenessCondition(final HyperGraph graph, final Object instance) { if (instance == null) return null; HGHandle type = graph.getTypeSystem().getTypeHandle(instance.getClass()); And and = new And(); and.add(type(type)); and.add(eq(instance)); if (instance instanceof HGLink) and.add(orderedLink(HGUtils.toHandleArray((HGLink)instance))); List<HGIndexer> indexers = graph.getIndexManager().getIndexersForType(type); if (indexers != null) for (HGIndexer idx : indexers) { if (idx instanceof ByPartIndexer) { ByPartIndexer byPart = (ByPartIndexer)idx; Object prop = TypeUtils.project(graph, type, instance, byPart.getDimensionPath(), true); and.add(new AtomPartCondition(byPart.getDimensionPath(), prop)); } } return and; } /** * <p> * Add the given instance as an atom in the graph if and only if no atoms * match the passed in {@link HGQueryCondition} * </p> */ public static HGHandle addUnique(final HyperGraph graph, final Object instance, final HGQueryCondition condition) { return graph.getTransactionManager().ensureTransaction(new Callable<HGHandle>() { public HGHandle call() { HGHandle h = findOne(graph, condition); return h == null ? graph.add(instance) : h; } }); } /** * <p> * Add a new atom of a given type only if there's no atom matching the passed in * {@link HGQueryCondition}. Note that an {@link AtomTypeCondition} * based on the <code>typeHandle</code> parameter is "and-ed" with the <code>condition</code> * parameter. * </p> */ public static HGHandle addUnique(final HyperGraph graph, final Object instance, final HGHandle typeHandle, final HGQueryCondition condition) { return graph.getTransactionManager().ensureTransaction(new Callable<HGHandle>() { public HGHandle call() { HGHandle h = findOne(graph, and(type(typeHandle), condition)); return h == null ? graph.add(instance, typeHandle) : h; } }); } /** * <p> * Add a new atom of a given type only if there's no atom matching the passed in * {@link HGQueryCondition}. Note that an {@link AtomTypeCondition} * based on the <code>javaClass</code> parameter is "and-ed" with the <code>condition</code> * parameter. * </p> */ public static HGHandle addUnique(HyperGraph graph, Object instance, Class javaClass, HGQueryCondition condition) { return addUnique(graph, instance, graph.getTypeSystem().getTypeHandle(javaClass), condition); } /** * <p> * Return a condition that matches a regular expression pattern against the string value of an atom. * </p> * * @param pattern The pattern following the syntax of {@link java.util.regex.Pattern}. */ public static AtomValueRegExPredicate matches(String pattern) { return new AtomValueRegExPredicate(Pattern.compile(pattern)); } /** * <p> * Return a condition that matches a regular expression pattern against the string value of an atom. * </p> * */ public static AtomValueRegExPredicate matches(Pattern pattern) { return new AtomValueRegExPredicate(pattern); } /** * <p> * Return a condition that matches a regular expression pattern against the string value of * an atom's projection (property) along the given path. * </p> * * @param pattern The pattern following the syntax of {@link java.util.regex.Pattern}. */ public static AtomPartRegExPredicate matches(String path, String pattern) { return new AtomPartRegExPredicate(path.split("\\."), Pattern.compile(pattern)); } /** * <p> * Return a condition that matches a regular expression pattern against the string value of * an atom's projection (property) along the given path. * </p> */ public static AtomPartRegExPredicate matches(String path, Pattern pattern) { return new AtomPartRegExPredicate(path.split("\\."), pattern); } /** * <p> * Return the "identity" condition that evaluates to true for a specific handle. It * translates to a result set containing the specified atom handle. * </p> * * @param atomHandle * @return */ public static IsCondition is(HGHandle atomHandle) { return new IsCondition(atomHandle); } /** * <p>Return a {@link HGQueryCondition} constraining the type of the result * to the type identified by <code>typeHandle</code>.</p> * @see AtomTypeCondition */ public static AtomTypeCondition type(HGHandle typeHandle) { return new AtomTypeCondition(typeHandle); } /** * <p>Return a {@link HGQueryCondition} constraining the type of the result * to the type identified by <code>type</code> {@link Ref}. The content of the reference * can be a <code>Class</code> or a {@HGLink} and you can use a variable reference in a * compiled query. </p> */ public static AtomTypeCondition type(Ref<?> type) { return new AtomTypeCondition(type); } /** * <p>Return a {@link HGQueryCondition} constraining the type of the result * to the type corresponding to the Java class <code>clazz</code>.</p> * @see AtomTypeCondition */ public static AtomTypeCondition type(Class<?> clazz) { return new AtomTypeCondition(clazz); } /** * <p>Return a {@link HGQueryCondition} constraining the type of the result * to the type identified by <code>typeHandle</code> and all its sub-types. The set * of sub-types is obtained as the closure of the {@link HGSubsumes} relation.</p> * @see TypePlusCondition */ public static TypePlusCondition typePlus(HGHandle h) { return new TypePlusCondition(h); } /** * <p>Return a {@link HGQueryCondition} constraining the type of the result * to the type corresponding to the Java class <code>clazz</code> and all its sub-types. The set * of sub-types is obtained as the closure of the {@link HGSubsumes} relation.</p> * @see TypePlusCondition */ public static TypePlusCondition typePlus(Class<?> clazz) { return new TypePlusCondition(clazz); } /** * <p>Return a condition constraining the result set to atoms more general than the passed in * <code>specific</code> parameter. This condition is generally useful when searching for types, * but it is applicable to any set atoms interlinked with the {@link HGSubsumes} relation. * @see SubsumesCondition */ public static SubsumesCondition subsumes(HGHandle specific) { return new SubsumesCondition(specific); } /** * <p>Return a condition constraining the result set to atoms more specific than the passed in * <code>general</code> parameter. This condition is generally useful when searching for types, * but it is applicable to any set atoms interlinked with the {@link HGSubsumes} relation. * @see SubsumedCondition */ public static SubsumedCondition subsumed(HGHandle general) { return new SubsumedCondition(general); } /** * <p>Return a condition constraining the result set to atoms more specific than the passed in * <code>general</code> reference parameter. This condition is generally useful when searching for types, * but it is applicable to any set atoms interlinked with the {@link HGSubsumes} relation. * @see SubsumedCondition */ public static SubsumedCondition subsumed(Ref<HGHandle> general) { return new SubsumedCondition(general); } /** * <p>Return a conjunction (logical <code>and</code>) of conditions - atoms in the result set will have * to match all condition in the parameter list.</p> * @see And */ public static And and(HGQueryCondition...clauses) { And and = new And(); for (HGQueryCondition x:clauses) and.add(x); return and; } /** * <p>Return a disjunction (logical <code>or</code>) of conditions - atoms in the result set will have * to match at least one of the conditions in the parameter list.</p> * @see Or */ public static Or or(HGQueryCondition...clauses) { Or or = new Or(); for (HGQueryCondition x:clauses) or.add(x); return or; } /** * <p>Return the negation of an {@link HGAtomPredicate}. </p> * @see Not */ public static Not not(HGAtomPredicate predicate) { return new Not(predicate); } /** * <p> * Return a query condition that constraints the result set to atoms that are targets to a specific link. * </p> * @param linkHandle The handle of the {@link HGLink} whose target the resulting atom should be. * @see TargetCondition */ public static TargetCondition target(HGHandle linkHandle) { return new TargetCondition(linkHandle); } /** * <p> * Return a query condition that constraints the result set to atoms that are targets to a specific link as * specified by the {@link HGHandle} {@link Ref} parameter. * </p> * @param linkHandle A (possibly {@link Var}) reference to the handle of the {@link HGLink} whose target * the resulting atom should be. * @see TargetCondition */ public static TargetCondition target(Ref<HGHandle> linkHandle) { return new TargetCondition(linkHandle); } /** * <p> * Return a condition constraining the result to links to a specific atom. * </p> * @param atomHandle The atom to which resulting links should point to. * @see IncidentCondition */ public static IncidentCondition incident(HGHandle atomHandle) { return new IncidentCondition(atomHandle); } public static IncidentCondition incident(Ref<?> atomHandle) { return new IncidentCondition((Ref<HGHandle>)atomHandle); } /** * <p> * Return a condition constraining the query result set to links pointing to a target atom * positioned within a predetermined range in the link tuple. * </p> * * @param target * A {@link Ref} to the target atom specified as a {@link HGHandle}. * @param lowerBound * A {@link Ref} to the lower bound of the desired range. If the number is negative, it is * counted from the last target in the tuple (e.g. -1 means the last target, -2 the penultimate * target etc.). * @param upperBound * A {@link Ref} to the upper bound of the desired range. If the number is negative, it is * counted from the last target in the tuple (e.g. -1 means the last target, -2 the penultimate * target etc.). * @see PositionedIncidentCondition */ public static PositionedIncidentCondition incidentAt(Ref<HGHandle> target, Ref<Integer> lowerBound, Ref<Integer> upperBound) { return new PositionedIncidentCondition(target, lowerBound, upperBound, hg.constant(false)); } /** * @see {@link #incidentAt(Ref, Ref, Ref)}. */ public static PositionedIncidentCondition incidentAt(HGHandle target, int lowerBound, int upperBound) { return hg.incidentAt(hg.constant(target), hg.constant(lowerBound), hg.constant(upperBound)); } /** * @see {@link #incidentAt(Ref, Ref, Ref)} - <code>position</code> is used both as lower and upper bound. */ public static PositionedIncidentCondition incidentAt(Ref<HGHandle> target, int position) { return hg.incidentAt(target, hg.constant(position), hg.constant(position)); } /** * @see {@link #incidentAt(Ref, Ref, Ref)} - <code>position</code> is used both as lower and upper bound. */ public static PositionedIncidentCondition incidentAt(HGHandle target, int position) { return hg.incidentAt(hg.constant(target), hg.constant(position), hg.constant(position)); } /** * Same as {@link hg#incidentAt(Ref, Ref, Ref) except uses the complement of the specified range. * That is, if you specify a range of [2,4], it will match links that do point to the desired target, * but not at positions 2-4. * @see {@link PositionedIncidentCondition} */ public static PositionedIncidentCondition incidentNotAt(Ref<HGHandle> target, Ref<Integer> lowerBound, Ref<Integer> upperBound) { return new PositionedIncidentCondition(target, lowerBound, upperBound, hg.constant(true)); } /** * @see {@link #incidentNotAt(Ref, Ref, Ref)}. */ public static PositionedIncidentCondition incidentNotAt(HGHandle target, int lowerBound, int upperBound) { return hg.incidentNotAt(hg.constant(target), hg.constant(lowerBound), hg.constant(upperBound)); } /** * @see {@link #incidentNotAt(Ref, Ref, Ref)} - <code>position</code> is used both as lower and upper bound. */ public static PositionedIncidentCondition incidentNotAt(HGHandle target, int position) { return hg.incidentNotAt(hg.constant(target), hg.constant(position), hg.constant(position)); } /** * @see {@link #incidentNotAt(Ref, Ref, Ref)} - <code>position</code> is used both as lower and upper bound. */ public static PositionedIncidentCondition incidentNotAt(Ref<HGHandle> target, int position) { return hg.incidentNotAt(target, hg.constant(position), hg.constant(position)); } /** * <p>Return a condition constraining the query result set to links pointing to a target set * of atoms. * </p> * @param link The target set specified as a {@link HGLink} instance. The order of targets in this * link is ignored - it is treated as a set. * @see LinkCondition */ public static LinkCondition link(HGLink link) { return new LinkCondition(link); } /** * <p>Return a condition constraining the query result set to links pointing to a target set * of atoms. * </p> * @param link The target set specified as a {@link HGHandle} array. The order of targets in this * array is ignored - it is treated as a set. * @see LinkCondition */ public static LinkCondition link(HGHandle...h) { return new LinkCondition(h); } /** * <p>Return a condition constraining the query result set to links pointing to a target set * of atoms, as specified by the list of {@link HGHandle} {@link Ref}. * </p> * @param link The target set specified as an of references to {@link HGHandle}. The order of targets in this * array is ignored - it is treated as a set. * @see LinkCondition */ public static LinkCondition link(Ref<HGHandle>...h) { return new LinkCondition(h); } /** * <p>Return a condition constraining the query result set to links pointing to a target set * of atoms. * </p> * @param C The target set specified as a Java collection. * @see LinkCondition */ public static LinkCondition link(Collection<HGHandle> C) { return new LinkCondition(C); } /** * <p>Return a condition constraining the query result set to being ordered links of a certain * form. * </p> * @param h The target set specified as a {@link HGHandle} array. The order of targets in this * array sets the order of targets in the resulting atoms. * @see OrderedLinkCondition */ public static OrderedLinkCondition orderedLink(HGHandle...h) { return new OrderedLinkCondition(h); } /** * <p>Return a condition constraining the query result set to being ordered links of a certain * form. * </p> * @param h The target set specified as an of {@link Ref} {@link HGHandle}s. The order of targets in this * array sets the order of targets in the resulting atoms. * @see OrderedLinkCondition */ public static OrderedLinkCondition orderedLink(Ref<HGHandle>...h) { return new OrderedLinkCondition(h); } /** * <p>Return a condition constraining the query result set to being ordered links of a certain * form. * </p> * @param L The target set specified as a Java list. The order of targets in this * list sets the order of targets in the resulting atoms. * @see OrderedLinkCondition */ public static OrderedLinkCondition orderedLink(List<HGHandle> L) { return new OrderedLinkCondition(L); } /** * <p>Return a condition constraining the query result set to being links with the specified arity (number * of targets). * </p> * @param i The arity of the atoms in the result set. * @see ArityCondition */ public static ArityCondition arity(int i) { return new ArityCondition(i); } /** * <p>Return a condition constraining the query result set to being links with the specified arity (number * of targets). * </p> * @param i A {@link Ref} to the arity of the atoms in the result set. * @see ArityCondition */ public static ArityCondition arity(Ref<Integer> i) { return new ArityCondition(i); } /** * <p>Return an atom predicate constraining the result set to atoms that are not connected * to other atoms, i.e. whose incidence set is empty.</p> * @see DisconnectedPredicate */ public static DisconnectedPredicate disconnected() { return new DisconnectedPredicate(); } /** * <p> * Return a condition constraining the result set to atoms that are members of the * specified subgraph. * </p> * @param subgraphHandle The atom handle of the {@link HGSubgraph} atoms. */ public static SubgraphMemberCondition memberOf(HGHandle subgraphHandle) { return new SubgraphMemberCondition(subgraphHandle); } /** * <p> * Return a condition constraining the result set to atoms that are instances of * {@link HGSubgraph} and containing the specified atom. * </p> * @param The atom that return subgraphs should contain. */ public static SubgraphContainsCondition contains(HGHandle atom) { return new SubgraphContainsCondition(atom); } /** * <p> * Return a condition that constraints resulting atoms by a specific value and {@link ComparisonOperator}. * </p> * * @param value The value to compare with. * @param op The {@link ComparisonOperator} to use in the comparison. * @see AtomValueCondition */ public static AtomValueCondition value(Object value, ComparisonOperator op) { return new AtomValueCondition(value, op); } /** * <p> * Return a condition that constraints resulting atoms by a specific value * {@link Ref} and {@link ComparisonOperator}. * </p> * * @param value The value reference to compare with. * @param op The {@link ComparisonOperator} to use in the comparison. * @see AtomValueCondition */ public static AtomValueCondition value(Ref<Object> value, ComparisonOperator op) { return new AtomValueCondition((Ref<Object>)(value == null ? hg.constant(value) : value), op); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is equal to * the passed in <code>x</code> parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition eq(Object x) { return value(x, ComparisonOperator.EQ); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is equal to * the passed in <code>x</code> {@link Ref} parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition eq(Ref<Object> x) { return value(x, ComparisonOperator.EQ); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is less than * the passed in <code>x</code> parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition lt(Object x) { return value(x, ComparisonOperator.LT); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is less than * the passed in <code>x</code> {@link Ref} parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition lt(Ref<Object> x) { return value(x, ComparisonOperator.LT); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is greater than * the passed in <code>x</code> parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition gt(Object x) { return value(x, ComparisonOperator.GT); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is greater than * the passed in <code>x</code> {@link Ref} parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition gt(Ref<Object> x) { return value(x, ComparisonOperator.GT); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is less than or equal to * the passed in <code>x</code> parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition lte(Object x) { return value(x, ComparisonOperator.LTE); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is less than or equal to * the passed in <code>x</code> {@link Ref} parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition lte(Ref<Object> x) { return value(x, ComparisonOperator.LTE); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is greater than equal to * the passed in <code>x</code> parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition gte(Object x) { return value(x, ComparisonOperator.GTE); } /** * <p>Return a condition constraining resulting atoms to atoms whose value is greater than equal to * the passed in <code>x</code> {@link Ref} parameter. * </p> * @see AtomValueCondition */ public static AtomValueCondition gte(Ref<Object> x) { return value(x, ComparisonOperator.GTE); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a certain part (e.g. a Java property) as specified by the <code>value</code> and <code>op</code> * {@link ComparisonOperator} parameters. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @param op The {@link ComparisonOperator} to use. Not that if <code>op != ComparisonOperator.EQ</code>, the * atom part must be <code>Comparable</code>. * @see AtomPartCondition */ public static AtomPartCondition part(String path, Object value, ComparisonOperator op) { return new AtomPartCondition(path.split("\\."), value, op); } /** * See {@link #part(String, Object, ComparisonOperator)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition part(String path, Ref<Object> value, ComparisonOperator op) { return new AtomPartCondition(path.split("\\."), (Ref<Object>)(value == null ? hg.constant(value) : value), op); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a part (e.g. a Java property) equal to the specified <code>value</code>. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @see AtomPartCondition */ public static AtomPartCondition eq(String path, Object x) { return part(path, x, ComparisonOperator.EQ); } /** * See {@link #eq(String, Object)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition eq(String path, Ref<Object> x) { return part(path, (Ref<Object>)(x == null ? hg.constant(x) : x), ComparisonOperator.EQ); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a part (e.g. a Java property) less than the specified <code>value</code>. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @see AtomPartCondition */ public static AtomPartCondition lt(String path, Object x) { return part(path, x, ComparisonOperator.LT); } /** * See {@link #lt(String, Object)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition lt(String path, Ref<Object> x) { return part(path, x, ComparisonOperator.LT); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a part (e.g. a Java property) greater than the specified <code>value</code>. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @see AtomPartCondition */ public static AtomPartCondition gt(String path, Object x) { return part(path, x, ComparisonOperator.GT); } /** * See {@link #gt(String, Object)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition gt(String path, Ref<Object> x) { return part(path, x, ComparisonOperator.LT); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a part (e.g. a Java property) less than or equal to the specified <code>value</code>. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @see AtomPartCondition */ public static AtomPartCondition lte(String path, Object x) { return part(path, x, ComparisonOperator.LTE); } /** * See {@link #lte(String, Object)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition lte(String path, Ref<Object> x) { return part(path, x, ComparisonOperator.LT); } /** * <p> * Return a condition constraining the result to atoms of some {@link HGCompositeType} and having * a part (e.g. a Java property) greater than or equal to the specified <code>value</code>. * </p> * @param path The path of the property with the nested value structure of the atom. This is specified with * "dotted" notation. For example: <code>user.address.street</code>. * @param value The value to compare the atom part against. * @see AtomPartCondition */ public static AtomPartCondition gte(String path, Object x) { return part(path, x, ComparisonOperator.GTE); } /** * See {@link #gte(String, Object)}. This method specifying the value as a * {@link Ref}. */ public static AtomPartCondition gte(String path, Ref<Object> x) { return part(path, x, ComparisonOperator.LT); } /** * <p> * Return a "condition" that transforms the result set by applying an arbitrary {@link Mapping} to each * element. * </p> * * @param m The {@link Mapping} to apply. * @param c The underlying condition to evaluate before applying the mapping. * @see MapCondition */ public static HGQueryCondition apply(Mapping<?,?> m, HGQueryCondition c) { return new MapCondition(c, m); } /** * <p> * Return a {@link Mapping} that takes a link atom and returns a target at the given position. * </p> * @param targetPosition The position of the target to be returned. * @see LinkProjectionMapping */ public static Mapping<HGLink, HGHandle> linkProjection(int targetPosition) { return new LinkProjectionMapping(targetPosition); } /** * <p> * Return a {@link Mapping} that takes a link atom and returns a target at the given position. * </p> * @param targetPosition A {@link Ref} to the position of the target to be returned. * @see LinkProjectionMapping */ public static Mapping<HGLink, HGHandle> linkProjection(Ref<Integer> targetPosition) { return new LinkProjectionMapping(targetPosition); } /** * <p> * Return a {@link Mapping} that takes a {@link HGHandle} of an atom and return its runtime against * through a call to <code>HyperGraph.get</code>. * </p> * @param graph The {@link HyperGraph} instance against which to dereference the atom. * @see DerefMapping */ public static Mapping<HGHandle, Object> deref(HyperGraph graph) { return new DerefMapping(graph); } /** * <p> * Short for <code>hg.apply(hg.deref(graph), condition)</code> - assuming the <code>condition</code> * parameter yields a result set of {@link HGHandle}s, the returned condition will yield a result set * of atoms loaded from the <code>graph</code> parameter. * </p> * * @param graph * @param condition * @return */ public static HGQueryCondition deref(HyperGraph graph, HGQueryCondition condition) { return apply(deref(graph), condition); } /** * <p> * Return a {@link Mapping} that given a handle to a link will return the target (handle) at the specified * target position. This is a {@link CompositeMapping} of <code>deref(graph)</code> and <code>linkProjection(targetPosition)</code>. * </p> * @param graph The HyperGraph instance. * @param targetPosition The target position. * @see CompositeMapping */ public static Mapping<HGHandle,HGHandle> targetAt(HyperGraph graph, int targetPosition) { return new CompositeMapping(deref(graph), linkProjection(targetPosition)); } /** * <p> * Return a condition that will yield all atoms in the graph. * </p> * @see AnyAtomCondition */ public static HGQueryCondition all() { return new AnyAtomCondition(); } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start The starting atom. * @see BFSCondition */ public static BFSCondition bfs(HGHandle start) { return new BFSCondition(start); } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @see BFSCondition */ public static BFSCondition bfs(Ref<HGHandle> start) { return new BFSCondition(start); } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start The starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @see BFSCondition */ public static BFSCondition bfs(HGHandle start, HGAtomPredicate lp, HGAtomPredicate sp) { BFSCondition c = new BFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); return c; } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @see BFSCondition */ public static BFSCondition bfs(Ref<HGHandle> start, HGAtomPredicate lp, HGAtomPredicate sp) { BFSCondition c = new BFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); return c; } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start The starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @param returnPreceding Whether to return siblings preceding the current atom in an ordered link. * @param returnSucceeding Whether to return siblings following the current atom in an ordered link. * @see BFSCondition */ public static BFSCondition bfs(HGHandle start, HGAtomPredicate lp, HGAtomPredicate sp, boolean returnPreceding, boolean returnSucceeding) { BFSCondition c = new BFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); c.setReturnPreceeding(returnPreceding); c.setReturnSucceeding(returnSucceeding); return c; } /** * <p> * Return a condition whose result set is the breadth first traversal of the graph * starting a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @param returnPreceding Whether to return siblings preceding the current atom in an ordered link. * @param returnSucceeding Whether to return siblings following the current atom in an ordered link. * @see BFSCondition */ public static BFSCondition bfs(Ref<HGHandle> start, HGAtomPredicate lp, HGAtomPredicate sp, boolean returnPreceding, boolean returnSucceeding) { BFSCondition c = new BFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); c.setReturnPreceeding(returnPreceding); c.setReturnSucceeding(returnSucceeding); return c; } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting with a given atom. * </p> * @param start The starting atom. * @see DFSCondition */ public static DFSCondition dfs(HGHandle start) { return new DFSCondition(start); } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting with a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @see DFSCondition */ public static DFSCondition dfs(Ref<HGHandle> start) { return new DFSCondition(start); } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting with a given atom. * </p> * @param start The starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @see DFSCondition */ public static DFSCondition dfs(HGHandle start, HGAtomPredicate lp, HGAtomPredicate sp) { DFSCondition c = new DFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); return c; } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting with a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @see DFSCondition */ public static DFSCondition dfs(Ref<HGHandle> start, HGAtomPredicate lp, HGAtomPredicate sp) { DFSCondition c = new DFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); return c; } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting a given atom. * </p> * @param start The starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @param returnPreceding Whether to return siblings preceding the current atom in an ordered link. * @param returnSucceeding Whether to return siblings following the current atom in an ordered link. * @see DFSCondition */ public static DFSCondition dfs(HGHandle start, HGAtomPredicate lp, HGAtomPredicate sp, boolean returnPreceeding, boolean returnSucceeding) { DFSCondition c = new DFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); c.setReturnPreceeding(returnPreceeding); c.setReturnSucceeding(returnSucceeding); return c; } /** * <p> * Return a condition whose result set is the depth first traversal of the graph * starting a given atom. * </p> * @param start A {@link Ref} to the starting atom. * @param lp A filtering {@link HGAtomPredicate} constraining what links to follow - only * links satisfying this predicate will be followed. * @param sp A filtering {@link HGAtomPredicate} - only atoms satisfying this predicate * will be *traversed*. If you want all atoms to be traversed, but examine only a subset * of them, use a conjunction of this condition and an {@link HGAtomPredicate}, e.g. * <code>hg.and(hg.type(someType), hg.bfs(startingAtom))</code>. * @param returnPreceding Whether to return siblings preceding the current atom in an ordered link. * @param returnSucceeding Whether to return siblings following the current atom in an ordered link. * @see DFSCondition */ public static DFSCondition dfs(Ref<HGHandle> start, HGAtomPredicate lp, HGAtomPredicate sp, boolean returnPreceeding, boolean returnSucceeding) { DFSCondition c = new DFSCondition(start); c.setLinkPredicate(lp); c.setSiblingPredicate(sp); c.setReturnPreceeding(returnPreceeding); c.setReturnSucceeding(returnSucceeding); return c; } static final HGHandle the_any_handle = new HGHandle() { public HGPersistentHandle getPersistent() { // A persistent "any handle" should never be used // in this context. If needed, it has to be obtained // from the handle factory associated with the graph. // The runtime "any handle" here is only to be used // as a don't care in query expressions. return null; } }; /** * <p>Return a special handle indicating a "don't care" in a condition expression (e.g. * when specifying the form of a link in a <code>hg.orderedLink(hg.anyHandle(), x, y)</code> * condition.</p> * <p> * <strong>Node:</strong> This is not a {@link org.hypergraphdb.HGPersistentHandle}. To get a persistent "don't care" handle, * please use {@link org.hypergraphdb.HGHandleFactory.anyHandle()}. * </p> */ public static HGHandle anyHandle() { return the_any_handle; } /** * <p>Create a new variable with an initial value and attach it to the current variable context.</p> * * @param name The name of the variable. Any previous variable with that name in the current context will * be overriden. * @param initialValue The initial value of the variable. * @return The {@link Var} instance. */ public static <T> Var<T> var(String name, T initialValue) { Var<T> v = VarContext.ctx().get(name); VarContext.ctx().setGlobalValue(name, initialValue); return v; } /** * <p>Create a new variable and attach it to the current variable context.</p> * * @param name The name of the variable. Any previous variable with that name in the current context will * be overriden. * @return The {@link Var} instance. */ public static <T> Var<T> var(String name) { return VarContext.ctx().get(name); } /** * <p>Create a new variable and attach it to the current variable context.</p> * * @param name The name of the variable. Any previous variable with that name in the current context will * be overridden. * @param t A class parameter allowing to specify the type of the variable without providing an initial * value. Use this to avoid ugly type casts. * @return The {@link Var} instance. */ public static <T> Var<T> var(String name, Class<T> t) { return VarContext.ctx().get(name); } /** * <p>Create a new constant reference. The value of this reference cannot be changed.</p> * * @param value The value of the constant. * @return An instance of {@link Constant} whose {@link Constant#get()} method will return * the passed in value. */ public static <T> Ref<T> constant(T value) { return new Constant<T>(value); } /** * <p>Return <code>true</code> if the passed in {@link Ref} is a {@link Var} and * <code>false</code> otherwise. */ public static <T> boolean isVar(Ref<T> ref) { return ref instanceof Var; } /** * <p> * Count the number of atoms that match the query condition parameter. Retrieving * the count might require performing the actual query traversing the result set. * In cases where the condition is simple and the count is available directly from * an index, it is returned right away. Otherwise, the operation may be expensive * when the result set matching <code>cond</code> is large or it takes time * to obtain it. * </p> * * @param graph The HyperGraph against which the counting is performed. * @param cond The condition specifying the result set. * @return The number of atoms satisfying the query condition. */ public static long count(final HyperGraph graph, final HGQueryCondition cond) { return graph.getTransactionManager().ensureTransaction(new Callable<Long>() { public Long call() { ExpressionBasedQuery<?> q = (ExpressionBasedQuery<?>)HGQuery.make(graph, cond); ResultSizeEstimation.Counter counter = ResultSizeEstimation.countersMap.get(q.getCondition().getClass()); if (counter == null) return ResultSizeEstimation.countResultSet(q); else return counter.count(graph, q.getCondition()); } }, HGTransactionConfig.READONLY); } /** * <p> * Count the result set from executing the given query. The query is executed and * the result set scanned completely. * </p> */ public static long count(final HGQuery<?> query) { return query.getHyperGraph().getTransactionManager().ensureTransaction(new Callable<Long>() { public Long call() { return ResultSizeEstimation.countResultSet(query); } }, HGTransactionConfig.READONLY); } // // Querying section. // /** * <p> * Run a query based on the passed in condition. If the result set is not * empty, get and return the atom instance of the first element. Otherwise, * return <code>null</code>. * </p> * * @param graph The HyperGraph database to query. * @param condition The query condition. */ public static <T> T getOne(final HyperGraph graph, final HGQueryCondition condition) { return graph.getTransactionManager().ensureTransaction(new Callable<T>() { public T call() { HGHandle h = null; HGSearchResult<HGHandle> rs = null; try { rs = graph.find(condition); if (rs.hasNext()) h = rs.next(); } finally { if (rs != null) rs.close(); } return h == null ? null : (T)graph.get(h); } }, HGTransactionConfig.READONLY); } /** * <p> * Run a query based on the passed in condition. If the result set is not * empty, return the first <code>HGHandle</code> element. Otherwise, * return <code>null</code>. * </p> * * @param graph The {@link HyperGraph} instance to run the query against. * @param condition The query condition constraining the resulting atom. * @return The very first result from the result set, or <code>null</code> if * the result set is empty. */ public static <T> T findOne(final HyperGraph graph, final HGQueryCondition condition) { return graph.getTransactionManager().ensureTransaction(new Callable<T>() { public T call() { HGSearchResult<T> rs = null; try { rs = graph.find(condition); if (rs.hasNext()) return rs.next(); else return null; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Run a query based on the specified condition and put all <code>HGHandle</code>s * from the result set into a <code>java.util.List</code>. * </p> * * @param graph The {@link HyperGraph} to run the query against. * @param condition The query condition constraining the result set. * @return A list of all results from the result set. */ public static <T> List<T> findAll(final HyperGraph graph, final HGQueryCondition condition) { // final ArrayList<T> result = new ArrayList<T>(); // HGQuery<T> query = HGQuery.make(graph, condition); // HGUtils.queryBatchProcess(query, // new Mapping<T, Boolean>() // { // public Boolean eval(T x) { result.add(x); return Boolean.TRUE; } // }, // 500, // null, // 1); // return result; return graph.getTransactionManager().ensureTransaction(new Callable<List<T>>() { public List<T> call() { ArrayList<T> result = new ArrayList<T>(); HGSearchResult<T> rs = null; try { rs = graph.find(condition); while (rs.hasNext()) result.add(rs.next()); return result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Run a query based on the specified condition and put all atom instances * from the result set into a <code>java.util.List</code>. * </p> * * @param graph The {@link HyperGraph} to run the query against. * @param condition The query condition constraining the result set. * @return A list of all results from the result set, dereferenced as <code>HGHandle</code>s * against the graph. */ public static <T> List<T> getAll(final HyperGraph graph, final HGQueryCondition condition) { // final ArrayList<T> result = new ArrayList<T>(); // HGQuery<HGHandle> query = HGQuery.make(graph, condition); // HGUtils.queryBatchProcess(query, // new Mapping<HGHandle, Boolean>() // { // public Boolean eval(HGHandle x) { result.add((T)graph.get(x)); return Boolean.TRUE; } // }, // 500, // null, // 1); // return result; return graph.getTransactionManager().ensureTransaction(new Callable<List<T>>() { public List<T> call() { ArrayList<Object> result = new ArrayList<Object>(); HGSearchResult<HGHandle> rs = null; try { rs = graph.find(condition); while (rs.hasNext()) result.add(graph.get(rs.next())); return (List<T>)result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Execute the given query, put all the elements from the result set in a <code>List</code> * and return that <code>List</code> * </p> */ public static <T> List<T> findAll(final HGQuery<T> query) { // final ArrayList<T> result = new ArrayList<T>(); // HGUtils.queryBatchProcess(query, // new Mapping<T, Boolean>() // { // public Boolean eval(T x) { result.add(x); return Boolean.TRUE; } // }, // 500, // null, // 1); // return result; return query.getHyperGraph().getTransactionManager().ensureTransaction(new Callable<List<T>>() { public List<T> call() { ArrayList<T> result = new ArrayList<T>(); HGSearchResult<T> rs = null; try { rs = query.execute(); while (rs.hasNext()) result.add(rs.next()); return result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } /** * <p> * Execute the given query, put all atom instances * from the result set into a <code>java.util.List</code>. * </p> */ public static <T> List<T> getAll(final HGQuery<HGHandle> query) { return query.getHyperGraph().getTransactionManager().ensureTransaction(new Callable<List<T>>() { public List<T> call() { ArrayList<Object> result = new ArrayList<Object>(); HGSearchResult<HGHandle> rs = null; try { rs = query.execute(); while (rs.hasNext()) result.add(query.getHyperGraph().get(rs.next())); return (List<T>)result; } finally { if (rs != null) rs.close(); } } }, HGTransactionConfig.READONLY); } } }