-
-
Notifications
You must be signed in to change notification settings - Fork 598
Add EventuallyQueue API #1291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Add EventuallyQueue API #1291
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
340bcf2
Add EventuallyQueue API
dplewis 11738f5
Merge branch 'master' into saveEventually
dplewis 28999b9
Add saveEventually and destroyEventually
dplewis 820751b
Documentation
dplewis 9845031
Add in memory cache, prevent raise conditions
dplewis cf80916
oops
dplewis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,238 @@ | ||
'use strict'; | ||
|
||
const assert = require('assert'); | ||
const Parse = require('../../node'); | ||
const sleep = require('./sleep'); | ||
|
||
describe('Parse EventuallyQueue', () => { | ||
beforeEach(async () => { | ||
await Parse.EventuallyQueue.clear(); | ||
}); | ||
|
||
it('can queue save object', async () => { | ||
const object = new TestObject({ test: 'test' }); | ||
await object.save(); | ||
object.set('foo', 'bar'); | ||
await Parse.EventuallyQueue.save(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const query = new Parse.Query(TestObject); | ||
const result = await query.get(object.id); | ||
assert.strictEqual(result.get('foo'), 'bar'); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
}); | ||
|
||
it('can queue destroy object', async () => { | ||
const object = new TestObject({ test: 'test' }); | ||
await object.save(); | ||
await Parse.EventuallyQueue.destroy(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.equalTo('objectId', object.id); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 0); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
}); | ||
|
||
it('can queue multiple object', async () => { | ||
const obj1 = new TestObject({ foo: 'bar' }); | ||
const obj2 = new TestObject({ foo: 'baz' }); | ||
const obj3 = new TestObject({ foo: 'bag' }); | ||
await Parse.EventuallyQueue.save(obj1); | ||
await Parse.EventuallyQueue.save(obj2); | ||
await Parse.EventuallyQueue.save(obj3); | ||
|
||
let length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 3); | ||
|
||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.ascending('createdAt'); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 3); | ||
assert.strictEqual(results[0].get('foo'), 'bar'); | ||
assert.strictEqual(results[1].get('foo'), 'baz'); | ||
assert.strictEqual(results[2].get('foo'), 'bag'); | ||
|
||
length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
|
||
// TODO: Properly handle SingleInstance | ||
await Parse.EventuallyQueue.destroy(results[0]); | ||
await Parse.EventuallyQueue.destroy(results[1]); | ||
await Parse.EventuallyQueue.destroy(results[2]); | ||
|
||
length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 3); | ||
|
||
await Parse.EventuallyQueue.sendQueue(); | ||
const objects = await query.find(); | ||
assert.strictEqual(objects.length, 0); | ||
}); | ||
|
||
it('can queue destroy for object that does not exist', async () => { | ||
const object = new TestObject({ test: 'test' }); | ||
await object.save(); | ||
await object.destroy(); | ||
await Parse.EventuallyQueue.destroy(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
}); | ||
|
||
it('can queue destroy then save', async () => { | ||
const object = new TestObject({ hash: 'test' }); | ||
await Parse.EventuallyQueue.destroy(object); | ||
await Parse.EventuallyQueue.save(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.equalTo('hash', 'test'); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 1); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
}); | ||
|
||
it('can queue unsaved object with hash', async () => { | ||
const hash = 'secret'; | ||
const object = new TestObject({ test: 'test' }); | ||
object.set('hash', hash); | ||
await Parse.EventuallyQueue.save(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.equalTo('hash', hash); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 1); | ||
}); | ||
|
||
it('can queue saved object and unsaved with hash', async () => { | ||
const hash = 'ransom+salt'; | ||
const object = new TestObject({ test: 'test' }); | ||
object.set('hash', hash); | ||
await Parse.EventuallyQueue.save(object); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
let query = new Parse.Query(TestObject); | ||
query.equalTo('hash', hash); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 1); | ||
|
||
const unsaved = new TestObject({ hash, foo: 'bar' }); | ||
await Parse.EventuallyQueue.save(unsaved); | ||
await Parse.EventuallyQueue.sendQueue(); | ||
|
||
query = new Parse.Query(TestObject); | ||
query.equalTo('hash', hash); | ||
const hashes = await query.find(); | ||
assert.strictEqual(hashes.length, 1); | ||
assert.strictEqual(hashes[0].get('foo'), 'bar'); | ||
}); | ||
|
||
it('can queue same object but override undefined fields', async () => { | ||
const object = new Parse.Object('TestObject'); | ||
object.set('foo', 'bar'); | ||
object.set('test', '1234'); | ||
await Parse.EventuallyQueue.save(object); | ||
|
||
object.set('foo', undefined); | ||
await Parse.EventuallyQueue.save(object); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 1); | ||
|
||
const queue = await Parse.EventuallyQueue.getQueue(); | ||
assert.strictEqual(queue[0].object.foo, 'bar'); | ||
mtrezza marked this conversation as resolved.
Show resolved
Hide resolved
|
||
assert.strictEqual(queue[0].object.test, '1234'); | ||
}); | ||
|
||
it('can poll server', async () => { | ||
const object = new TestObject({ test: 'test' }); | ||
await object.save(); | ||
object.set('foo', 'bar'); | ||
await Parse.EventuallyQueue.save(object); | ||
Parse.EventuallyQueue.poll(); | ||
assert.ok(Parse.EventuallyQueue.isPolling()); | ||
|
||
await sleep(4000); | ||
const query = new Parse.Query(TestObject); | ||
const result = await query.get(object.id); | ||
assert.strictEqual(result.get('foo'), 'bar'); | ||
|
||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false); | ||
}); | ||
|
||
it('can clear queue', async () => { | ||
const object = new TestObject({ test: 'test' }); | ||
await object.save(); | ||
await Parse.EventuallyQueue.save(object); | ||
const q = await Parse.EventuallyQueue.getQueue(); | ||
assert.strictEqual(q.length, 1); | ||
|
||
await Parse.EventuallyQueue.clear(); | ||
const length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
}); | ||
|
||
it('can saveEventually', async done => { | ||
const parseServer = await reconfigureServer(); | ||
const object = new TestObject({ hash: 'saveSecret' }); | ||
await parseServer.handleShutdown(); | ||
parseServer.server.close(async () => { | ||
await object.saveEventually(); | ||
let length = await Parse.EventuallyQueue.length(); | ||
assert(Parse.EventuallyQueue.isPolling()); | ||
assert.strictEqual(length, 1); | ||
|
||
await reconfigureServer({}); | ||
await sleep(3000); // Wait for polling | ||
|
||
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false); | ||
length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.equalTo('hash', 'saveSecret'); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 1); | ||
done(); | ||
}); | ||
}); | ||
|
||
it('can destroyEventually', async done => { | ||
const parseServer = await reconfigureServer(); | ||
const object = new TestObject({ hash: 'deleteSecret' }); | ||
await object.save(); | ||
await parseServer.handleShutdown(); | ||
parseServer.server.close(async () => { | ||
await object.destroyEventually(); | ||
let length = await Parse.EventuallyQueue.length(); | ||
assert(Parse.EventuallyQueue.isPolling()); | ||
assert.strictEqual(length, 1); | ||
|
||
await reconfigureServer({}); | ||
await sleep(3000); // Wait for polling | ||
|
||
assert.strictEqual(Parse.EventuallyQueue.isPolling(), false); | ||
length = await Parse.EventuallyQueue.length(); | ||
assert.strictEqual(length, 0); | ||
|
||
const query = new Parse.Query(TestObject); | ||
query.equalTo('hash', 'deleteSecret'); | ||
const results = await query.find(); | ||
assert.strictEqual(results.length, 0); | ||
done(); | ||
}); | ||
}); | ||
}); |
This file contains hidden or 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 hidden or 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 |
---|---|---|
|
@@ -7,5 +7,5 @@ | |
"*Test.js" | ||
], | ||
"random": false, | ||
"timeout": 5000 | ||
"timeout": 10000 | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m using JSON.stringify to save the object in local storage. When I retrieve it’s no longer a class instance or same reference as the stored object. Is their a way to fix this? In a singleInstance environment like the browser objects with the same id have the same state and values. I can’t pass obj1 into destroy since it didn’t get an objectId from save.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understood this correctly, but
Object.create
takes the prototype to recreate the instance. Depending on what exactly goes missing,JSON.stringify
only stringifies enumerable, own properties, so sometime you may have to write a custom method to serialize/encode and then deserialize/decode an object.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stringify calls toJSON() internally. I ran into this issue with the LocalDatastore as well I think.