/// <summary> /// The valueMap()-step yields a Map representation of the properties of an element. /// It is important to note that the map of a vertex maintains a list of values for each key. /// The map of an edge or vertex-property represents a single property (not a list). /// The reason is that vertices in TinkerPop leverage vertex properties which support multiple values per key. /// CosmosDb implementation doesn't support modulating it with .by(unfold())! /// </summary> /// <param name="builder"></param> /// <param name="parameters">First parameter can be a boolean true to return id and label properties. /// Subsequent ones, if specified, will limit the response to just these properties. /// If omitted, all properties are returned</param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder ValueMap(this GremlinQueryBuilder builder, params IGremlinParameter[] parameters) { // this function can only take true or false if (parameters.Any(p => p == null)) { throw new ArgumentException("Null parameters are not allowed"); } // first parameter can be string or bool if (parameters.Any() && !(parameters.First().TrueValue is bool) && !(bool.TryParse(parameters.First().TrueValue.ToString(), out _)) && !(parameters.First().TrueValue is string)) { throw new GremlinQueryBuilderException( $"{nameof(ValueMap)} only supports boolean or string parameters as the first parameter and '{parameters.First().TrueValue}' does not appear to be"); } // subsequent parameters can only be strings if (parameters.Length > 1 && parameters.Skip(1).Any(p => !(p.TrueValue is string))) { throw new GremlinQueryBuilderException( $"{nameof(ValueMap)} only supports strings as parameters other than the initial one that can also be a boolean"); } if (parameters.Any(p => p.TrueValue is string s && (s == "id" || s == "label"))) { throw new GremlinQueryBuilderException( $"Property names 'id' and 'label' are not allowed. " + $"If these are required, pass boolean 'true' as the first parameter to {nameof(ValueMap)}, " + $"e.g. ValueMap(true) or ValueMap(true, \"PropertyName\""); } builder.AddArguments(parameters.OfType <GremlinArgument>().ToArray()); return(builder.Add($"valueMap({parameters.Expand()})")); }
public void RejectNonStringParameters() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); Assert.Throws <GremlinQueryBuilderException>(() => builder.As(new GremlinParameter(42))); Assert.Throws <GremlinQueryBuilderException>(() => builder.As(new GremlinParameter(false))); }
/// <summary> /// Predicate that checks if the incoming number is greater than or equal /// to the first provided number and less than the second /// </summary> /// <param name="builder"></param> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder Between(this GremlinQueryBuilder builder, IGremlinParameter start, IGremlinParameter end) { if (start == null) { throw new ArgumentNullException(nameof(start)); } if (end == null) { throw new ArgumentNullException(nameof(end)); } if (!start.IsNumber()) { throw new GremlinQueryBuilderException( $"{nameof(Between)} only supports numeric parameters and '{start.TrueValue}' does not appear to conform to this"); } if (!end.IsNumber()) { throw new GremlinQueryBuilderException( $"{nameof(Between)} only supports numeric parameters and '{end.TrueValue}' does not appear to conform to this"); } builder.AddArgument(start as GremlinArgument); builder.AddArgument(end as GremlinArgument); return(builder.Add($"between({start.QueryStringValue},{end.QueryStringValue})")); }
/// <summary> /// It is possible to filter vertices, edges, and vertex properties based on their properties using has()-step (filter) /// </summary> /// <param name="builder"></param> /// <param name="label"></param> /// <param name="key"></param> /// <param name="value">Optional value to check for. If not supplied, checks for any value for the property referenced by <paramref name="key"/></param> /// <returns></returns> public static GremlinQueryBuilder Has(this GremlinQueryBuilder builder, IGremlinParameter label, IGremlinParameter key, IGremlinParameter value) { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (!(key.TrueValue is string)) { throw new GremlinQueryBuilderException($"{nameof(key)} must always resolve to a string for property key and {key.TrueValue} does not"); } if (label == null) { throw new ArgumentNullException(nameof(key)); } if (!(label.TrueValue is string)) { throw new GremlinQueryBuilderException($"{nameof(label)} must always resolve to a string for property key and {label.TrueValue} does not"); } if (value == null) { throw new ArgumentNullException(nameof(value)); } builder.AddArgument(key as GremlinArgument); builder.AddArgument(value as GremlinArgument); builder.AddArgument(label as GremlinArgument); return(builder.Add($"has({label.QueryStringValue},{key.QueryStringValue},{value.QueryStringValue})")); }
public void GeneratesCorrectSyntaxWithFunction() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.By(new GremlinQueryBuilder().AddE(new GremlinParameter("myparam"))); Assert.Equal("by(addE('myparam'))", builder.Query); }
/// <summary> /// The valueMap()-step yields a Map representation of the properties of an element. /// It is important to note that the map of a vertex maintains a list of values for each key. /// The map of an edge or vertex-property represents a single property (not a list). /// The reason is that vertices in TinkerPop leverage vertex properties which support multiple values per key. /// CosmosDb implementation doesn't support modulating it with .by(unfold())! /// </summary> /// <param name="builder"></param> /// <param name="properties">If specified, only these properties will be included. Cannot contain 'id' and 'label'</param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder ValueMap(this GremlinQueryBuilder builder, string[] properties) { // overload for simplifying usage var parameters = (properties ?? new string[0]).Select(p => (IGremlinParameter) new GremlinParameter(p)); return(builder.ValueMap(parameters.ToArray())); }
public void GenerateCorrectSyntaxWithIntegerParameter() { var builder = new GremlinQueryBuilder(); builder.Barrier((GremlinParameter)5); Assert.Equal("barrier(5)", builder.Query); }
public void GenerateCorrectSyntaxForStringParameters() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.Aggregate(new GremlinParameter("myparam")); Assert.Equal("aggregate('myparam')", builder.Query); }
public void AcceptScope() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.Aggregate(GremlinScope.Local, new GremlinParameter("myparam")); Assert.Equal("aggregate(local,'myparam')", builder.Query); }
public void GenerateCorrectSyntaxWithParameter() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.By(new GremlinParameter("myparam")); Assert.Equal("by('myparam')", builder.Query); }
public void GenerateCorrectSyntaxForParameterlessInvocation() { var builder = new GremlinQueryBuilder(); builder.Barrier(); Assert.Equal("barrier()", builder.Query); }
/// <summary> /// There are two general ways to use select()-step. /// Select labeled steps within a path (as defined by as() in a traversal). /// Select objects out of a Map<String,Object> flow (i.e. a sub-map). /// When the set of keys or values (i.e. columns) of a path or map are needed, use select(keys) /// and select(values), respectively. select() can also accept a traversal that emits a key /// </summary> /// <param name="builder"></param> /// <param name="columns"></param> /// <returns></returns> public static GremlinQueryBuilder Select(this GremlinQueryBuilder builder, GremlinColumnModifier columns) { if (columns == null) { throw new ArgumentNullException(nameof(columns)); } return(builder.Add($"select({columns.QueryStringValue})")); }
public void GenerateCorrectSyntaxWithoutParameters() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.ValueMap(); Assert.Equal("valueMap()", builder.Query); Assert.Empty(builder.Arguments); }
public void GenerateCorrectSyntaxWithSingleBoolParameter() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.ValueMap(new GremlinParameter(true)); Assert.Equal("valueMap(true)", builder.Query); Assert.Empty(builder.Arguments); }
/// <summary> /// The or()-step ensures that at least one of the provided traversals yield a result (filter). /// The or()-step can take an arbitrary number of traversals. At least one of the traversals must /// produce at least one output for the original traverser to pass to the next step. /// An infix notation can be used as well /// </summary> /// <param name="builder"></param> /// <param name="functions"></param> /// <returns></returns> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder Or(this GremlinQueryBuilder builder, params GremlinQueryBuilder[] functions) { if (functions == null || !functions.Any()) { return(builder.Add("or()")); // for infix notation } builder.AddArguments(functions?.SelectMany(f => f.GremlinArguments).ToArray() ?? new GremlinArgument[0]); return(builder.Add($"or({functions.Expand()})")); }
public void GenerateCorrectSyntaxWithFunctions() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.And(new GremlinQueryBuilder().__().Out(new GremlinParameter("myparam")).HasId("test"), new GremlinQueryBuilder().__().Out().Has((GremlinParameter)"name", (GremlinParameter)"MyName")); Assert.Equal("and(__.out('myparam').hasId('test'),__.out().has('name','MyName'))", builder.Query); }
public void GenerateCorrectSyntaxForStringParameters() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.As("a"); builder.As((GremlinParameter)"b", (GremlinParameter)"c"); Assert.Equal("as('a').as('b','c')", builder.Query); }
public void SupportArguments() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.As(new GremlinArgument("argumentName", "argumentValue")); Assert.Equal("as(argumentName)", builder.Query); Assert.Single(builder.Arguments); }
public void GenerateCorrectSyntaxForStringParametersAndTraversals() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.AddE(new GremlinParameter("myparam")); builder.AddE(new GremlinQueryBuilder().G().V("someId").Values((GremlinParameter)"label")); Assert.Equal("addE('myparam').addE(g.V('someId').values('label'))", builder.Query); }
public static GremlinQueryBuilder Map(this GremlinQueryBuilder builder, GremlinQueryBuilder inner) { if (inner == null) { return(builder); } builder.AddArguments(inner.GremlinArguments); return(builder.Add($"map({inner.Query})")); }
public void GenerateCorrectSyntaxWithArguments() { GremlinQueryBuilder builder = new GremlinQueryBuilder(); builder.ValueMap(new GremlinArgument("bool", true), new GremlinArgument("propertyName", "prop")); Assert.Equal("valueMap(bool,propertyName)", builder.Query); Assert.Equal(2, builder.Arguments.Count); }
public void HandleArguments() { var builder = new GremlinQueryBuilder(); builder.Barrier(new GremlinArgument("five", 5)); Assert.Equal("barrier(five)", builder.Query); Assert.Single(builder.Arguments); }
/// <summary> /// The valueMap()-step yields a Map representation of the properties of an element. /// It is important to note that the map of a vertex maintains a list of values for each key. /// The map of an edge or vertex-property represents a single property (not a list). /// The reason is that vertices in TinkerPop leverage vertex properties which support multiple values per key. /// CosmosDb implementation doesn't support modulating it with .by(unfold())! /// </summary> /// <param name="builder"></param> /// <param name="includeIdAndLabel">Boolean true to return id and label properties</param> /// <param name="properties">If specified, only these properties will be included. Cannot contain 'id' and 'label'</param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder ValueMap(this GremlinQueryBuilder builder, bool includeIdAndLabel, params string[] properties) { // overload for simplifying usage var parameters = new IGremlinParameter[] { new GremlinParameter(includeIdAndLabel) }.Concat( (properties ?? new string[0]).Select(p => new GremlinParameter(p))); return(builder.ValueMap(parameters.ToArray())); }
/// <summary> /// Remove the traverser if its element does not have any of the ids /// </summary> /// <param name="builder"></param> /// <param name="parameters"></param> /// <returns></returns> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder HasId(this GremlinQueryBuilder builder, params IGremlinParameter[] parameters) { if (parameters == null || !parameters.Any()) { throw new GremlinQueryBuilderException($"{nameof(HasId)} requires at least one parameter in {nameof(parameters)}"); } builder.AddArguments(parameters.OfType <GremlinArgument>().ToArray()); return(builder.Add($"hasId({parameters.Expand()})")); }
/// <summary> /// The project()-step (map) projects the current object into a Map<String,Object> keyed by provided labels. /// It is similar to <seealso cref="SelectFunction.Select(CosmosDB.Gremlin.Fluent.GremlinQueryBuilder,CosmosDB.Gremlin.Fluent.IGremlinParameter[])"/>, save that instead of retrieving and modulating historic traverser state, /// it modulates the current state of the traverser /// </summary> /// <param name="builder"></param> /// <param name="labels"></param> /// <returns></returns> public static GremlinQueryBuilder Project(this GremlinQueryBuilder builder, params string[] labels) { if (labels == null || !labels.Any()) { return(builder.Add($"project()")); } return(builder.Add( $"project({labels.Select(p => (IGremlinParameter) new GremlinParameter(p)).ToArray().Expand()})")); }
/// <summary> /// The from()-step is not an actual step, but instead is a "step-modulator" similar to as() and by(). /// If a step is able to accept traversals or strings then from() is the means by which they are added. /// The general pattern is step().from(). See <seealso cref="ToFunction.To(CosmosDB.Gremlin.Fluent.GremlinQueryBuilder,CosmosDB.Gremlin.Fluent.IGremlinParameter)"/>. /// The list of steps that support from()-modulation are: simplePath(), cyclicPath(), path(), and addE() /// </summary> /// <param name="builder"></param> /// <param name="func"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> public static GremlinQueryBuilder From(this GremlinQueryBuilder builder, GremlinQueryBuilder func) { if (func == null) { throw new ArgumentNullException(nameof(func)); } builder.AddArguments(func.GremlinArguments); return(builder.Add($"from({func.Query})")); }
/// <summary> /// To specify a constant value for a traverser, use the constant()-step (map). /// This is often useful with conditional steps like choose()-step or coalesce()-step /// </summary> /// <param name="builder"></param> /// <param name="parameter"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> public static GremlinQueryBuilder Constant(this GremlinQueryBuilder builder, IGremlinParameter parameter) { if (parameter == null) { throw new ArgumentNullException(nameof(parameter)); } builder.AddArgument(parameter as GremlinArgument); return(builder.Add($"constant({parameter.QueryStringValue})")); }
public static GremlinQueryBuilder InE(this GremlinQueryBuilder builder, params IGremlinParameter[] parameters) { if (parameters == null || !parameters.Any()) { return(builder); } builder.AddArguments(parameters.OfType <GremlinArgument>().ToArray()); return(builder.Add($"inE({parameters.Expand()})")); }
/// <summary> /// The optional()-step (branch/flatMap) returns the result of the specified traversal /// if it yields a result else it returns the calling element, i.e. the identity() /// </summary> /// <param name="builder"></param> /// <param name="traversal"></param> /// <returns></returns> public static GremlinQueryBuilder Optional(this GremlinQueryBuilder builder, GremlinQueryBuilder traversal) { if (traversal == null) { throw new ArgumentNullException(nameof(traversal)); } builder.AddArguments(traversal.GremlinArguments); return(builder.Add($"optional({traversal.Query})")); }
/// <summary> /// The coalesce()-step evaluates the provided traversals in order and returns the first /// traversal that emits at least one element /// </summary> /// <param name="builder"></param> /// <param name="functions"></param> /// <returns></returns> /// <exception cref="GremlinQueryBuilderException"></exception> public static GremlinQueryBuilder Coalesce(this GremlinQueryBuilder builder, params GremlinQueryBuilder[] functions) { if (functions == null || !functions.Any()) { throw new GremlinQueryBuilderException($"{nameof(Coalesce)} requires at least one parameter to be present in {nameof(functions)}"); } builder.AddArguments(functions?.SelectMany(f => f.GremlinArguments).ToArray() ?? new GremlinArgument[0]); return(builder.Add($"coalesce({functions.Expand()})")); }