-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f13f75f
commit 3f703eb
Showing
5 changed files
with
215 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/** | ||
* Equality check | ||
* | ||
* Note we do not make a shallow equality check on documents, as it is less efficient and should | ||
* not be necessary: the queryResult.data is built by extracting documents from the state, thus | ||
* preserving references. | ||
* | ||
* @param {*} queryResA | ||
Check failure on line 8 in packages/cozy-client/src/hooks/utils.js
|
||
* @param {*} queryResB | ||
Check failure on line 9 in packages/cozy-client/src/hooks/utils.js
|
||
* @returns | ||
*/ | ||
export const equalityCheckForQuery = (queryResA, queryResB) => { | ||
//console.log('Call equality check : ', queryResA, queryResB) | ||
if (queryResA === queryResB) { | ||
// Referential equality | ||
return true | ||
} | ||
|
||
if ( | ||
typeof queryResA !== 'object' || | ||
queryResA === null || | ||
typeof queryResB !== 'object' || | ||
queryResB === null | ||
) { | ||
// queryResA or queryResB is not an object or null | ||
return false | ||
} | ||
|
||
if (queryResA.id !== queryResB.id) { | ||
return false | ||
} | ||
if (queryResA.fetchStatus !== queryResB.fetchStatus) { | ||
return false | ||
} | ||
|
||
const docsA = queryResA.storeData | ||
const docsB = queryResB.storeData | ||
if (!docsA || !docsB) { | ||
// No data to check | ||
return false | ||
} | ||
|
||
if (docsA.length !== docsB.length) { | ||
// A document was added or removed | ||
return false | ||
} | ||
|
||
for (let i = 0; i < docsA.length; i++) { | ||
if (docsA[i] !== docsB[i]) { | ||
// References should be the same for non-updated documents | ||
return false | ||
} | ||
} | ||
if (queryResA.relationshipNames) { | ||
// In case of relationships, we cannot check referential equality, because we | ||
// "hydrate" the data by creating a new instance of the related relationship class. | ||
// Thus, we check the document revision instead. | ||
const hydratedDataA = queryResA.data | ||
const hydratedDataB = queryResB.data | ||
if (hydratedDataA.length !== hydratedDataB.length) { | ||
return false | ||
} | ||
for (let i = 0; i < hydratedDataA.length; i++) { | ||
for (const name of queryResA.relationshipNames) { | ||
// Check hydrated relationship | ||
const includedA = hydratedDataA[i][name] | ||
const includedB = hydratedDataB[i][name] | ||
if (includedA && includedB) { | ||
if ( | ||
includedA._rev && | ||
includedB._rev && | ||
includedA._rev !== includedB._rev | ||
) { | ||
return false | ||
} | ||
} | ||
} | ||
} | ||
} | ||
//console.log('docs are same') | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
import { equalityCheckForQuery } from './utils' | ||
|
||
const mapIdsToDocuments = (state, doctype, ids) => { | ||
return ids.map(id => state[doctype][id]) | ||
} | ||
|
||
describe('equalityCheckForQuery', () => { | ||
const state = { | ||
documents: { | ||
'io.cozy.files': { | ||
doc1: { | ||
_id: 'doc1' | ||
}, | ||
doc2: { | ||
_id: 'doc2' | ||
}, | ||
doc3: { | ||
_id: 'doc3' | ||
} | ||
} | ||
}, | ||
queries: { | ||
query1: { | ||
id: 'query1', | ||
data: ['doc1', 'doc2'] | ||
}, | ||
query2: { | ||
id: 'query2', | ||
data: ['doc2'] | ||
} | ||
} | ||
} | ||
|
||
const queryResultA1 = { | ||
id: 1, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1', 'doc2']) | ||
} | ||
const queryResultA2 = { | ||
id: 1, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc1', 'doc2']) | ||
} | ||
const queryResultA3 = { | ||
id: 1, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', [ | ||
'doc1', | ||
'doc2', | ||
'doc3' | ||
]) | ||
} | ||
const queryResultA4 = { | ||
id: 1, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc2', 'doc3']) | ||
} | ||
const queryResultB1 = { | ||
id: 2, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc2']) | ||
} | ||
const queryResultB2 = { | ||
id: 2, | ||
data: mapIdsToDocuments(state.documents, 'io.cozy.files', ['doc3']) | ||
} | ||
|
||
it('should return true for referential equality', () => { | ||
expect(equalityCheckForQuery(queryResultA1, queryResultA1)).toBe(true) | ||
expect(equalityCheckForQuery(null, null)).toBe(true) | ||
}) | ||
|
||
it('should return false if one object is null', () => { | ||
expect(equalityCheckForQuery(null, queryResultA1)).toBe(false) | ||
expect(equalityCheckForQuery(queryResultA1, null)).toBe(false) | ||
}) | ||
|
||
it('should return false if one or both objects are not objects', () => { | ||
expect(equalityCheckForQuery('notAnObject', queryResultA1)).toBe(false) | ||
expect(equalityCheckForQuery(queryResultA1, 'notAnObject')).toBe(false) | ||
}) | ||
|
||
it('should return false if `id` properties are different', () => { | ||
expect(equalityCheckForQuery(queryResultA1, queryResultB1)).toBe(false) | ||
}) | ||
|
||
it('should return false if one or both objects lack `data`', () => { | ||
expect(equalityCheckForQuery({ id: 1 }, queryResultA1)).toBe(false) | ||
expect(equalityCheckForQuery(queryResultA1, { id: 1 })).toBe(false) | ||
}) | ||
|
||
it('should return false if `data` lengths are different', () => { | ||
expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false) | ||
}) | ||
|
||
it('should return false if elements in `data` are different', () => { | ||
expect(equalityCheckForQuery(queryResultA1, queryResultA3)).toBe(false) | ||
expect(equalityCheckForQuery(queryResultA3, queryResultA4)).toBe(false) | ||
expect(equalityCheckForQuery(queryResultB1, queryResultB2)).toBe(false) | ||
}) | ||
|
||
it('should return true for matching data array, with equal references ', () => { | ||
expect(equalityCheckForQuery(queryResultA1, queryResultA2)).toBe(true) | ||
}) | ||
|
||
it('should return false for matching data array, with different references ', () => { | ||
const queryResShallowCopyA1 = { | ||
...queryResultA1, | ||
data: { ...queryResultA1.data } | ||
} | ||
expect(equalityCheckForQuery(queryResultA1, queryResShallowCopyA1)).toBe( | ||
false | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters