-
-
Save hyb175/beb9ceed4c34300ba7c77d3d6d44ae52 to your computer and use it in GitHub Desktop.
// https://github.com/realm/realm-js/issues/370#issuecomment-270849466 | |
export default class Realm { | |
constructor(params) { | |
this.schema = {}; | |
this.callbackList = []; | |
this.data = {}; | |
this.schemaCallbackList = {}; | |
params.schema.forEach((schema) => { | |
this.data[schema.name] = {}; | |
}); | |
params.schema.forEach((schema) => { | |
this.schema[schema.name] = schema; | |
}); | |
this.lastLookedUpModel = null; | |
} | |
objects(schemaName) { | |
this.lastLookedUpModel = schemaName; | |
const objects = Object.values(this.data[schemaName]); | |
objects.values = () => objects; | |
objects.sorted = () => this.compareFunc ? objects.sort(this.compareFunc) : objects.sort(); | |
objects.addListener = (cb) => { | |
if (this.schemaCallbackList[schemaName]) { | |
this.schemaCallbackList[schemaName].push(cb); | |
} else { | |
this.schemaCallbackList[schemaName] = [cb]; | |
} | |
}; | |
objects.removeListener = () => {}; | |
objects.filtered = this.filtered ? this.filtered.bind(this, schemaName) : () => objects; | |
return objects; | |
} | |
write(fn) { | |
this.writing = true; | |
fn(); | |
this.writing = false; | |
} | |
create(schemaName, object) { | |
const modelObject = object; | |
const properties = this.schema[schemaName].schema.properties; | |
Object.keys(properties).forEach((key) => { | |
if (modelObject[key] && modelObject[key].model) { | |
this.data[modelObject[key].model][modelObject[key].id] = this.create( | |
modelObject[key].model, modelObject[key], | |
); | |
} else if (modelObject[key] && modelObject[key].length && modelObject[key][0].model) { | |
modelObject[key].forEach((obj) => { | |
this.data[modelObject[key][0].model][obj.id] = obj; | |
}); | |
modelObject[key].filtered = this.filtered ? this.filtered : () => modelObject[key]; | |
modelObject[key].sorted = () => modelObject[key].sort(); | |
} else if (modelObject[key] === undefined) { | |
if (typeof properties[key] === 'object' && properties[key].optional) { | |
modelObject[key] = null; | |
} | |
if (typeof properties[key] === 'object' && ['list', 'linkingObjects'].includes(properties[key].type)) { | |
modelObject[key] = []; | |
modelObject[key].filtered = () => []; | |
modelObject[key].sorted = () => []; | |
} | |
} | |
}); | |
this.data[schemaName][modelObject.id] = modelObject; | |
if (this.writing) { | |
if (this.schemaCallbackList[schemaName]) { | |
this.schemaCallbackList[schemaName].forEach(cb => cb(schemaName, { | |
insertions: { length: 1 }, | |
modifications: { length: 0 }, | |
deletions: { length: 0 }, | |
})); | |
} | |
this.callbackList.forEach((cb) => { cb(); }); | |
} | |
return modelObject; | |
} | |
objectForPrimaryKey(model, id) { | |
this.lastLookedUpModel = model; | |
return this.data[model][id]; | |
} | |
delete(object) { | |
if (this.lastLookedUpModel || object.model) { | |
const model = object.model ? object.model : this.lastLookedUpModel | |
if (Array.isArray(object)) { | |
object.forEach((item) => { | |
delete this.data[model][item.id]; | |
}); | |
} | |
delete this.data[model][object.id]; | |
if (this.writing) { | |
if (this.schemaCallbackList[model]) { | |
this.schemaCallbackList[model].forEach(cb => cb(model, { | |
insertions: { length: 0 }, | |
modifications: { length: 0 }, | |
deletions: { length: 1 }, | |
})); | |
} | |
this.callbackList.forEach((cb) => { cb(); }); | |
} | |
} | |
} | |
deleteAll() { | |
Object.keys(this.schema).forEach((key) => { | |
if (this.writing && this.schemaCallbackList[this.schema[key].name]) { | |
this.schemaCallbackList[this.schema[key].name].forEach(cb => cb(key, { | |
insertions: { length: 0 }, | |
modifications: { length: 0 }, | |
deletions: { length: Object.values(this.data[this.schema[key].name]).length }, | |
})); | |
} | |
this.data[this.schema[key].name] = {}; | |
}); | |
if (this.writing) this.callbackList.forEach((cb) => { cb(); }); | |
} | |
addListener(event, callback) { | |
this.callbackList.push(callback); | |
} | |
prepareData(schemaName, objects) { | |
objects.forEach((object) => { | |
this.create(schemaName, object); | |
}); | |
} | |
} | |
Realm.Object = class Object { | |
isValid() { return true; } | |
}; |
@tuomohopia Hi, the way you want to mock open()
method is gonna be similar to how Object
is mocked.
Something like the following should work:
Realm.open = (params) => {
return new Promise((resolve) => {
resolve(new Realm(params));
});
}
how to use filtered and sort?
how to use filtered and sort?
I'm wondering the same. Hope an anwser shows up :(
@rsbh @rafaelcavalcante
Sorry for the late reply. Filtered
and sort
are definitely the more tricky ones. I have put together a very hacky way to solve this, so I can't say I recommend doing this 😂
See the following for an example:
realm.filtered = jest.fn().mockImplementation(function mockedFiltered() {
const result = realm.objects('Car');
if (result.length) {
result.filtered = jest.fn((query, leadingChar) => {
if (leadingChar === 'D') {
result.sorted = () => cars; // cars is pre-defined earlier
} else {
result.sorted = () => [];
}
return result;
});
}
return result;
});
The example should support calls like realm.objects('Car').filtered('name BEGINSWITH $0', 'D');
This way, we are mocking out the filtered
method and sort can follow a similar pattern.
Thanks for this mock, it helped me alot as part of my business logic is wired up with realm interactions.
In my case I had to adjust the following lines to make it work completely:
const properties = this.schema[schemaName].schema.properties;
to
const properties = this.schema[schemaName].properties;
also, since realm returns proxy objects containing a toJSON function, I added:
const modelObjectJSON = { ...modelObject }
modelObject.toJSON = () => modelObjectJSON
return modelObject
@c-goettert Thanks for the addition!
esse código me ajudou muito, gostaria de contribuir com um MVP de uma função filtered. Neste MVP usei o tradicional eval do javascript para "evoluir" a expressão contida no filtered, apenas substituindo o nome do campo pelo seu respectivo valor, assim a evolução da expressão como um todo deve atender. Temos que tratar bastante coisa ainda (como aspas simples e duplas por exemplo), mas já funciona para alguns casos, consegui utilizar no meu teste de login:
Substituir a linha 30 do código original por isto:
objects.filtered = (filters) => {
if (filters) {
let filteredResult = [];
let keys = Object.keys(objects.values()[0] ||[]);
let filterTemp = filters;
let valuesTemp = objects.values();
for(let ind in valuesTemp) {
filterTemp = filters;
for(let key in keys) {
filterTemp = filterTemp.replace(keys[key], "'" + valuesTemp[ind][keys[key]] + "'");
}
filterTemp = filterTemp.replace(/ and /gi," && ");
filterTemp = filterTemp.replace(/ or /gi," || ");
//console.log("filterTemp",filters, filterTemp, eval(filterTemp));
if (eval(filterTemp)) {
filteredResult.push(valuesTemp[ind]);
}
}
return filteredResult;
} else {
return objects;
}
}
Also needs a method for close
, for those that use it.
close() {
return true;
}
When using require
you should export this file with module.exports = Realm
This seems like an impressively detailed mock but I can't get it to work.
Just keep hitting:
I tried adding an
open()
method. I think the problem is with theexport default
somehow. Anyone got this working anyhow?