Example #1
0
        private static JObject ApplySortsToData(JObject data, List <DataSort> dataSorts)
        {
            // get the collection we want to sort in our data
            JArray existing = (JArray)data.SelectToken("Location.Rows");

            // create a custom comparer that understands how we want sort elements
            var comparer = new JObjectSortComparer(dataSorts);

            // sort the collection using our custom comparer
            var sorted = existing.AsQueryable().OrderBy(obj => (JObject)obj, comparer);

            // put the sorted collection back into the orginal data
            data["Location"]["Rows"] = new JArray(sorted);

            return(data);
        }
Example #2
0
        public void Test()
        {
            var dataArray = new JArray(
                new JObject(
                    new JProperty("Name", "Greg"),
                    new JProperty("DOB", new DateTime(1987, 7, 27)),
                    new JProperty("NetWorth", 300),
                    new JProperty("TimeElapsed", new TimeSpan(2, 12, 20, 30)),
                    new JProperty("IsEmployed", true),
                    new JProperty("Job",
                                  new JObject(
                                      new JProperty("Employer", "Tyler Technologies"),
                                      new JProperty("Position", "Engineer"),
                                      new JProperty("Salary", "50000")
                                      )
                                  ),
                    new JProperty("Addresses", new JArray(
                                      new JObject(
                                          new JProperty("Street", "12 Jameco Mill Road"),
                                          new JProperty("City", "Scarborough"),
                                          new JProperty("State", "ME"),
                                          new JProperty("ZipCode", "04074"),
                                          new JProperty("PreviousOwners",
                                                        new JArray(
                                                            new JObject(
                                                                new JProperty("Name", "Bob")
                                                                ),
                                                            new JObject(
                                                                new JProperty("Name", "Chris")
                                                                )
                                                            )
                                                        )
                                          ),
                                      new JObject(
                                          new JProperty("Street", "2218 Schoharie Turnpike"),
                                          new JProperty("City", "Duanesburg"),
                                          new JProperty("State", "NY"),
                                          new JProperty("ZipCode", "12056")
                                          )
                                      ))
                    ),
                new JObject(
                    new JProperty("Name", "Meg"),
                    new JProperty("DOB", new DateTime(1987, 7, 28)),
                    new JProperty("NetWorth", 50.3),
                    new JProperty("TimeElapsed", new TimeSpan(12, 20, 30)),
                    new JProperty("IsEmployed", true),
                    new JProperty("Addresses", new JArray(
                                      new JObject(
                                          new JProperty("Street", "12 Jameco Mill Road"),
                                          new JProperty("City", "Scarborough"),
                                          new JProperty("State", "ME"),
                                          new JProperty("ZipCode", "04074")
                                          ),
                                      new JObject(
                                          new JProperty("Street", "32 Paddock Place"),
                                          new JProperty("City", "South Portland"),
                                          new JProperty("State", "ME"),
                                          new JProperty("ZipCode", "04105")
                                          )
                                      ))
                    ),
                new JObject(
                    new JProperty("Name", "Bob"),
                    new JProperty("DOB", null),
                    new JProperty("NetWorth", null),
                    new JProperty("TimeElapsed", null),
                    new JProperty("IsEmployed", null),
                    new JProperty("Job",
                                  new JObject(
                                      new JProperty("Employer", "Waste Management"),
                                      new JProperty("Position", "Engineer"),
                                      new JProperty("Salary", "70000")
                                      )
                                  )
                    ),
                new JObject(
                    new JProperty("Name", null),
                    new JProperty("DOB", null),
                    new JProperty("NetWorth", -150)
                    ),
                new JObject(
                    )
                );

            var queryable     = dataArray.AsQueryable();
            var parsingConfig = ParsingConfig.Default;

            parsingConfig.CustomTypeProvider = new CustomTypeProvider();

            #region Count
            var simpleCount = queryable.Count();
            #endregion

            #region Filtering

            // String(value) handles null values no problem
            var filteredByString     = queryable.ApplyPropertiesExistFilter("Name").Where("String(Name) == @0", "Greg");
            var stringFilteringCount = filteredByString.Count();

            var filteredByStringContains      = queryable.ApplyPropertiesExistFilter("Name").Where("(Name.Type == @1 ? String.Empty : String(Name)).Contains(@0)", "Greg", JTokenType.Null);
            var filteredByStringContainsCount = filteredByStringContains.Count();

            // DateTime(value) does not handle null values. Need to check for null
            var filteredByDate    = queryable.ApplyPropertiesExistFilter("DOB").Where("(DOB.Type == @1 ? DateTime.MinValue : DateTime(DOB)) <= @0", new DateTime(1987, 7, 27), JTokenType.Null);
            var dateFilteredCount = filteredByDate.Count();

            // Convert.ToDecimal converts null to zero. So we need to account for null specifically
            var filteredByNumber    = queryable.ApplyPropertiesExistFilter("NetWorth").Where("(NetWorth.Type == @1 ? Decimal.MinValue : Convert.ToDecimal(NetWorth)) <= @0", Convert.ToDecimal(0), JTokenType.Null);
            var numberFilteredCount = filteredByNumber.Count();

            // TimeSpans are not stored as a CLR type in JSON objects, they're stored as strings. So we need to cast as string and then parse using TimeSpan.Parse
            var filteredByTimeSpan     = queryable.ApplyPropertiesExistFilter("TimeElapsed").Where("(TimeElapsed.Type == @1 ? TimeSpan.MinValue : TimeSpan.Parse(String(TimeElapsed))) >= @0", new TimeSpan(18, 20, 0), JTokenType.Null);
            var timeSpanFilteringCount = filteredByTimeSpan.Count();

            var filteredByBool      = queryable.ApplyPropertiesExistFilter("IsEmployed").Where("(IsEmployed.Type == @1 ? false : Boolean(IsEmployed)) == @0", true, JTokenType.Null);
            var filteredByBoolCount = filteredByBool.Count();

            // Filtering on a nested one-to-one field
            var filteringNestedOneToOne      = queryable.ApplyPropertiesExistFilter("Job.Position").Where("String(Job.Position) == @0", "Engineer");
            var filteringNestedOneToOneCount = filteringNestedOneToOne.Count();

            // Filtering on a nested one-to-many field
            var filteringNestedOneToMany      = queryable.ApplyPropertiesExistFilter("Addresses.State").Where("Addresses.Any(String(State) == @0)", "ME");
            var filteringNestedOneToManyCount = filteringNestedOneToMany.Count();

            // FIltering on multiple nested sequence operators
            var multipleNestedAny      = queryable.ApplyPropertiesExistFilter("Addresses.PreviousOwners").Where("Addresses.Any(PreviousOwners.Any())");
            var multipleNestedAnyCount = multipleNestedAny.Count();

            var multipleNestedPropertyFilter      = queryable.ApplyPropertiesExistFilter("Addresses.PreviousOwners.Name").Where("Addresses.Any(PreviousOwners.Any(String(Name) == @0))", "Chris");
            var multipleNestedPropertyFilterCount = multipleNestedPropertyFilter.Count();
            #endregion

            #region Grouping

            var groupingByTopLevelBool = queryable.ApplyPropertiesExistFilter("IsEmployed").GroupBy("IsEmployed");
            var distinctGroupsCount    = groupingByTopLevelBool.Count(); // == 2

            var groupingByOneToOneField     = queryable.ApplyPropertiesExistFilter("Job.Position").GroupBy("Job.Position");
            var distinctPositionGroupsCount = groupingByOneToOneField.Count(); // == 2

            var groupingByOneToManyField = queryable.ApplyPropertiesExistFilter("Addresses.State")
                                           .SelectMany("Addresses.Select(it)",              // Hacky workaround to force JToken that is a JArray to be recognized as an enumerable
                                                       "new(Outer as Parent, Inner as Address)",
                                                       "Outer",
                                                       "Inner")
                                           .GroupBy("Address.State");

            var distinctAddressStateGroupCount = groupingByOneToManyField.Count(); // == 2

            #endregion

            #region Selection

            // Using the SelectProperties extension method in conjunction with the NameProjection class allow us to handle missing fields, getting them converted to null
            var firstNameSelector       = queryable.SelectProperties(new NameProjection("Name"));
            var nestedOneToOneSelector  = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("DOB"), new NameProjection("Job.Position", "Position"));
            var nestedOneToManySelector = queryable.SelectProperties(new NameProjection("Name"),
                                                                     new NameProjection("Job.Position", "Position"),
                                                                     new NameProjection("Addresses", new List <NameProjection>
            {
                new NameProjection("State"),
                new NameProjection("City"),
                new NameProjection("PreviousOwners", new List <NameProjection>
                {
                    new NameProjection("Name")
                })
            }));

            var rootLevelCalculation = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("TimeElapsed"), new NameProjection("NetWorth"))
                                       // Calculate NetWorth/TimeElapsed (dollars per hour?)
                                       // Check for null or JTokenType.Null, since the SelectProperties logic adds actual nulls (TODO: need to do this check everywhere)
                                       .Select("new(Name as Name, (NetWorth == null || TimeElapsed == null || NetWorth.Type == @0 || TimeElapsed.Type == @0 ? null : (Decimal(NetWorth) / Decimal(TimeSpan.Parse(String(TimeElapsed)).TotalHours))) as DollarsPerHour)", JTokenType.Null);

            // Calculation with SQL-style null handling
            var nestedOneToOneCalculationSqlNullHandling = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("NetWorth"), new NameProjection("Job.Salary", "Salary"))
                                                           .Select("new(Name as Name, (NetWorth == null || Salary == null || NetWorth.Type == @0 || Salary.Type == @0 ? null : (Decimal(NetWorth) + Decimal(Salary))) as Total)", JTokenType.Null);

            var nestedOneToOneCalculationLogicalNulHandling = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("NetWorth"), new NameProjection("Job.Salary", "Salary"))
                                                              .Select(@"new(
                                                                                        (
                                                                                            (NetWorth == null || NetWorth.Type == @0) && (Salary == null || Salary.Type == @0)
                                                                                        ) ? null : 
                                                                                        (
                                                                                            (
                                                                                                (NetWorth == null || NetWorth.Type == @0) ? 0 : Decimal(NetWorth)
                                                                                            ) + 
                                                                                            (
                                                                                                (Salary == null || Salary.Type == @0) ? 0 : Decimal(Salary)
                                                                                            )
                                                                                        ) as Total
                                                                                    )", JTokenType.Null);

            var nestedOneToManyAggregationSqlNullHandling = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("Addresses"))
                                                            .Select("new(Name as Name, ((Addresses == null || Addresses.Type == @0) ? null : Addresses.Count()) as AddressCount)", JTokenType.Null);

            var nestedOneToManyAggregationLogicalNullHandling = queryable.SelectProperties(new NameProjection("Name"), new NameProjection("Addresses"))
                                                                .Select("new(Name as Name, ((Addresses == null || Addresses.Type == @0) ? 0 : Addresses.Count()) as AddressCount)", JTokenType.Null);

            #endregion



            var i = 0;
        }