/// <summary> /// Read instance property value and add to Property dictionary on ODataEntity instance. /// </summary> /// <param name="currentEntity">ODataEntity instance being initialized</param> /// <param name="property">The instance property value being read.</param> /// <param name="propertyName">The name of the instance property being read.</param> private void MaterializeProperty(ODataEntity currentEntity, ODataProperty property, string propertyName) { if (property.Value is ODataComplexValue) { // for a given complex value , we will flatten it out so that // Excel can show these values in a tabular format instead of having to nest rows. // e.g.: if the property value is BoxArt{ SmallUrl ="", LargeUrl =""} // we will convert it into . // instance[BoxArt.SmallUrl] = ""; // instance[BoxArt.LargeUrl] = ""; ODataComplexValue complexPropertyValue = (ODataComplexValue)property.Value; foreach (var primitiveProperty in complexPropertyValue.Properties) { string flattenedPropertyName = string.Join(".", propertyName, primitiveProperty.Name); this.MaterializeProperty(currentEntity, primitiveProperty, flattenedPropertyName); } } else if (property.Value is ODataCollectionValue) { // we don't support collections here yet. } else { // this is a primitive property, assign results to dictionary. currentEntity[propertyName] = property.Value; } }
protected static ODataEntity GetEntity(StringWriter output) { var result = new Dictionary <string, object>(); var jo = (JObject)Deserialize(output); return(ODataEntity.Create((JObject)jo["d"])); }
public void FlattenComplexTypes() { IODataFeedClient target = new ConnectedODataFeedClient(); string requestUri = "http://odata.netflix.com/v2/Catalog/Titles?$top=1&$select=BoxArt"; AutoResetEvent resetEvent = new AutoResetEvent(false); target.FeedDownloaded += (sender, args) => { try { Assert.IsNull(args.Error, "No error expected"); Assert.IsFalse(args.IsCancelled, "No error expected"); Assert.IsNull(args.TotalCount, "No count expected"); Assert.AreEqual(args.Entries.Count(), 1, "Only one entity expected"); ODataEntity entity = args.Entries.Single(); foreach (var propertyName in new[] { "BoxArt.SmallUrl", "BoxArt.MediumUrl", "BoxArt.LargeUrl", "BoxArt.HighDefinitionUrl" }) { Assert.IsTrue(entity.Properties.ContainsKey(propertyName), "{0} property not flattened", propertyName); } } finally { resetEvent.Set(); } }; IAsyncResult expected = target.BeginDownload(requestUri); resetEvent.WaitOne(); }
private List <ODataEntity> ProcessOperationDictionaryResponse(IDictionary <Content, object> input, ODataRequest req, HttpContext httpContext, out int count) { var x = ProcessODataFilters(input.Keys, req, out var totalCount); var output = new List <ODataEntity>(); var projector = Projector.Create(req, true); foreach (var content in x) { var fields = CreateFieldDictionary(content, projector, httpContext); var item = new ODataEntity { { "key", fields }, { "value", input[content] } }; output.Add(item); } count = totalCount ?? output.Count; if (req.CountOnly) { return(null); } return(output); }
/// <summary> /// Use the ODataReader to read results and convert them feed into usable CLR instances. /// </summary> /// <param name="odataReader">OData Reader representing current OData feed download.</param> private void MaterializeResponse(ODataMessageReader odataReader) { var feedReader = this.CreateReader(odataReader); List <ODataEntity> odataEntities = new List <ODataEntity>(); Exception readingError = null; Uri nextPageLink = null; long?totalCount = null; try { ODataEntity currentEntity = new ODataEntity(); while (feedReader.Read()) { // we never expand in this application, so there is no chance of getting back an expanded link switch (feedReader.State) { case ODataReaderState.EntryStart: currentEntity = new ODataEntity(); odataEntities.Add(currentEntity); break; case ODataReaderState.NavigationLinkEnd: ODataNavigationLink navigationLink = (ODataNavigationLink)feedReader.Item; currentEntity.NavigationProperties[navigationLink.Name] = navigationLink.Url; break; case ODataReaderState.EntryEnd: ODataEntry entry = (ODataEntry)feedReader.Item; currentEntity.TypeName = entry.TypeName; currentEntity.EditLink = entry.EditLink; currentEntity.ReadLink = entry.ReadLink; if (entry.MediaResource != null) { currentEntity.MediaUri = entry.MediaResource.ReadLink.OriginalString; currentEntity.MediaType = entry.MediaResource.ContentType; } foreach (var property in entry.Properties) { this.MaterializeProperty(currentEntity, property, property.Name); } break; case ODataReaderState.FeedEnd: ODataFeed feed = (ODataFeed)feedReader.Item; nextPageLink = feed.NextPageLink; totalCount = feed.Count; break; } } } catch (Exception deserializationError) { readingError = deserializationError; } this.RaiseFeedDownloaded(odataEntities, nextPageLink, totalCount, readingError); }
public async System.Threading.Tasks.Task BookFlight(ODataEntity bookingEntity, string collectionName) { try { SharedContext.JsonContext.SetRingVisibility(Visibility.Visible); var execution = this.Store.ScheduleCreateEntity(bookingEntity, collectionName); var response = await execution.Response; if (response is IODataResponseSingle) { if (((IODataResponseSingle)response).PayloadType == ODataType.Entity) { this.FlightBookingEntity = (SAP.Data.OData.Online.ODataEntity)((IODataResponseSingle)response).Payload; } } SharedContext.JsonContext.SetRingVisibility(Visibility.Collapsed); } catch (Exception) { SharedContext.JsonContext.SetRingVisibility(Visibility.Collapsed); throw; } }
private static IQueryable<TElement> ApplyOrderBy<TElement>(IQueryable<TElement> query, ODataSortKeyExpression sortKey, bool isPrimarySort) { var parameter = Expression.Parameter(typeof(TElement)); var translated = Translate(parameter, sortKey.Expression); var lambda = Expression.Lambda(translated, parameter); var methodName = (isPrimarySort ? "OrderBy" : "ThenBy") + (sortKey.Descending ? "Descending" : string.Empty); MethodInfo method; switch (methodName) { case "OrderBy": method = Helpers.GetMethod((IQueryable<object> q) => q.OrderBy(o => o)); break; case "OrderByDescending": method = Helpers.GetMethod((IQueryable<object> q) => q.OrderByDescending(o => o)); break; case "ThenBy": method = Helpers.GetMethod((IOrderedQueryable<object> q) => q.ThenBy(o => o)); break; case "ThenByDescending": method = Helpers.GetMethod((IOrderedQueryable<object> q) => q.ThenByDescending(o => o)); break; default: throw Throw.UnexpectedCase(methodName); } var denormalizedLambda = ODataEntity.Denormalize(lambda); var result = method.GetGenericMethodDefinition() .MakeGenericMethod(lambda.Type.GetGenericArguments(typeof(Func<,>))) .Invoke(null, new object[] { query, denormalizedLambda }); return (IQueryable<TElement>)result; }
public static IQueryable<TElement> Apply<TElement>(IQueryable<TElement> query, ODataQueryExpression oDataQuery, out IQueryable<TElement> inlineCountQuery) { var finalQuery = query; if (oDataQuery.Filter != null) { var parameter = Expression.Parameter(typeof(TElement)); var predicate = Expression.Lambda<Func<TElement, bool>>(Translate(parameter, oDataQuery.Filter), parameter); var denormalizedPredicate = (Expression<Func<TElement, bool>>)ODataEntity.Denormalize(predicate); finalQuery = finalQuery.Where(denormalizedPredicate); } inlineCountQuery = finalQuery; for (var i = 0; i < oDataQuery.OrderBy.Count; ++i) { finalQuery = ApplyOrderBy(finalQuery, oDataQuery.OrderBy[i], isPrimarySort: i == 0); } if (oDataQuery.Skip > 0) { finalQuery = finalQuery.Skip(oDataQuery.Skip); } if (oDataQuery.Top.HasValue) { finalQuery = finalQuery.Take(oDataQuery.Top.Value); } return finalQuery; }
public void ODataEntityTestIncompatibleGet() { var entity = new ODataEntity(new[] { KeyValuePair.Create("A", "100".As <object>()) }); var ex = UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <double?>("A")); ex.Message.ShouldEqual("value '100' of type System.String for property 'A' is not compatible with requested type System.Nullable`1[System.Double]"); }
public void TestGet() { var row = new ODataEntity(new Dictionary<string, object> { { "a", 1 }, { "b", "2" } }); row.Get<int>("A").ShouldEqual(1); row.Get<string>("b").ShouldEqual("2"); UnitTestHelpers.AssertThrows<InvalidCastException>(() => row.Get<string>("a")); UnitTestHelpers.AssertThrows<ArgumentException>(() => row.Get<string>("c")); }
public void TestGet() { var row = new ODataEntity(new Dictionary <string, object> { { "a", 1 }, { "b", "2" } }); row.Get <int>("A").ShouldEqual(1); row.Get <string>("b").ShouldEqual("2"); UnitTestHelpers.AssertThrows <InvalidCastException>(() => row.Get <string>("a")); UnitTestHelpers.AssertThrows <ArgumentException>(() => row.Get <string>("c")); }
public void OData_Children_Entity_SelectChildren_NoExpand() { Test(() => { CreateTestStructure(); var entity = ODataGET <ODataEntity>($"/OData.svc/Root/Sites('{TestSiteName}')", "?metadata=no&$select=Id,Name,Children"); Assert.IsTrue(ODataEntity.Create((JObject)entity.AllProperties["Children"]).IsDeferred); }); }
public void ODataEntityTestNumericCastIssue() { var entity = new ODataEntity(new[] { new KeyValuePair <string, object>("x", 1.5), new KeyValuePair <string, object>("y", long.MaxValue) }); var ex = UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <int>("x")); ex.Message.ShouldEqual("Failed to convert property 'x' value '1.5' of type System.Double to requested type System.Int32"); var ex2 = UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <int>("y")); ex2.Message.ShouldEqual("Failed to convert property 'y' value '9223372036854775807' of type System.Int64 to requested type System.Int32"); }
protected static ODataEntities GetEntities(StringWriter output) { var result = new List <ODataEntity>(); var jo = (JObject)Deserialize(output); var d = (JObject)jo["d"]; var count = d["__count"].Value <int>(); var jarray = (JArray)d["results"]; for (int i = 0; i < jarray.Count; i++) { result.Add(ODataEntity.Create((JObject)jarray[i])); } return(new ODataEntities(result.ToList(), count)); }
private static TExpression ConvertFromUnknownType <TExpression>(TExpression expression, Type type) where TExpression : ODataExpression { // sanity check Throw.If(expression.Type != ODataExpressionType.Unknown, "expression: must be of unknown type"); switch (expression.Kind) { case ODataExpressionKind.MemberAccess: var memberAccess = (ODataMemberAccessExpression)expression.As <ODataExpression>(); return((TExpression)MemberAccess(memberAccess.Expression, ODataEntity.GetProperty(memberAccess.Member.Name, type)).As <ODataExpression>()); default: throw Throw.UnexpectedCase(expression.Kind); } }
internal override ODataEntity Project(Content content, HttpContext httpContext) { var entity = new ODataEntity(); var fields = new Dictionary <string, object>(); var selfurl = GetSelfUrl(content); var fieldNames = content.Fields.Keys; var relevantFieldNames = Request.Select.Count == 0 ? fieldNames : fieldNames.Intersect(Request.Select); foreach (var fieldName in relevantFieldNames) { if (ODataMiddleware.DisabledFieldNames.Contains(fieldName)) { continue; } if (IsAllowedField(content, fieldName)) { if (content.Fields.TryGetValue(fieldName, out var field)) { fields.Add(fieldName, GetJsonObject(field, selfurl, Request)); } else if (fieldName == ICONPROPERTY) { fields.Add(fieldName, content.Icon ?? content.ContentType.Icon); } else { fields.Add(fieldName, null); } } } entity.Add("ContentName", content.Name); entity.Add("ContentType", content.ContentType.Name); entity.Add("Fields", fields); var permissions = ExportPermissions(content); if (permissions != null) { entity.Add("Permissions", permissions); } return(entity); }
public bool TryConvertMethodCallToRowProperty(MethodCallExpression methodCall, out PropertyInfo property) { property = null; try { var normalized = ODataEntity.Normalize(methodCall); if (normalized.NodeType == ExpressionType.MemberAccess) { property = ((MemberExpression)normalized).Member as PropertyInfo; } } catch (ODataCompileException) { } return(property != null); }
public async Task <IODataEntity> CreateStreamEntity() { var stream = await pickAPicture(); if (stream == null) { return(null); } Windows.Storage.Streams.Buffer buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size); await stream.ReadAsync(buffer, (uint)stream.Size, InputStreamOptions.None); DataReader dataReader = DataReader.FromBuffer(buffer); byte[] bytes = new byte[buffer.Length]; dataReader.ReadBytes(bytes); ODataRequestParametersSingle req; IODataResponse resp; IODataRequestExecution exec; req = new ODataRequestParametersSingle("Photos", RequestMode.Create, new ODataUploadMediaResource(bytes, stream.ContentType)); try { exec = Store.ScheduleRequest(req); resp = await exec.Response; } catch (Exception ex) { result.Text += ex.Message + "\n"; return(null); } if (((ODataResponseSingle)resp).PayloadType == ODataType.Error) { return(null); } else { ODataEntity entity = (ODataEntity)((ODataResponseSingle)resp).Payload; await UpdateNonMediaProperty(entity, "Added at: " + DateTime.Now.ToString()); return(entity); } }
public void TestGetValuesFromODataEntity() { var entity = new ODataEntity(new Dictionary <string, object> { { "A", null }, { "B", 1 }, { "C", new ODataEntity(new Dictionary <string, object> { { "X", "abc" } }) }, { "D", ODataValue.FromObject(-1) }, { "F", 1.5 }, }); entity.Get <string>("A").ShouldEqual(null); entity.Get <int>("b").ShouldEqual(1); entity.Get <int?>("b").ShouldEqual(1); entity.Get <ODataValue>("B").Value.ShouldEqual(1); entity.Get <ODataEntity>("c").Get <string>("x").ShouldEqual("abc"); entity.Get <ODataObject>("C").GetType().ShouldEqual(typeof(ODataEntity)); entity.Get <int>("d").ShouldEqual(-1); UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <int>("a")); UnitTestHelpers.AssertThrows <InvalidCastException>(() => entity.Get <long>("F")); }
public static Result Project(IQueryable query, IReadOnlyList <ODataSelectColumnExpression> select) { if (select.Count == 0) { return(Project(query, new[] { ODataExpression.SelectStar() })); } Throw <NotSupportedException> .If(select.Any(sc => !sc.AllColumns && sc.Type == ODataExpressionType.Complex), "Selecting a complex type is only supported when selecting all columns of that type (with '/*')"); var mapping = BuildMapping(select); var parameter = Expression.Parameter(query.ElementType); var newExpression = BuildNewExpression(parameter, mapping); var lambda = Expression.Lambda(newExpression, parameter); var selectMethod = Helpers.GetMethod((IQueryable <object> q) => q.Select(o => o)) .GetGenericMethodDefinition() .MakeGenericMethod(query.ElementType, newExpression.Type); var denormalizedLambda = ODataEntity.Denormalize(lambda); var projected = (IQueryable)selectMethod.Invoke(null, new object[] { query, denormalizedLambda }); var resultMapping = BuildResultMapping(projected.ElementType, mapping); return(new Result(projected, resultMapping)); }
/// <summary> /// Writes the given fields of a Content to the webresponse. /// </summary> /// <param name="httpContext">The current <see cref="HttpContext"/> instance containing the current web-response.</param> /// <param name="fields">A Dictionary<string, object> that will be written.</param> protected abstract Task WriteSingleContentAsync(HttpContext httpContext, ODataEntity fields);
private ODataExpression ParseSimple() { if (this.TryEat(ODataTokenKind.LeftParen)) { // parse group var group = this.ParseExpression(); this.Eat(ODataTokenKind.RightParen); return(group); } ODataToken next; if (this.TryEat(ODataTokenKind.Identifier, out next)) { if (this.TryEat(ODataTokenKind.LeftParen)) { // parse function ODataFunction function; if (!Enum.TryParse(next.Text, ignoreCase: true, result: out function)) { throw new ODataParseException(next.Text + " is not a known ODataFunction!"); } var arguments = this.ParseExpressionList(this.ParseExpression, ODataTokenKind.Comma); this.Eat(ODataTokenKind.RightParen); if (function == ODataFunction.IsOf || function == ODataFunction.Cast) { var typeLiteral = this.ReParseAsType(arguments[arguments.Count - 1]); var argumentsCopy = arguments.ToArray(); argumentsCopy[arguments.Count - 1] = ODataExpression.Constant(typeLiteral); arguments = argumentsCopy; } return(ODataExpression.Call(function, arguments)); } // parse member access var type = this._elementType; // root element type ODataMemberAccessExpression access = null; // root member while (true) { // get the property var property = typeof(ODataObject).IsAssignableFrom(type) ? ODataEntity.GetProperty(next.Text, typeof(ODataObject)) : type.GetProperty(next.Text, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); if (property == null) { throw new ODataParseException("Property '" + next.Text + "' could not be found on type " + type.FullName); } access = ODataExpression.MemberAccess(access, property); // if we don't see '/' followed by an identifier, we're done // we can't just use TryEat() here, because we need to distinguish between Foo/Bar/* and Foo/Bar/Baz if (this.Next().Kind != ODataTokenKind.Slash || this.Next(2).Kind != ODataTokenKind.Identifier) { break; } // otherwise, update next to the next id and then advance type down the property chain this.Eat(ODataTokenKind.Slash); next = this.Eat(ODataTokenKind.Identifier); type = property.PropertyType; } return(access); } // literals if (this.TryEat(ODataTokenKind.NullLiteral, out next)) { return(ODataExpression.Constant(null)); } if (this.TryEat(ODataTokenKind.BinaryLiteral, out next)) { throw new NotImplementedException("Binary Literal Parse"); } if (this.TryEat(ODataTokenKind.BooleanLiteral, out next)) { return(ODataExpression.Constant(bool.Parse(next.Text))); } // see comment on the enum //if (this.TryEat(ODataTokenKind.ByteLiteral, out next)) //{ // return ODataExpression.Constant(Convert.ToByte(next.Text, fromBase: 16)); //} if (this.TryEat(ODataTokenKind.DateTimeLiteral, out next)) { Func <string, string> zeroIfEmpty = s => s.Length == 0 ? "0" : s; var dateTime = new DateTime( year: int.Parse(next.Match.Groups["year"].Value), month: int.Parse(next.Match.Groups["month"].Value), day: int.Parse(next.Match.Groups["day"].Value), hour: int.Parse(next.Match.Groups["hour"].Value), minute: int.Parse(next.Match.Groups["minute"].Value), second: int.Parse(zeroIfEmpty(next.Match.Groups["second"].Value)), millisecond: 0 ) .AddSeconds(double.Parse(zeroIfEmpty(next.Match.Groups["fraction"].Value))); return(ODataExpression.Constant(dateTime)); } if (this.TryEat(ODataTokenKind.DecimalLiteral, out next)) { return(ODataExpression.Constant(decimal.Parse(next.Text.Substring(0, next.Text.Length - 1)))); } if (this.TryEat(ODataTokenKind.DoubleLiteral, out next)) { return(ODataExpression.Constant(double.Parse(next.Text))); } if (this.TryEat(ODataTokenKind.SingleLiteral, out next)) { return(ODataExpression.Constant(float.Parse(next.Text.Substring(0, next.Text.Length - 1)))); } if (this.TryEat(ODataTokenKind.GuidLiteral, out next)) { return(ODataExpression.Constant(Guid.Parse(next.Match.Groups["digits"].Value))); } if (this.TryEat(ODataTokenKind.Int32Literal, out next)) { // Note: this will fail hard if we have an out-of-range int value. However, this is consistent // with MSFT's implementation (see http://services.odata.org/v3/odata/odata.svc/Products?$format=json&$filter=Price%20ge%202147483648) return(ODataExpression.Constant(int.Parse(next.Text))); } if (this.TryEat(ODataTokenKind.Int64Literal, out next)) { return(ODataExpression.Constant(long.Parse(next.Text.Substring(0, next.Text.Length - 1)))); } if (this.TryEat(ODataTokenKind.StringLiteral, out next)) { // unescaping, from http://stackoverflow.com/questions/3979367/how-to-escape-a-single-quote-to-be-used-in-an-odata-query return(ODataExpression.Constant(next.Match.Groups["chars"].Value.Replace("''", "'"))); } throw new ODataParseException("Unexpected token " + this.Next()); }
/// <summary>This method is not supported in this writer.</summary> protected override Task WriteSingleContentAsync(HttpContext httpContext, ODataEntity fields) { throw new SnNotSupportedException(); }
public void TestSerialization() { var row = new ODataEntity(new Dictionary<string, object> { { "a", 1 }, { "b", "2" } }); }
public void TestSerialization() { var row = new ODataEntity(new Dictionary <string, object> { { "a", 1 }, { "b", "2" } }); }
/// <inheritdoc /> protected override async Task WriteSingleContentAsync(HttpContext httpContext, ODataEntity fields) { using (var writer = new StringWriter()) { WriteStart(writer); writer.Write(" <tr><td>Name</td><td>Value</td></tr>\n"); foreach (var item in fields.OrderBy(x => x.Key)) { if (item.Key == "__metadata") { if (item.Value is ODataSimpleMeta simpleMeta) { writer.Write(" <tr><td>__metadata.Uri</td><td>"); writer.Write(simpleMeta.Uri); writer.Write("</td></tr>\n"); writer.Write(" <tr><td>__metadata.Type</td><td>"); writer.Write(simpleMeta.Type); writer.Write("</td></tr>\n"); if (simpleMeta is ODataFullMeta fullMeta) { writer.Write(" <tr><td>__metadata.Actions</td><td>"); WriteValue(writer, fullMeta.Actions.Where(x => !x.Forbidden).Select(x => x.Name)); writer.Write("</td></tr>\n"); writer.Write(" <tr><td>__metadata.Functions</td><td>"); WriteValue(writer, fullMeta.Functions.Where(x => !x.Forbidden).Select(x => x.Name)); writer.Write("</td></tr>\n"); } } } else { writer.Write(" <tr><td>"); writer.Write(item.Key); writer.Write("</td><td>"); WriteValue(writer, item.Value); writer.Write("</td></tr>\n"); } } WriteEnd(writer); var resp = httpContext.Response; resp.ContentType = "text/html"; await WriteRawAsync(writer.GetStringBuilder().ToString(), httpContext); } }
/// <inheritdoc /> protected override async Task WriteSingleContentAsync(HttpContext httpContext, ODataRequest odataRequest, ODataEntity fields) { await WriteAsync(new ODataSingleContent { FieldData = fields }, httpContext, odataRequest).ConfigureAwait(false); }