/// <summary> /// Initializes a new instance of the FunctionSegment class /// </summary> /// <param name="function">the function representing the Function</param> internal FunctionSegment(Function function) : base() { ExceptionUtilities.CheckArgumentNotNull(function, "function"); this.Container = null; this.Function = function; this.UseParentheses = false; }
/// <summary> /// Initializes a new instance of the FunctionSegment class /// </summary> /// <param name="function">the function representing the Function</param> /// <param name="container">the entity container for the function</param> /// <param name="useParentheses">used to determine if the uri generated will have parentheses</param> internal FunctionSegment(Function function, EntityContainer container, bool useParentheses) : base() { ExceptionUtilities.CheckArgumentNotNull(function, "function"); this.Container = container; this.Function = function; this.UseParentheses = useParentheses; }
/// <summary> /// Checks for a name collision between an action's name and a property's name /// </summary> /// <param name="function">The function to check for name property collision</param> /// <param name="bindingEntityDataType">The bindingEntityDataType is the entity to check against</param> /// <param name="actualInstanceEntityType">the entity type of the instance of the entity</param> /// <returns>a string representing the entity container's name</returns> public string BuildExpectedContainerName(Function function, EntityDataType bindingEntityDataType, EntityType actualInstanceEntityType) { string containerName = string.Empty; // check for open entity type on the function definition or on the actual entity itself if (bindingEntityDataType.Definition.IsOpen || actualInstanceEntityType.IsOpen) { containerName = string.Concat(function.Model.GetDefaultEntityContainer().Name, "."); } var foundNameCollision = bindingEntityDataType.Definition.AllProperties.Where(a => a.Name.Equals(function.Name)).FirstOrDefault(); if (foundNameCollision != null && !bindingEntityDataType.Definition.IsOpen) { containerName = string.Concat(function.Model.GetDefaultEntityContainer().Name, "."); } return containerName; }
/// <summary> /// Converts a Payload that contains the action parameters into QueryValues /// </summary> /// <param name="parametersPayload">Parameter Payload</param> /// <param name="action">Function that has the parameters that will be converted to a QueryValue</param> /// <returns>A Lookup of parameter names and QueryValues</returns> public IDictionary<string, QueryValue> Convert(ComplexInstance parametersPayload, Function action) { var parametersLookup = new Dictionary<string, QueryValue>(); foreach (var property in parametersPayload.Properties) { var functionParameter = action.Parameters.Single(p => p.Name == property.Name); var functionParameterQueryType = this.QueryTypeLibrary.GetDefaultQueryType(functionParameter.DataType); QueryValue parameterValue = null; if (property.ElementType == ODataPayloadElementType.ComplexMultiValueProperty) { var complexMultValueProperty = property as ComplexMultiValueProperty; parameterValue = this.PayloadElementToQueryValueConverter.Convert(complexMultValueProperty.Value, functionParameterQueryType); } else if (property.ElementType == ODataPayloadElementType.ComplexProperty) { var complexProperty = property as ComplexProperty; parameterValue = this.PayloadElementToQueryValueConverter.Convert(complexProperty.Value, functionParameterQueryType); } else if (property.ElementType == ODataPayloadElementType.PrimitiveMultiValueProperty) { var derivedProperty = property as PrimitiveMultiValueProperty; parameterValue = this.PayloadElementToQueryValueConverter.Convert(derivedProperty.Value, functionParameterQueryType); } else if (property.ElementType == ODataPayloadElementType.PrimitiveProperty) { var derivedProperty = property as PrimitiveProperty; parameterValue = this.PayloadElementToQueryValueConverter.Convert(derivedProperty.Value, functionParameterQueryType); } ExceptionUtilities.CheckObjectNotNull(parameterValue, "Cannot convert to query value parameter for Action that is of type {0} and has a payload like {1}", property.ElementType, property); parametersLookup.Add(property.Name, parameterValue); } return parametersLookup; }
/// <summary> /// Adds new <see cref="Function"/> to the model. /// </summary> /// <param name="function">Function to be added</param> public void Add(Function function) { ExceptionUtilities.CheckArgumentNotNull(function, "function"); ExceptionUtilities.Assert(function.Model == null, "Function was already added to another model"); function.Model = this; this.functionsList.Add(function); }
/// <summary> /// Find out whether action matches with the ODataUri select function segment /// </summary> /// <param name="action">The action</param> /// <param name="selectSegment">The segment</param> /// <returns>Whether action matches with the function segment</returns> private bool FuctionMatchWithSelectFunctionSegment(Function action, ODataUriSegment selectSegment) { FunctionSegment selectFunctionSegment = selectSegment as FunctionSegment; if (selectFunctionSegment != null && selectFunctionSegment.Function == action) { return true; } // Sometimes the $select segment is an UnrecognizedSegment UnrecognizedSegment otherTypeOfSelectSegment = selectSegment as UnrecognizedSegment; if (otherTypeOfSelectSegment != null && selectFunctionSegment == null) { string actionName = action.Name; // Determine the if selction segment was <Action Name> or <EntityContainer>.<Action Name> if (otherTypeOfSelectSegment.Value.Contains('.')) { actionName = string.Concat(action.Model.GetDefaultEntityContainer().Name, ".", actionName); } if (otherTypeOfSelectSegment.Value.Equals(actionName, System.StringComparison.OrdinalIgnoreCase)) { return true; } } return false; }
protected virtual void VisitFunction(Function function) { this.VisitAnnotatedItem(function); foreach (var parameter in function.Parameters) { this.VisitFunctionParameter(parameter); } }
/// <summary> /// Find out whether to expect action descriptor with projection in request uri /// </summary> /// <param name="requestUri">The request uri</param> /// <param name="action">The action</param> /// <param name="isTopLevelElement">Whether the entity being verified is top level payload element</param> /// <returns>Whether to expect action descriptor</returns> private bool ExpectActionWithProjection(ODataUri requestUri, Function action, bool isTopLevelElement) { ODataUriSegmentPathCollection selectSegments = requestUri.SelectSegments; ODataUriSegmentPathCollection expandSegments = requestUri.ExpandSegments; // handle single level $select path, expect action descriptor if $select=ActionName or $select=Container.* foreach (var selectSegmentPath in selectSegments.Where(ss => ss.Count == 1)) { ODataUriSegment selectSegment = selectSegmentPath.Single(); if (isTopLevelElement && this.FuctionMatchWithSelectFunctionSegment(action, selectSegment)) { return true; } if (this.IsSelectAllFunctionSegment(selectSegment)) { return true; } } // handle multiple level $select path, expect action descriptor for $expand=Rating if: $select=Rating or $select=Rating/ActionName or $Select=Rating/Container.* foreach (var expandSegmentPath in expandSegments) { List<ODataUriSegment> expandSegmentList = expandSegmentPath.ToList(); foreach (var selectSegmentPath in selectSegments.Where(ss => ss.Count == expandSegmentPath.Count || ss.Count == expandSegmentPath.Count + 1)) { List<ODataUriSegment> selectSegmentList = selectSegmentPath.ToList(); if (this.FunctionMatchWithExpandSegmentList(selectSegmentList, expandSegmentList, action)) { return true; } } } return false; }
/// <summary> /// Find out whether to expect action descriptor given expand and select segments. /// </summary> /// <param name="selectSegmentList">The select segments</param> /// <param name="expandSegmentList">The expand segments</param> /// <param name="action">The action</param> /// <returns>Whether to expect action descriptor</returns> private bool FunctionMatchWithExpandSegmentList(List<ODataUriSegment> selectSegmentList, List<ODataUriSegment> expandSegmentList, Function action) { // check if $select path and $expand path matchs int index = 0; NavigationSegment expandNavSegment = null; foreach (var expandSegment in expandSegmentList) { expandNavSegment = expandSegment as NavigationSegment; ExceptionUtilities.CheckArgumentNotNull(expandNavSegment, "Unexpected expand segment."); NavigationSegment selectNavSegment = selectSegmentList[index] as NavigationSegment; if (selectNavSegment == null || !expandNavSegment.NavigationProperty.Equals(selectNavSegment.NavigationProperty)) { return false; } index++; } // check if the action binding type matches with last segment of $expand path EntityDataType bindingEntityDataType = action.Parameters.First().DataType as EntityDataType; ExceptionUtilities.CheckArgumentNotNull(bindingEntityDataType, "Unexpected feed-bound action."); EntityType bindingEntityType = bindingEntityDataType.Definition; if (bindingEntityType != expandNavSegment.NavigationProperty.ToAssociationEnd.EntityType) { return false; } // expect action descriptor (return true) for $expand=Rating if: $select=Rating, $select=Rating/ActionName, $Select=Rating/Container.* if (selectSegmentList.Count == expandSegmentList.Count + 1) { ODataUriSegment lastSelectSegment = selectSegmentList.Last(); return this.FuctionMatchWithSelectFunctionSegment(action, lastSelectSegment) || this.IsSelectAllFunctionSegment(lastSelectSegment); } return true; }
private bool FunctionSignaturesAreSame(Function f1, Function f2) { if (f1.FullName != f2.FullName) { return false; } return this.ParametersMatch(f1.Parameters, f2.Parameters); }
/// <summary> /// Checks if the expected action descriptor in the case where the entity type is open and the property is open /// </summary> /// <param name="function">The function to check for name property collision</param> /// <param name="bindingEntityDataType">The bindingEntityDataType is the entity to check against</param> /// <param name="expectActionDescriptor">current value of the expected behavior</param> /// <returns>true is the action descriptor is expected in response payload</returns> public bool VerifyIfOpenType(Function function, EntityDataType bindingEntityDataType, bool expectActionDescriptor) { if ((expectActionDescriptor == false) && bindingEntityDataType.Definition.IsOpen) { // in open types, an action with a name collision will be returned in metadata var possibleNameCollision = bindingEntityDataType.Definition.AllProperties.Where(a => a.Name.Equals(function.Name)).FirstOrDefault(); if (possibleNameCollision != null) { // if property is not declared, then action descriptor will be present expectActionDescriptor = !possibleNameCollision.IsMetadataDeclaredProperty(); } } return expectActionDescriptor; }
/// <summary> /// Initializes a new instance of the LinqToAstoriaReplaceFunctionParameterReferenceVisitor class /// </summary> /// <param name="function">The function for which to replace parameters</param> /// <param name="arguments">Argumnets for the function call</param> public LinqToAstoriaReplaceFunctionParameterReferenceVisitor(Function function, IEnumerable<QueryExpression> arguments) { this.PushFunctionCallToStack(function, arguments); }
private void CompareFunction(Function expectedFunction, Function actualFunction) { this.CompareReturnType( expectedFunction.ReturnType, actualFunction.ReturnType, string.Format(CultureInfo.InvariantCulture, "Function '{0}'", expectedFunction.Name)); this.CompareParameters( expectedFunction.Parameters, actualFunction.Parameters, string.Format(CultureInfo.InvariantCulture, "Function '{0}'", expectedFunction.Name)); }
private StoredProcedure ConvertToStoredProcedure(Function customFunction) { string functionName = this.GetFunctionName(customFunction); string schema = this.GetSchemaName(customFunction); var storedProcedure = new StoredProcedure(schema, functionName); foreach (var parameter in customFunction.Parameters) { storedProcedure.Parameters.Add(this.ConvertToDatabaseFunctionParameter(parameter)); } var bodyAnnotation = customFunction.Annotations.OfType<StoreFunctionBodyAnnotation>().SingleOrDefault(); if (bodyAnnotation != null) { storedProcedure.Body = bodyAnnotation.Body; } foreach (var returnTypeAnnotation in customFunction.Annotations.OfType<StoredProcedureReturnTypeFunctionAnnotation>()) { var storedProcedureReturnTypeAnnotation = new StoredProcedureReturnTypeAnnotation(this.ConvertToDatabaseType(returnTypeAnnotation.ReturnType)); storedProcedureReturnTypeAnnotation.BodyGenerationAnnotation = this.GetStoreFunctionBodyGenerationInfoToStoreItem(returnTypeAnnotation.BodyGenerationAnnotation); storedProcedure.Annotations.Add(storedProcedureReturnTypeAnnotation); } return storedProcedure; }
/// <summary> /// Removes a <see cref="Function"/> from the model. /// </summary> /// <param name="function">Function to be removed</param> public void Remove(Function function) { ExceptionUtilities.CheckArgumentNotNull(function, "function"); ExceptionUtilities.Assert(function.Model == this, "Function was not added to this model"); ExceptionUtilities.Assert(this.functionsList.Remove(function), "Function was not added to this model"); function.Model = null; }
private void AddCommandTextToAnnotation(Function function, string body) { var metatdataAnnotation = function.Annotations.OfType<StoreFunctionMetadataAnnotation>().Single(); metatdataAnnotation.CommandText = body; }
private bool ShouldGenerateCommandText(Function function) { var useCommandTextAnnotation = function.Annotations.OfType<UseStoreFunctionCommandTextAnnotation>().SingleOrDefault(); if (useCommandTextAnnotation != null) { return useCommandTextAnnotation.UseCommandText; } return false; }
private string GetSchemaName(Function customFunction) { string schema = null; var functionInStoreAnnotation = customFunction.Annotations.OfType<StoreFunctionMetadataAnnotation>().SingleOrDefault(); if (functionInStoreAnnotation != null) { schema = string.IsNullOrEmpty(functionInStoreAnnotation.Schema) ? null : functionInStoreAnnotation.Schema; } return schema; }
private string GetFunctionName(Function customFunction) { string functionName = customFunction.Name; var functionInStoreAnnotation = customFunction.Annotations.OfType<StoreFunctionMetadataAnnotation>().SingleOrDefault(); if (functionInStoreAnnotation != null) { functionName = string.IsNullOrEmpty(functionInStoreAnnotation.StoreFunctionName) ? functionName : functionInStoreAnnotation.StoreFunctionName; } return functionName; }
private DatabaseFunction ConvertToDatabaseFunction(Function customFunction) { string functionName = this.GetFunctionName(customFunction); string schema = this.GetSchemaName(customFunction); var databaseFunction = new DatabaseFunction(schema, functionName); databaseFunction.ReturnType = this.ConvertToDatabaseType(customFunction.ReturnType); foreach (var parameter in customFunction.Parameters) { databaseFunction.Parameters.Add(this.ConvertToDatabaseFunctionParameter(parameter)); } var bodyGenerationAnnotation = this.GetStoreFunctionBodyGenerationInfoToStoreItem(customFunction.Annotations.OfType<StoreFunctionBodyGenerationInfoAnnotation>().SingleOrDefault()); if (bodyGenerationAnnotation != null) { databaseFunction.Annotations.Add(bodyGenerationAnnotation); } var bodyAnnotation = customFunction.Annotations.OfType<StoreFunctionBodyAnnotation>().SingleOrDefault(); if (bodyAnnotation != null) { databaseFunction.Body = bodyAnnotation.Body; } return databaseFunction; }
/// <summary> /// Creates a Function that takes one or more arguments, and returns the first of its arguments /// </summary> /// <param name="name"> /// The name of the function /// </param> /// <param name="firstArgumentType">The type of the first argument for the function</param> /// <param name="otherArgumentsTypes">The types of the rest of the arguments for the function</param> /// <returns> A Function that returns the first of its parameters.</returns> public static Function CreateSimpleServiceOperation(string name, DataType firstArgumentType, params DataType[] otherArgumentsTypes) { ExceptionUtilities.CheckArgumentNotNull(name, "name"); ExceptionUtilities.CheckArgumentNotNull(firstArgumentType, "firstArgumentType"); ExceptionUtilities.CheckArgumentNotNull(otherArgumentsTypes, "otherArgumentsTypes"); var function = new Function(name) { ReturnType = firstArgumentType, Parameters = { new FunctionParameter("arg0", firstArgumentType), }, Annotations = { new LegacyServiceOperationAnnotation() { Method = HttpVerb.Get }, new FunctionBodyAnnotation() { FunctionBody = CommonQueryBuilder.FunctionParameterReference("arg0"), }, } }; for (int i = 0; i < otherArgumentsTypes.Length; i++) { function.Parameters.Add(new FunctionParameter("arg" + (i + 1).ToString(CultureInfo.InvariantCulture), otherArgumentsTypes[i])); } return function; }
private void AddEntityTypeDrivenToggleActions(EntityModelSchema schema, EntitySet entitySet) { int functionCount = 0; var entityType = entitySet.EntityType; // Create a bunch of functions based on the entityType provided var toggleProperty = this.Random.ChooseFrom(entityType.AllProperties.Where(p => typeof(BooleanDataType).IsAssignableFrom(p.PropertyType.GetType()))); var properties = entityType.Properties.Where(p => !p.IsStream()).AsEnumerable(); var navigationProperties = entityType.NavigationProperties; var bindingTypes = new DataType[] { DataTypes.EntityType.WithDefinition(entityType), DataTypes.CollectionOfEntities(entityType) }; // Create a function where this type is returned and a input parameter foreach (var memberProperty in properties) { if (memberProperty == toggleProperty) { continue; } // Skip if we have used a datatype already if (this.useDataTypes.ContainsKey(memberProperty.PropertyType)) { continue; } else { this.useDataTypes.Add(memberProperty.PropertyType, true); } foreach (var bindingDataType in bindingTypes) { string funcNameString = bindingDataType is CollectionDataType ? "_FuncCollectionBound_" : "_Func_"; var function = new Function(entityType.NamespaceName, entityType.Name + "_" + memberProperty.Name + funcNameString + functionCount) { ReturnType = memberProperty.PropertyType, Parameters = { new FunctionParameter(entityType.Name, bindingDataType), new FunctionParameter(memberProperty.Name, memberProperty.PropertyType) }, Annotations = { new ServiceOperationAnnotation() { IsAction = true, BindingKind = OperationParameterBindingKind.Sometimes }, new ActionWithSingleParameterReturnedAnnotation(), } }; schema.Add(function); functionCount++; var noReturnFunction = new Function(entityType.NamespaceName, entityType.Name + "_" + memberProperty.Name + funcNameString + functionCount) { Parameters = { new FunctionParameter(entityType.Name, bindingDataType), new FunctionParameter(memberProperty.Name, memberProperty.PropertyType) }, Annotations = { new ServiceOperationAnnotation() { IsAction = true }, new ToggleBoolPropertyValueActionAnnotation() { ToggleProperty = toggleProperty.Name, } } }; schema.Add(noReturnFunction); functionCount++; var noParameterFunction = new Function(entityType.NamespaceName, entityType.Name + "_" + memberProperty.Name + funcNameString + functionCount) { ReturnType = memberProperty.PropertyType, Parameters = { new FunctionParameter(entityType.Name, bindingDataType), }, Annotations = { new ServiceOperationAnnotation() { IsAction = true }, new ToggleBoolPropertyValueActionAnnotation() { ToggleProperty = toggleProperty.Name, ReturnProperty = memberProperty.Name, } } }; schema.Add(noParameterFunction); functionCount++; } } // Create a function where this type is returned and a input parameter foreach (var navigationProperty in navigationProperties) { var navigationEntityType = navigationProperty.ToAssociationEnd.EntityType; DataType returnType = DataTypes.EntityType.WithDefinition(navigationEntityType); if (navigationProperty.ToAssociationEnd.Multiplicity == EndMultiplicity.Many) { returnType = DataTypes.CollectionType.WithElementDataType(returnType); } // Skip if we have used a datatype already if (this.useDataTypes.ContainsKey(returnType)) { continue; } else { this.useDataTypes.Add(returnType, true); } foreach (var bindingDataType in bindingTypes) { string funcNameString = bindingDataType is CollectionDataType ? "_FuncCollectionBound_" : "_Func_"; var navigationFunction = new Function(entityType.NamespaceName, entityType.Name + "_" + navigationProperty.Name + funcNameString + functionCount) { ReturnType = returnType, Parameters = { new FunctionParameter(entityType.Name, bindingDataType), }, Annotations = { new ServiceOperationAnnotation() { IsAction = true }, new ToggleBoolPropertyValueActionAnnotation() { ToggleProperty = toggleProperty.Name, ReturnProperty = navigationProperty.Name, } } }; schema.Add(navigationFunction); functionCount++; var noReturnNavigationFunction = new Function(entityType.NamespaceName, entityType.Name + "_" + navigationProperty.Name + funcNameString + functionCount) { Parameters = { new FunctionParameter(entityType.Name, bindingDataType), }, Annotations = { new ServiceOperationAnnotation() { IsAction = true }, new ToggleBoolPropertyValueActionAnnotation() { ToggleProperty = toggleProperty.Name, } } }; schema.Add(noReturnNavigationFunction); functionCount++; } } }