Commit 3d68e978 authored by Aurel's avatar Aurel

merge mapping & wip from romain

parents 3d191693 9e9d22cb
......@@ -8455,11 +8455,10 @@ return new Parser;
function ReplicateStorage(spec) {
this._query_options = spec.query || {};
if (spec.signature_select_metadata !== undefined) {
this._query_options.select_list = [spec.signature_select_metadata];
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_select_metadata = spec.signature_select_metadata;
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
......@@ -9176,12 +9175,12 @@ return new Parser;
options) {
return new RSVP.Queue()
.push(function () {
if (options.signature_select_metadata !== undefined) {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_select_metadata]];
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
......@@ -9388,8 +9387,8 @@ return new Parser;
}
local_hash = null;
if (options.signature_select_metadata !== undefined) {
local_hash = local_dict[key][options.signature_select_metadata];
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
......@@ -9541,7 +9540,7 @@ return new Parser;
check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
})
.push(function () {
return signature_allDocs;
......@@ -9569,7 +9568,7 @@ return new Parser;
check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
});
}
})
......@@ -12653,14 +12652,18 @@ return new Parser;
});
};
function handleGet(request, resolve, reject) {
function handleGet(store, id, resolve, reject) {
var request = store.get(id);
request.onerror = reject;
request.onsuccess = function () {
if (request.result) {
resolve(request.result);
} else {
// XXX How to get ID
reject(new jIO.util.jIOError("Cannot find document", 404));
reject(new jIO.util.jIOError(
"IndexedDB: cannot find object '" + id + "' in the '" +
store.name + "' store",
404
));
}
};
}
......@@ -12671,7 +12674,8 @@ return new Parser;
return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata"], "readonly");
handleGet(
transaction.objectStore("metadata").get(id),
transaction.objectStore("metadata"),
id,
resolve,
reject
);
......@@ -12704,7 +12708,8 @@ return new Parser;
);
}
handleGet(
transaction.objectStore("metadata").get(id),
transaction.objectStore("metadata"),
id,
getAttachments,
reject
);
......@@ -12832,7 +12837,8 @@ return new Parser;
result_list.push(result);
}
i += 1;
handleGet(store.get(buildKeyPath([id, name, i])),
handleGet(store,
buildKeyPath([id, name, i]),
(i <= end_index) ? getPart(i) : resolver,
reject
);
......@@ -12841,8 +12847,8 @@ return new Parser;
getPart(start_index - 1)();
}
// XXX Should raise if key is not good
handleGet(transaction.objectStore("attachment")
.get(buildKeyPath([id, name])),
handleGet(transaction.objectStore("attachment"),
buildKeyPath([id, name]),
getBlob,
reject
);
......@@ -13686,6 +13692,9 @@ return new Parser;
}
}
}
if (storage._map_id[0] === "equalSubProperty") {
storage._mapping_dict[storage._map_id[1]] = ["keep"];
}
if (storage._query.query !== undefined) {
query_list.push(QueryFactory.create(storage._query.query));
}
......@@ -13853,12 +13862,25 @@ return new Parser;
this,
doc
),
id = doc[this._property_for_sub_id];
id = doc[this._property_for_sub_id],
storage = this;
if (this._property_for_sub_id && id !== undefined) {
return this._sub_storage.put(id, sub_doc);
}
if (!this._id_mapped || doc[this._id_mapped] !== undefined) {
return this._sub_storage.post(sub_doc);
return getSubStorageId(storage, id, doc)
.push(function (sub_id) {
return storage._sub_storage.put(sub_id, sub_doc);
})
.push(function () {
return doc[storage._id_mapped];
})
.push(undefined, function (error) {
if (error instanceof jIO.util.jIOError) {
return storage._sub_storage.post(sub_doc);
}
throw error;
});
}
throw new jIO.util.jIOError(
"post is not supported with id mapped",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2597,11 +2597,10 @@ return new Parser;
function ReplicateStorage(spec) {
this._query_options = spec.query || {};
if (spec.signature_select_metadata !== undefined) {
this._query_options.select_list = [spec.signature_select_metadata];
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_select_metadata = spec.signature_select_metadata;
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
......@@ -3318,12 +3317,12 @@ return new Parser;
options) {
return new RSVP.Queue()
.push(function () {
if (options.signature_select_metadata !== undefined) {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_select_metadata]];
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
......@@ -3530,8 +3529,8 @@ return new Parser;
}
local_hash = null;
if (options.signature_select_metadata !== undefined) {
local_hash = local_dict[key][options.signature_select_metadata];
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
......@@ -3683,7 +3682,7 @@ return new Parser;
check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
})
.push(function () {
return signature_allDocs;
......@@ -3711,7 +3710,7 @@ return new Parser;
check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
});
}
})
......@@ -5255,6 +5254,9 @@ return new Parser;
}
}
}
if (storage._map_id[0] === "equalSubProperty") {
storage._mapping_dict[storage._map_id[1]] = ["keep"];
}
if (storage._query.query !== undefined) {
query_list.push(QueryFactory.create(storage._query.query));
}
......@@ -5422,12 +5424,25 @@ return new Parser;
this,
doc
),
id = doc[this._property_for_sub_id];
id = doc[this._property_for_sub_id],
storage = this;
if (this._property_for_sub_id && id !== undefined) {
return this._sub_storage.put(id, sub_doc);
}
if (!this._id_mapped || doc[this._id_mapped] !== undefined) {
return this._sub_storage.post(sub_doc);
return getSubStorageId(storage, id, doc)
.push(function (sub_id) {
return storage._sub_storage.put(sub_id, sub_doc);
})
.push(function () {
return doc[storage._id_mapped];
})
.push(undefined, function (error) {
if (error instanceof jIO.util.jIOError) {
return storage._sub_storage.post(sub_doc);
}
throw error;
});
}
throw new jIO.util.jIOError(
"post is not supported with id mapped",
......
{
"name": "jio",
"version": "v3.17.0",
"version": "v3.18.0",
"license": "LGPLv3",
"author": "Nexedi SA",
"contributors": [
......
......@@ -209,14 +209,18 @@
});
};
function handleGet(request, resolve, reject) {
function handleGet(store, id, resolve, reject) {
var request = store.get(id);
request.onerror = reject;
request.onsuccess = function () {
if (request.result) {
resolve(request.result);
} else {
// XXX How to get ID
reject(new jIO.util.jIOError("Cannot find document", 404));
reject(new jIO.util.jIOError(
"IndexedDB: cannot find object '" + id + "' in the '" +
store.name + "' store",
404
));
}
};
}
......@@ -227,7 +231,8 @@
return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata"], "readonly");
handleGet(
transaction.objectStore("metadata").get(id),
transaction.objectStore("metadata"),
id,
resolve,
reject
);
......@@ -260,7 +265,8 @@
);
}
handleGet(
transaction.objectStore("metadata").get(id),
transaction.objectStore("metadata"),
id,
getAttachments,
reject
);
......@@ -388,7 +394,8 @@
result_list.push(result);
}
i += 1;
handleGet(store.get(buildKeyPath([id, name, i])),
handleGet(store,
buildKeyPath([id, name, i]),
(i <= end_index) ? getPart(i) : resolver,
reject
);
......@@ -397,8 +404,8 @@
getPart(start_index - 1)();
}
// XXX Should raise if key is not good
handleGet(transaction.objectStore("attachment")
.get(buildKeyPath([id, name])),
handleGet(transaction.objectStore("attachment"),
buildKeyPath([id, name]),
getBlob,
reject
);
......
......@@ -55,11 +55,10 @@
function ReplicateStorage(spec) {
this._query_options = spec.query || {};
if (spec.signature_select_metadata !== undefined) {
this._query_options.select_list = [spec.signature_select_metadata];
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_select_metadata = spec.signature_select_metadata;
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
......@@ -776,12 +775,12 @@
options) {
return new RSVP.Queue()
.push(function () {
if (options.signature_select_metadata !== undefined) {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_select_metadata]];
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
......@@ -988,8 +987,8 @@
}
local_hash = null;
if (options.signature_select_metadata !== undefined) {
local_hash = local_dict[key][options.signature_select_metadata];
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
......@@ -1141,7 +1140,7 @@
check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
})
.push(function () {
return signature_allDocs;
......@@ -1169,7 +1168,7 @@
check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount,
signature_select_metadata: context._signature_select_metadata
signature_hash_key: context._signature_hash_key
});
}
})
......
......@@ -493,7 +493,10 @@
})
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Cannot find document");
equal(
error.message,
"IndexedDB: cannot find object 'inexistent' in the 'metadata' store"
);
equal(error.status_code, 404);
})
.fail(function (error) {
......@@ -679,7 +682,10 @@
})
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Cannot find document");
equal(
error.message,
"IndexedDB: cannot find object 'inexistent' in the 'metadata' store"
);
equal(error.status_code, 404);
})
.fail(function (error) {
......
......@@ -73,8 +73,7 @@
equal(jio.__storage._check_remote_attachment_creation, false);
equal(jio.__storage._check_remote_attachment_deletion, false);
equal(jio.__storage._check_remote_attachment_modification, false);
equal(jio.__storage._signature_select_metadata, undefined);
equal(jio.__storage._signature_hash_key, undefined);
equal(jio.__storage._custom_signature_sub_storage, false);
equal(jio.__storage._signature_hash,
"_replicate_7209dfbcaff00f6637f939fdd71fa896793ed385");
......@@ -129,7 +128,7 @@
check_remote_attachment_creation: true,
check_remote_attachment_deletion: true,
check_remote_attachment_modification: true,
signature_select_metadata: 'bar'
signature_hash_key: 'bar'
});
deepEqual(
......@@ -153,8 +152,7 @@
equal(jio.__storage._check_remote_attachment_creation, true);
equal(jio.__storage._check_remote_attachment_deletion, true);
equal(jio.__storage._check_remote_attachment_modification, true);
equal(jio.__storage._signature_select_metadata, 'bar');
equal(jio.__storage._signature_hash_key, 'bar');
equal(jio.__storage._custom_signature_sub_storage, false);
ok(jio.__storage._signature_sub_storage instanceof jio.constructor);
equal(jio.__storage._signature_sub_storage.__type, "query");
......@@ -734,4 +732,4 @@
});
});
}(jIO, QUnit, Blob));
\ No newline at end of file
}(jIO, QUnit, Blob));
......@@ -81,7 +81,7 @@
// Uses memory substorage, so that it is flushed after each run
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -164,7 +164,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: true,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -305,7 +305,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: true,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -472,6 +472,57 @@
});
});
test("local and remote document creations with same 'etag'", function () {
stop();
expect(3);
var context = this;
RSVP.all([
context.jio.put("conflict", {title: "foo", foo_etag: 'foo etag'}),
context.jio.__storage._remote_sub_storage.put("conflict",
{title: "foo",
foo_etag: 'bar etag'})
])
.then(function () {
return context.jio.repair();
})
.then(function () {
return context.jio.__storage._signature_sub_storage.get("conflict");
})
.then(function (result) {
deepEqual(result, {
hash: "foo dynetag"
});
})
.then(function () {
return context.jio.get("conflict");
})
.then(function (result) {
deepEqual(result, {
title: "foo",
foo_etag: 'foo etag'
});
})
.then(function () {
return context.jio.__storage._remote_sub_storage.get("conflict");
})
.then(function (result) {
deepEqual(result, {
title: "foo",
foo_etag: 'bar etag'
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("local and remote document creations: keep local", function () {
stop();
expect(3);
......@@ -480,7 +531,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -555,7 +606,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -629,7 +680,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -706,7 +757,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -783,7 +834,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -858,7 +909,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -932,7 +983,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -1010,7 +1061,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -1085,7 +1136,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -1160,7 +1211,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "storagealldocsdynamicselect",
sub_storage: {
......@@ -1350,7 +1401,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -1424,7 +1475,7 @@
this.jio = jIO.createJIO({
type: "replicate",
check_local_modification: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -1552,7 +1603,7 @@
this.jio = jIO.createJIO({
type: "replicate",
check_remote_modification: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -1685,7 +1736,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -1776,7 +1827,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -1867,7 +1918,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2047,7 +2098,7 @@
this.jio = jIO.createJIO({
type: "replicate",
check_local_deletion: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2236,7 +2287,7 @@
this.jio = jIO.createJIO({
type: "replicate",
check_remote_deletion: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2492,7 +2543,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2589,7 +2640,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 2,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2680,7 +2731,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 3,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2817,7 +2868,7 @@
this.jio = jIO.createJIO({
type: "replicate",
use_remote_post: true,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -2944,7 +2995,7 @@
type: "replicate",
use_remote_post: true,
check_local_modification: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3069,7 +3120,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 1,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3157,7 +3208,7 @@
type: "replicate",
conflict_handling: 1,
use_remote_post: true,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3282,7 +3333,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 2,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3375,7 +3426,7 @@
type: "replicate",
conflict_handling: 2,
check_local_modification: false,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3467,7 +3518,7 @@
this.jio = jIO.createJIO({
type: "replicate",
conflict_handling: 3,
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3552,7 +3603,7 @@
// in the same local sub storage
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "uuid",
sub_storage: {
......@@ -3652,7 +3703,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "replicatefaststorage200defaultquery"
},
......@@ -3708,7 +3759,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "replicatefaststorage200customquery"
},
......@@ -3757,7 +3808,7 @@
this.jio = jIO.createJIO({
type: "replicate",
signature_select_metadata: 'foo_etag',
signature_hash_key: 'foo_etag',
local_sub_storage: {
type: "query",
sub_storage: {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment