BUG FIX: A schema is required when Realm is opened in a query-based sync situation (#1985)
This commit is contained in:
parent
05aef95bbd
commit
1b1b51ded2
|
@ -14,6 +14,7 @@ X.Y.Z Release notes (YYYY-MM-DD)
|
||||||
* [Sync] Added support for `Session.addConnectionNotification()` and `Session.removeConnectionNotification`.
|
* [Sync] Added support for `Session.addConnectionNotification()` and `Session.removeConnectionNotification`.
|
||||||
* [Sync] Added `Session.connectionState`.
|
* [Sync] Added `Session.connectionState`.
|
||||||
* [Sync] Added `Session.isConnected()`.
|
* [Sync] Added `Session.isConnected()`.
|
||||||
|
* [Sync] Added a check to prevent the case where query-based sync is opened without a schema. It is not possible to deduce the schema, and subscribing to a query-based sync will lead to an error if no schema is defined (#1976).
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
* React Native for Android now supports the Android Gradle Plugin 3.0 (#1742).
|
* React Native for Android now supports the Android Gradle Plugin 3.0 (#1742).
|
||||||
|
|
|
@ -96,6 +96,8 @@ class Realm {
|
||||||
* In this case, `config.schema` is _optional_ or not have changed, unless
|
* In this case, `config.schema` is _optional_ or not have changed, unless
|
||||||
* `config.schemaVersion` is incremented, in which case the Realm will be automatically
|
* `config.schemaVersion` is incremented, in which case the Realm will be automatically
|
||||||
* migrated to use the new schema.
|
* migrated to use the new schema.
|
||||||
|
* In the case of query-based sync, `config.schema` is required. An exception will be
|
||||||
|
* thrown if `config.schema` is not defined.
|
||||||
* @param {Realm~Configuration} [config] - **Required** when first creating the Realm.
|
* @param {Realm~Configuration} [config] - **Required** when first creating the Realm.
|
||||||
* @throws {Error} If anything in the provided `config` is invalid.
|
* @throws {Error} If anything in the provided `config` is invalid.
|
||||||
* @throws {IncompatibleSyncedRealmError} when an incompatible synced Realm is opened
|
* @throws {IncompatibleSyncedRealmError} when an incompatible synced Realm is opened
|
||||||
|
@ -105,8 +107,11 @@ class Realm {
|
||||||
/**
|
/**
|
||||||
* Open a Realm asynchronously with a promise. If the Realm is synced, it will be fully
|
* Open a Realm asynchronously with a promise. If the Realm is synced, it will be fully
|
||||||
* synchronized before it is available.
|
* synchronized before it is available.
|
||||||
|
* In the case of query-based sync, `config.schema` is required. An exception will be
|
||||||
|
* thrown if `config.schema` is not defined.
|
||||||
* @param {Realm~Configuration} config - if no config is defined, it will open the default realm
|
* @param {Realm~Configuration} config - if no config is defined, it will open the default realm
|
||||||
* @returns {ProgressPromise} - a promise that will be resolved with the Realm instance when it's available.
|
* @returns {ProgressPromise} - a promise that will be resolved with the Realm instance when it's available.
|
||||||
|
* @throws {Error} If anything in the provided `config` is invalid.
|
||||||
*/
|
*/
|
||||||
static open(config) {}
|
static open(config) {}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,9 @@ module.exports = function(realmConstructor) {
|
||||||
// result in sync rejecting the writes. `_waitForDownload` ensures that the session is kept
|
// result in sync rejecting the writes. `_waitForDownload` ensures that the session is kept
|
||||||
// alive until our callback has returned, which prevents it from being torn down and recreated
|
// alive until our callback has returned, which prevents it from being torn down and recreated
|
||||||
// when we close the schemaless Realm and open it with the correct schema.
|
// when we close the schemaless Realm and open it with the correct schema.
|
||||||
|
if (!config.sync.fullSynchronization && config.schema === undefined) {
|
||||||
|
throw new Error('Query-based sync requires a schema.');
|
||||||
|
}
|
||||||
let syncSession;
|
let syncSession;
|
||||||
let promise = new Promise((resolve, reject) => {
|
let promise = new Promise((resolve, reject) => {
|
||||||
let realm = new realmConstructor(waitForDownloadConfig(config));
|
let realm = new realmConstructor(waitForDownloadConfig(config));
|
||||||
|
|
|
@ -609,6 +609,13 @@ SharedRealm RealmClass<T>::create_shared_realm(ContextType ctx, realm::Realm::Co
|
||||||
handleRealmFileException(ctx, config, ex);
|
handleRealmFileException(ctx, config, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if REALM_ENABLE_SYNC
|
||||||
|
auto schema = realm->schema();
|
||||||
|
if (realm->is_partial() && schema.empty() && config.cache) {
|
||||||
|
throw std::invalid_argument("Query-based sync requires a schema.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GlobalContextType global_context = Context<T>::get_global_context(ctx);
|
GlobalContextType global_context = Context<T>::get_global_context(ctx);
|
||||||
if (!realm->m_binding_context) {
|
if (!realm->m_binding_context) {
|
||||||
realm->m_binding_context.reset(new RealmDelegate<T>(realm, global_context));
|
realm->m_binding_context.reset(new RealmDelegate<T>(realm, global_context));
|
||||||
|
|
|
@ -49,7 +49,7 @@ module.exports = {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password').then(user => {
|
return Realm.Sync.User.register('http://localhost:9080', uuid(), 'password').then(user => {
|
||||||
const config = user.createConfiguration({ sync: { url: 'realm://localhost:9080/~/myrealm' },
|
const config = user.createConfiguration({ sync: { url: 'realm://localhost:9080/~/myrealm', fullSynchronization: true },
|
||||||
schema: [{ name: 'IntegerPrimaryKey', properties: { int: 'int?' }, primaryKey: 'int' },
|
schema: [{ name: 'IntegerPrimaryKey', properties: { int: 'int?' }, primaryKey: 'int' },
|
||||||
{ name: 'StringPrimaryKey', properties: { string: 'string?' }, primaryKey: 'string' },
|
{ name: 'StringPrimaryKey', properties: { string: 'string?' }, primaryKey: 'string' },
|
||||||
{ name: 'NoPrimaryKey', properties: { string: 'string' }},
|
{ name: 'NoPrimaryKey', properties: { string: 'string' }},
|
||||||
|
|
|
@ -174,16 +174,16 @@ module.exports = {
|
||||||
let config = (user, url) => {
|
let config = (user, url) => {
|
||||||
return {
|
return {
|
||||||
schema: [
|
schema: [
|
||||||
Realm.Permissions.Permission,
|
|
||||||
Realm.Permissions.User,
|
|
||||||
Realm.Permissions.Role,
|
|
||||||
{
|
{
|
||||||
name: 'Object',
|
name: 'Object',
|
||||||
properties: {
|
properties: {
|
||||||
value: 'int',
|
value: 'int',
|
||||||
permissions: '__Permission[]'
|
permissions: '__Permission[]'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
Realm.Permissions.Permission,
|
||||||
|
Realm.Permissions.User,
|
||||||
|
Realm.Permissions.Role,
|
||||||
],
|
],
|
||||||
sync: {user: user, url: url, fullSynchronization: false }
|
sync: {user: user, url: url, fullSynchronization: false }
|
||||||
};
|
};
|
||||||
|
|
|
@ -478,7 +478,8 @@ module.exports = {
|
||||||
sync: {
|
sync: {
|
||||||
user,
|
user,
|
||||||
error : err => console.log(err),
|
error : err => console.log(err),
|
||||||
url: 'realm://localhost:9080/~/sync-v1'
|
url: 'realm://localhost:9080/~/sync-v1',
|
||||||
|
fullSynchronization: true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return Realm.open(config)
|
return Realm.open(config)
|
||||||
|
@ -520,7 +521,8 @@ module.exports = {
|
||||||
sync: {
|
sync: {
|
||||||
user,
|
user,
|
||||||
error : err => console.log(err),
|
error : err => console.log(err),
|
||||||
url: 'realm://localhost:9080/~/sync-v1'
|
url: 'realm://localhost:9080/~/sync-v1',
|
||||||
|
fullSynchronization: true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -776,7 +778,8 @@ module.exports = {
|
||||||
url: `realm://localhost:9080/default/__partial/`,
|
url: `realm://localhost:9080/default/__partial/`,
|
||||||
_disableQueryBasedSyncUrlChecks: true,
|
_disableQueryBasedSyncUrlChecks: true,
|
||||||
fullSynchronization: false,
|
fullSynchronization: false,
|
||||||
}
|
},
|
||||||
|
schema: [ { name: 'Dog', properties: { name: 'string' } } ]
|
||||||
};
|
};
|
||||||
const realm = new Realm(config1);
|
const realm = new Realm(config1);
|
||||||
TestCase.assertFalse(realm.isClosed);
|
TestCase.assertFalse(realm.isClosed);
|
||||||
|
@ -816,6 +819,12 @@ module.exports = {
|
||||||
TestCase.assertThrows(() => Realm.automaticSyncConfiguration('foo', 'bar')); // too many arguments
|
TestCase.assertThrows(() => Realm.automaticSyncConfiguration('foo', 'bar')); // too many arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function schemalessNotAllowed() {
|
||||||
|
let config = Realm.Sync.User.current.createConfiguration();
|
||||||
|
config.schema = undefined; // no schema in the configuration
|
||||||
|
Realm.deleteFile(config);
|
||||||
|
TestCase.assertThrows(() => { let realm = new Realm(config); } );
|
||||||
|
}
|
||||||
|
|
||||||
return runOutOfProcess(__dirname + '/partial-sync-api-helper.js', username, REALM_MODULE_PATH)
|
return runOutOfProcess(__dirname + '/partial-sync-api-helper.js', username, REALM_MODULE_PATH)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -826,6 +835,7 @@ module.exports = {
|
||||||
__partialIsNotAllowed();
|
__partialIsNotAllowed();
|
||||||
shouldFail();
|
shouldFail();
|
||||||
defaultRealmInvalidArguments();
|
defaultRealmInvalidArguments();
|
||||||
|
schemalessNotAllowed();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let config = Realm.Sync.User.current.createConfiguration();
|
let config = Realm.Sync.User.current.createConfiguration();
|
||||||
|
|
Loading…
Reference in New Issue