Skip to content

Commit

Permalink
v3.3.0 (#11)
Browse files Browse the repository at this point in the history
* Fix for sorting being able to override the filter.

* Add date and dateTime filtering support to ClientSideDataService and improve overall sorting and filtering of dates.

* fix date test running in other offsets

* more ClientSideDataService filtering test cases

* v3.3.0
  • Loading branch information
nruffing authored Jan 13, 2024
1 parent 98f9ceb commit fe580d5
Show file tree
Hide file tree
Showing 13 changed files with 1,448 additions and 1,145 deletions.
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,20 @@ Customizable native Vue3 data grid with very limited dependencies. Leverages a f

## Release Notes

### v3.3.0
- Add `date` and `dateTime` filtering support to `ClientSideDataService`.
- Improved `date` and `dateTime` support for sorting and filtering in `ClientSideDataService` ensuring all computations are done on UTC dates and falsey values are converted to the JS minimum date of `1970-01-01 00:00:00.000+00:00`.
- Fix for sorting being able to override the filter.

### v3.2.0
- [#9](https://github.com/nruffing/data-grid-vue/issues/9): Add package export so styles can be loaded via `data-grid-vue/style`.
- Fix bug in `ClientSideDataService` where paging through a sorted grid could cause data to not stay sorted.
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v2.1.0 to leverage ability to debounce the `dragover` event.
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v2.1.0 to leverage ability to debounce the `dragover` event.
- Replace [`debounce`](https://www.npmjs.com/package/debounce) with new [`native-event-vue`](https://www.npmjs.com/package/native-event-vue) package to leverage the lightweight vue-friendly native event handling with debounce.
- Update development dependencies.

### v3.1.0
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v1.1.0
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v1.1.0
- update development dependencies

### v3.0.1
Expand Down Expand Up @@ -193,7 +198,7 @@ Customizable native Vue3 data grid with very limited dependencies. Leverages a f
- Repo now uses [`pnpm`](https://pnpm.io/) where the `data-grid-vue` package is build from the root workspace and the documentation site and dev app are nested workspaces.
- Now being built with `vite` [v5](https://vitejs.dev/blog/announcing-vite5).
- Update [`debounce`](https://www.npmjs.com/package/debounce/v/2.0.0) dependency to new major version v2.0.0 which requires node v18 ([current oldest supported version](https://nodejs.org/en/about/previous-releases)).
- Update ['dragon-drop-vue'](https://www.npmjs.com/package/dragon-drop-vue) dependency to v0.2.0
- Update [`dragon-drop-vue`](https://www.npmjs.com/package/dragon-drop-vue) dependency to v0.2.0
- Documentation site theme update
- Documentation site is now setup up as a [progressive web app](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps).
- bugfix: `DataGridVueOptions.clickOutsideDirectiveName` removed.
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"datagridvue",
"docsearch",
"dragover",
"falsey",
"gapi",
"keyvault",
"navigatable",
Expand Down
265 changes: 265 additions & 0 deletions lib/DataService.Client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
import { expect, test, describe } from 'vitest'
import { ClientSideDataService, StubDataService } from './DataService'
import { SortType } from './Sort'
import { DataType } from './DataGridVue'
import { FilterOperator } from './Filter'

interface TestDataItem {
id: number
name: string
date: string
}

const TestDataItemOne = { id: 1, name: 'Test 1', date: '2024-01-13T12:33:00.000Z' }
const TestDataItemTwo = { id: 2, name: 'Test 2', date: '2024-01-12T12:32:00.000Z' }
const TestDataItemThree = { id: 2, name: 'Test 3', date: '2024-01-11T12:31:00.000Z' }
const TestDataItemFour = { id: 4, name: 'Test 4', date: '2024-01-10T12:30:00.000Z' }
const TestDataItemFive = { id: 5, name: 'Test 5', date: '2024-01-10T12:29:00.000Z' }

const TestDataSet = [TestDataItemThree, TestDataItemTwo, TestDataItemFour, TestDataItemFive, TestDataItemOne] as TestDataItem[]

describe('StubDataService', () => {
test('getPageAsync', async () => {
const pageData = await StubDataService.getPageAsync(1, 10, [], undefined)
expect(pageData).toEqual({
totalItems: 0,
dataItems: [],
})
})
})

describe('ClientSideDataService', () => {
test('getPageAsync | pages', async () => {
const dataService = new ClientSideDataService([...TestDataSet])
const pageDataOne = await dataService.getPageAsync(1, 2, [], undefined)
const pageDataTwo = await dataService.getPageAsync(2, 1, [], undefined)
const pageDataThree = await dataService.getPageAsync(2, 3, [], undefined)
expect(pageDataOne).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemThree, TestDataItemTwo],
})
expect(pageDataTwo).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemTwo],
})
expect(pageDataThree).toEqual({
totalItems: TestDataSet.length,
dataItems: [TestDataItemFive, TestDataItemOne],
})
})

test('getPageAsync | filters', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const testCases = [
{
filter: { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.equals, value: '3' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 0,
expected: [],
},
{
filter: { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.equals, value: '4' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.date, operator: FilterOperator.lessThan, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 2,
expected: [TestDataItemFour, TestDataItemFive],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.date, operator: FilterOperator.equals, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemThree],
},
{
filter: { or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-11' }], and: undefined },
pageNum: 1,
pageSize: 2,
expectedTotalItems: 0,
expected: [],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T12:30:00.000Z' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T14:30:00.000+02:00' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'date', dataType: DataType.dateTime, operator: FilterOperator.equals, value: '2024-01-10T14:30:00.000+02:00' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemFour],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.equals, value: 'Test 3' }],
and: undefined,
},
pageNum: 1,
pageSize: 2,
expectedTotalItems: 1,
expected: [TestDataItemThree],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.notEquals, value: 'Test 3' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 4,
expected: [TestDataItemTwo, TestDataItemFour, TestDataItemFive, TestDataItemOne],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.contains, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 1,
expected: [TestDataItemTwo],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.startsWith, value: 'te' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 5,
expected: [TestDataItemThree, TestDataItemTwo, TestDataItemFour, TestDataItemFive],
},
{
filter: {
or: [{ fieldName: 'name', dataType: DataType.alphanumeric, operator: FilterOperator.endsWith, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 1,
expected: [TestDataItemTwo],
},
{
filter: {
or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.notEquals, value: '2' }],
and: undefined,
},
pageNum: 1,
pageSize: 4,
expectedTotalItems: 3,
expected: [TestDataItemFour, TestDataItemFive, TestDataItemOne],
},
]

for (const testCase of testCases) {
const pageData = await dataService.getPageAsync(testCase.pageNum, testCase.pageSize, [], testCase.filter)
expect(pageData, JSON.stringify(testCase)).toEqual({
totalItems: testCase.expectedTotalItems,
dataItems: testCase.expected,
})
}
})

test('getPageAsync | sorts', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const testCases = [
{
sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFive, TestDataItemFour],
},
{
sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }],
pageNum: 2,
pageSize: 2,
expected: [TestDataItemThree, TestDataItemTwo],
},
{ sort: [{ fieldName: 'id', dataType: DataType.number, type: SortType.descending }], pageNum: 3, pageSize: 2, expected: [TestDataItemOne] },
{ sort: [], pageNum: 3, pageSize: 1, expected: [TestDataItemFour] },
{
sort: [
{ fieldName: 'id', dataType: DataType.number, type: SortType.ascending },
{ fieldName: 'name', dataType: DataType.alphanumeric, type: SortType.descending },
],
pageNum: 1,
pageSize: 3,
expected: [TestDataItemOne, TestDataItemThree, TestDataItemTwo],
},
{
sort: [{ fieldName: 'date', dataType: DataType.date, type: SortType.ascending }],
pageNum: 2,
pageSize: 2,
expected: [TestDataItemThree, TestDataItemTwo],
},
{
sort: [{ fieldName: 'date', dataType: DataType.date, type: SortType.ascending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFour, TestDataItemFive],
},
{
sort: [{ fieldName: 'date', dataType: DataType.dateTime, type: SortType.ascending }],
pageNum: 1,
pageSize: 2,
expected: [TestDataItemFive, TestDataItemFour],
},
]

for (const testCase of testCases) {
const pageData = await dataService.getPageAsync(testCase.pageNum, testCase.pageSize, testCase.sort, undefined)
expect(pageData, JSON.stringify(testCase)).toEqual({
totalItems: TestDataSet.length,
dataItems: testCase.expected,
})
}
})

test('getPageAsync | filters and sorts', async () => {
const dataService = new ClientSideDataService([...TestDataSet])

const filter = { or: [{ fieldName: 'id', dataType: DataType.number, operator: FilterOperator.greaterThan, value: '2' }], and: undefined }
const sort = [
{ fieldName: 'date', dataType: DataType.dateTime, type: SortType.ascending },
{ fieldName: 'name', dataType: DataType.alphanumeric, type: SortType.descending },
]

const pageData = await dataService.getPageAsync(1, 4, sort, filter)

console.log(JSON.stringify(pageData, null, 2))

expect(pageData).toEqual({
totalItems: 2,
dataItems: [TestDataItemFive, TestDataItemFour],
})
})
})
76 changes: 0 additions & 76 deletions lib/DataService.spec.ts

This file was deleted.

1 change: 1 addition & 0 deletions lib/DataService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export class ClientSideDataService implements DataService {

const sortJson = JSON.stringify(sort)
if (sortJson !== this.previousSortJson) {
this.sorted = [...this.filtered]
ClientSideSort.sort(sort, this.sorted)
this.previousSortJson = sortJson
}
Expand Down
Loading

0 comments on commit fe580d5

Please sign in to comment.