Request for querying data objects.
Inheritance: DataObjectSimpleQueryRequest
        public async Task Get_ByCollectionId_WithStateModerated(DataObjectSyncanoClient client)
        {
            //given
            var newRequest = new DataObjectDefinitionRequest();
            newRequest.ProjectId = TestData.ProjectId;
            newRequest.CollectionId = TestData.CollectionId;
            newRequest.State = DataObjectState.Moderated;
            var dataObject = await client.New(newRequest);

            var getRequest = new DataObjectRichQueryRequest();
            getRequest.ProjectId = TestData.ProjectId;
            getRequest.CollectionId = TestData.CollectionId;
            getRequest.State = DataObjectState.Moderated;

            //when
            var result =
                await client.Get(getRequest);

            //then
            result.ShouldNotBeNull();
            result.Any(d => d.Id == dataObject.Id).ShouldBeTrue();

            //cleanup
            var deleteRequest = new DataObjectSimpleQueryRequest();
            deleteRequest.ProjectId = TestData.ProjectId;
            deleteRequest.CollectionId = TestData.CollectionId;
            await client.Delete(deleteRequest);
        }
        public async Task Get_Data2_OrderBy(DataObjectSyncanoClient client)
        {
            //given
            var newData1 = new DataObjectDefinitionRequest();
            newData1.ProjectId = TestData.ProjectId;
            newData1.CollectionId = TestData.CollectionId;
            newData1.DataTwo = 1;

            var newData2 = new DataObjectDefinitionRequest();
            newData2.ProjectId = TestData.ProjectId;
            newData2.CollectionId = TestData.CollectionId;
            newData2.DataTwo = 2;

            var dataObject1 = await client.New(newData1);
            var dataObject2 = await client.New(newData2);

            var getRequest = new DataObjectRichQueryRequest();
            getRequest.ProjectId = TestData.ProjectId;
            getRequest.CollectionId = TestData.CollectionId;
            getRequest.OrderBy = DataObjectOrderBy.DataOne;
            getRequest.Order = DataObjectOrder.Ascending;
            getRequest.AddDataFieldFilter(DataObjectSpecialField.DataTwo, DataObjectOperator.LowerThanOrEquals, 2);
            getRequest.AddDataFieldFilter(DataObjectSpecialField.DataTwo, DataObjectOperator.GreaterThanOrEquals, 1);

            //when
            var result =
                await client.Get(getRequest);

            //then
            result.ShouldNotBeNull();
            result.Count.ShouldEqual(2);
            result[0].Id.ShouldEqual(dataObject1.Id);
            result[1].Id.ShouldEqual(dataObject2.Id);

            //cleanup
            var deleteRequest = new DataObjectSimpleQueryRequest();
            deleteRequest.ProjectId = TestData.ProjectId;
            deleteRequest.CollectionId = TestData.CollectionId;
            await client.Delete(deleteRequest);
        }
        public async Task Get_WithToMuchFolders_ThrowsException(DataObjectSyncanoClient client)
        {
            //given
            var request = new DataObjectRichQueryRequest();
            request.ProjectId = TestData.ProjectId;
            request.CollectionId = TestData.CollectionId;
            request.Folders = new List<string>();
            for (int i = 0; i < DataObjectSyncanoClient.MaxVauluesPerRequest; ++i)
                request.Folders.Add("abc");
            request.Folder = "abc";

            try
            {
                //when
                await client.Get(request);
                throw new Exception("Get should throw an exception");
            }
            catch (Exception e)
            {
                //then
                e.ShouldBeType<ArgumentException>();
            }
        }
        public async Task Get_WithToBigLimit_ThrowsException(DataObjectSyncanoClient client)
        {
            //given
            var request = new DataObjectRichQueryRequest();
            request.ProjectId = TestData.ProjectId;
            request.CollectionId = TestData.CollectionId;
            request.Limit = DataObjectSyncanoClient.MaxVauluesPerRequest + 1;

            try
            {
                //when
                await client.Get(request);
                throw new Exception("Get should throw an exception");
            }
            catch (Exception e)
            {
                //then
                e.ShouldBeType<ArgumentException>();
            }
        }
        public async Task Get_WithNullCollectionIdAndCollectionKey_ThrowsException(DataObjectSyncanoClient client)
        {
            //given
            var request = new DataObjectRichQueryRequest();
            request.ProjectId = TestData.ProjectId;

            try
            {
                //when
                await client.Get(request);
                throw new Exception("Get should throw an exception");
            }
            catch (Exception e)
            {
                //then
                e.ShouldBeType<ArgumentNullException>();
            }
        }
        public async Task Get_WithInvalidProjectId_ThrowsException(DataObjectSyncanoClient client)
        {
            //given
            var request = new DataObjectRichQueryRequest();
            request.ProjectId = "abc";
            request.CollectionId = TestData.CollectionId;

            try
            {
                //when
                await client.Get(request);
                throw new Exception("Get should throw an exception");
            }
            catch (Exception e)
            {
                //then
                e.ShouldBeType<SyncanoException>();
            }
        }
        /// <summary>
        /// Get data from collection(s) or whole project with optional additional filtering. All filters, unless explicitly noted otherwise, affect all hierarchy levels. To paginate and to get more data, use since parameter.
        /// <remarks>The collection_id/collection_key parameter means that one can use either one of them - collection_id or collection_key.</remarks>
        /// <remarks>User API key usage permitted. Returns Data Objects that are in a container with a read_data permission and associated with current user Data Objects that are in a container with a read_own_data permission.</remarks>
        /// </summary>
        /// <param name="request">Request for querying data objects.</param>
        /// <returns>List of DataObject objects.</returns>
        public async Task<List<DataObject>> Get(DataObjectRichQueryRequest request)
        {
            if (request.ProjectId == null)
                throw new ArgumentNullException();

            if (request.CollectionId == null && request.CollectionKey == null)
                throw new ArgumentNullException();

            if (request.Limit > MaxVauluesPerRequest || request.Limit < 0)
                throw new ArgumentException();

            if (request.ChildrenLimit > MaxVauluesPerRequest || request.ChildrenLimit < 0)
                throw new ArgumentException();

            var dataIds = request.DataIds == null ? new List<string>() : new List<string>(request.DataIds);
            if (dataIds.Count + (request.DataId != null ? 1 : 0) > MaxVauluesPerRequest)
                throw new ArgumentException();
            if (request.DataId != null)
                dataIds.Add(request.DataId);

            var folders = request.Folders == null ? new List<string>() : new List<string>(request.Folders);
            if (folders.Count + (request.Folder != null ? 1 : 0) >
                MaxVauluesPerRequest)
                throw new ArgumentException();
            if (request.Folder != null)
                folders.Add(request.Folder);

            var parentIds = request.ParentIds == null ? new List<string>() : new List<string>(request.ParentIds);
            if (parentIds.Count + (request.ParentId != null ? 1 : 0) > MaxVauluesPerRequest)
                throw new ArgumentException();
            if (request.ParentId != null)
                parentIds.Add(request.ParentId);

            var childIds = request.ChildIds == null ? new List<string>() : new List<string>(request.ChildIds);
            if (childIds.Count + (request.ChildId != null ? 1 : 0) > MaxVauluesPerRequest)
                throw new ArgumentException();
            if (request.ChildId != null)
                childIds.Add(request.ChildId);

            var parameters = new
            {
                project_id = request.ProjectId,
                collection_id = request.CollectionId,
                collection_key = request.CollectionKey,
                data_ids = dataIds.Count == 0 ? null : dataIds.ToArray(),
                state = request.State.ToString(),
                folders = folders.Count == 0 ? null : folders.ToArray(),
                since = request.Since,
                max_id = request.MaxId,
                limit = request.Limit,
                order = DataObjectOrderStringConverter.GetString(request.Order),
                order_by = DataObjectOrderByStringConverter.GetString(request.OrderBy),
                filter = request.Filter == null ? null : request.Filter.ToString(),
                include_children = request.IncludeChildren,
                depth = request.Depth,
                children_limit = request.ChildrenLimit,
                parent_ids = parentIds.ToArray(),
                child_ids = childIds.ToArray(),
                by_user = request.ByUser,
                dataFilters = request.DataFieldFilters.ToDictionary(pair =>  pair.Key, pair => pair.Value)
            };

            
            return
                await
                    _syncanoClient.PostAsync<List<DataObject>>("data.get",
                        parameters, "data");
        }