public async Task UpsertAsync_MissingColumn_Throws()
        {
            using var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, JObjectWithAllTypes);
            await store.InitializeAsync();

            var upserted = new JObject()
            {
                { "id", "xyz" },
                { "Object", new JObject()
                  {
                      { "id", "abc" }
                  } },
                { "Array", new JArray()
                  {
                      new JObject()
                      {
                          { "id", 3 }
                      }
                  } },
                { "Integer", 123L },
                { "Float", 12.5m },
                { "String", "def" },
                { "Boolean", true },
                { "SomeExtraField", new DateTime(2003, 5, 6, 4, 5, 1, DateTimeKind.Utc) },
                { "Bytes", new byte[] { 1, 2, 3 } },
                { "Guid", new Guid("AB3EB1AB-53CD-4780-928B-A7E1CB7A927C") },
                { "TimeSpan", new TimeSpan(1234) }
            };

            await Assert.ThrowsAsync <InvalidOperationException>(() => store.UpsertAsync(TestTable, new[] { upserted }, false));
        }
        public async Task DeleteAsyncById_CanDeleteEntities()
        {
            var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, IdEntityDefinition);
            await store.InitializeAsync();

            await store.UpsertAsync(TestTable, IdEntityValues, false);

            // Page before the deletion.
            var page = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length, page.Count);
            Assert.Contains(page.Items, o => o.Value <string>("stringValue") == "item#1");

            var ids = IdEntityValues.Skip(2).Take(2).Select(o => o.Value <string>("id")).ToArray();
            await store.DeleteAsync(TestTable, ids);

            // Page after the deletion.
            var page2 = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length - 2, page2.Count);
            Assert.DoesNotContain(page2.Items, o => o.Value <string>("id") == ids[0]);
            Assert.DoesNotContain(page2.Items, o => o.Value <string>("id") == ids[1]);
        }
        public async Task GetItemAsync_ReturnsItem_WhenPresent()
        {
            var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, IdEntityDefinition);
            await store.InitializeAsync();

            await store.UpsertAsync(TestTable, IdEntityValues, false);

            var expected = IdEntityValues.Skip(2).First();
            var result   = await store.GetItemAsync(TestTable, expected.Value <string>("id"));

            Assert.Equal(expected.ToString(Formatting.None), result.ToString(Formatting.None));
        }
        public async Task GetItemAsync_ReturnsNull_WhenMissing()
        {
            var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, IdEntityDefinition);
            await store.InitializeAsync();

            await store.UpsertAsync(TestTable, IdEntityValues, false);

            // Page before the deletion.
            var result = await store.GetItemAsync(TestTable, Guid.NewGuid().ToString());

            Assert.Null(result);
        }
        public async Task UpsertAsync_Returns_OnNoColumns()
        {
            using var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, JObjectWithAllTypes);
            await store.InitializeAsync();

            var upserted = new JObject[] { new JObject() };
            await store.UpsertAsync(TestTable, upserted, false);

            var query = new QueryDescription(TestTable);
            var page  = await store.GetPageAsync(query);

            Assert.Empty(page.Items);
        }
        public async Task UpsertAsync_ThenGetPageAsync_AllTypes()
        {
            using var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, JObjectWithAllTypes);
            await store.InitializeAsync();

            var upserted = new JObject()
            {
                { "id", "xyz" },
                { "Object", new JObject()
                  {
                      { "id", "abc" }
                  } },
                { "Array", new JArray()
                  {
                      new JObject()
                      {
                          { "id", 3 }
                      }
                  } },
                { "Integer", 123L },
                { "Float", 12.5m },
                { "String", "def" },
                { "Boolean", true },
                { "Date", new DateTime(2003, 5, 6, 4, 5, 1, DateTimeKind.Utc) },
                { "Bytes", new byte[] { 1, 2, 3 } },
                { "Guid", new Guid("AB3EB1AB-53CD-4780-928B-A7E1CB7A927C") },
                { "TimeSpan", new TimeSpan(1234) },
                { "Uri", new Uri("http://localhost/") }
            };
            await store.UpsertAsync(TestTable, new[] { upserted }, false);

            var query = new QueryDescription(TestTable);
            var page  = await store.GetPageAsync(query);

            Assert.Single(page.Items);
            Assert.Equal(upserted.ToString(Formatting.None), page.Items.First().ToString(Formatting.None));
        }
        public async Task DeleteAsyncById_EmptyListOfIds()
        {
            var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, IdEntityDefinition);
            await store.InitializeAsync();

            await store.UpsertAsync(TestTable, IdEntityValues, false);

            // Page before the deletion.
            var page = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length, page.Count);

            var ids = Array.Empty <string>();
            await store.DeleteAsync(TestTable, ids);

            // Page after the deletion.
            var page2 = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length, page2.Count);
        }
        public async Task DeleteAsyncByQuery_CanDeleteEntities()
        {
            var store = new OfflineSQLiteStore(ConnectionString);

            store.DefineTable(TestTable, IdEntityDefinition);
            await store.InitializeAsync();

            await store.UpsertAsync(TestTable, IdEntityValues, false);

            // Page before the deletion.
            var page = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length, page.Count);
            Assert.Contains(page.Items, o => o.Value <string>("stringValue") == "item#1");

            QueryDescription query = QueryDescription.Parse(TestTable, "$filter=(stringValue eq 'item#1')");
            await store.DeleteAsync(query);

            // Page after the deletion.
            var page2 = await store.GetPageAsync(new QueryDescription(TestTable) { IncludeTotalCount = true });

            Assert.Equal(IdEntityValues.Length - 1, page2.Count);
            Assert.DoesNotContain(page2.Items, o => o.Value <string>("stringValue") == "item#1");
        }