mirror of
https://github.com/discourse/discourse.git
synced 2025-04-01 12:55:57 +08:00
FIX: allows adapters to define a custom primaryKey (#9254)
This commit is contained in:
parent
92e81d2ae5
commit
2b78bd01ab
app/assets/javascripts/discourse
test/javascripts
@ -27,6 +27,8 @@ function rethrow(error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default EmberObject.extend({
|
export default EmberObject.extend({
|
||||||
|
primaryKey: "id",
|
||||||
|
|
||||||
storageKey(type, findArgs, options) {
|
storageKey(type, findArgs, options) {
|
||||||
if (options && options.cacheKey) {
|
if (options && options.cacheKey) {
|
||||||
return options.cacheKey;
|
return options.cacheKey;
|
||||||
@ -132,7 +134,7 @@ export default EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
destroyRecord(store, type, record) {
|
destroyRecord(store, type, record) {
|
||||||
return ajax(this.pathFor(store, type, record.get("id")), {
|
return ajax(this.pathFor(store, type, record.get(this.primaryKey)), {
|
||||||
type: "DELETE"
|
type: "DELETE"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -124,14 +124,14 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
if (adapter.cache) {
|
if (adapter.cache) {
|
||||||
const stale = adapter.findStale(this, type, findArgs, opts);
|
const stale = adapter.findStale(this, type, findArgs, opts);
|
||||||
hydrated = this._updateStale(stale, hydrated);
|
hydrated = this._updateStale(stale, hydrated, adapter.primaryKey);
|
||||||
adapter.cacheFind(this, type, findArgs, opts, hydrated);
|
adapter.cacheFind(this, type, findArgs, opts, hydrated);
|
||||||
}
|
}
|
||||||
return hydrated;
|
return hydrated;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateStale(stale, hydrated) {
|
_updateStale(stale, hydrated, primaryKey) {
|
||||||
if (!stale) {
|
if (!stale) {
|
||||||
return hydrated;
|
return hydrated;
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ export default EmberObject.extend({
|
|||||||
hydrated.set(
|
hydrated.set(
|
||||||
"content",
|
"content",
|
||||||
hydrated.get("content").map(item => {
|
hydrated.get("content").map(item => {
|
||||||
var staleItem = stale.content.findBy("id", item.get("id"));
|
var staleItem = stale.content.findBy(primaryKey, item.get(primaryKey));
|
||||||
if (staleItem) {
|
if (staleItem) {
|
||||||
staleItem.setProperties(item);
|
staleItem.setProperties(item);
|
||||||
} else {
|
} else {
|
||||||
@ -186,12 +186,11 @@ export default EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
update(type, id, attrs) {
|
update(type, id, attrs) {
|
||||||
return this.adapterFor(type).update(this, type, id, attrs, function(
|
const adapter = this.adapterFor(type);
|
||||||
result
|
return adapter.update(this, type, id, attrs, function(result) {
|
||||||
) {
|
if (result && result[type] && result[type][adapter.primaryKey]) {
|
||||||
if (result && result[type] && result[type].id) {
|
|
||||||
const oldRecord = findAndRemoveMap(type, id);
|
const oldRecord = findAndRemoveMap(type, id);
|
||||||
storeMap(type, result[type].id, oldRecord);
|
storeMap(type, result[type][adapter.primaryKey], oldRecord);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
@ -199,22 +198,25 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
createRecord(type, attrs) {
|
createRecord(type, attrs) {
|
||||||
attrs = attrs || {};
|
attrs = attrs || {};
|
||||||
return !!attrs.id ? this._hydrate(type, attrs) : this._build(type, attrs);
|
const adapter = this.adapterFor(type);
|
||||||
|
return !!attrs[adapter.primaryKey]
|
||||||
|
? this._hydrate(type, attrs)
|
||||||
|
: this._build(type, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyRecord(type, record) {
|
destroyRecord(type, record) {
|
||||||
|
const adapter = this.adapterFor(type);
|
||||||
|
|
||||||
// If the record is new, don't perform an Ajax call
|
// If the record is new, don't perform an Ajax call
|
||||||
if (record.get("isNew")) {
|
if (record.get("isNew")) {
|
||||||
removeMap(type, record.get("id"));
|
removeMap(type, record.get(adapter.primaryKey));
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.adapterFor(type)
|
return adapter.destroyRecord(this, type, record).then(function(result) {
|
||||||
.destroyRecord(this, type, record)
|
removeMap(type, record.get(adapter.primaryKey));
|
||||||
.then(function(result) {
|
return result;
|
||||||
removeMap(type, record.get("id"));
|
});
|
||||||
return result;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_resultSet(type, result, findArgs) {
|
_resultSet(type, result, findArgs) {
|
||||||
@ -252,9 +254,10 @@ export default EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_build(type, obj) {
|
_build(type, obj) {
|
||||||
|
const adapter = this.adapterFor(type);
|
||||||
obj.store = this;
|
obj.store = this;
|
||||||
obj.__type = type;
|
obj.__type = type;
|
||||||
obj.__state = obj.id ? "created" : "new";
|
obj.__state = obj[adapter.primaryKey] ? "created" : "new";
|
||||||
|
|
||||||
// TODO: Have injections be automatic
|
// TODO: Have injections be automatic
|
||||||
obj.topicTrackingState = this.register.lookup("topic-tracking-state:main");
|
obj.topicTrackingState = this.register.lookup("topic-tracking-state:main");
|
||||||
@ -264,7 +267,7 @@ export default EmberObject.extend({
|
|||||||
const klass = this.register.lookupFactory("model:" + type) || RestModel;
|
const klass = this.register.lookupFactory("model:" + type) || RestModel;
|
||||||
const model = klass.create(obj);
|
const model = klass.create(obj);
|
||||||
|
|
||||||
storeMap(type, obj.id, model);
|
storeMap(type, obj[adapter.primaryKey], model);
|
||||||
return model;
|
return model;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -288,6 +291,7 @@ export default EmberObject.extend({
|
|||||||
subType = root.meta.types[subType] || subType;
|
subType = root.meta.types[subType] || subType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const subTypeAdapter = this.adapterFor(subType);
|
||||||
const pluralType = this.pluralize(subType);
|
const pluralType = this.pluralize(subType);
|
||||||
const collection = root[this.pluralize(subType)];
|
const collection = root[this.pluralize(subType)];
|
||||||
if (collection) {
|
if (collection) {
|
||||||
@ -296,7 +300,7 @@ export default EmberObject.extend({
|
|||||||
if (!hashedCollection) {
|
if (!hashedCollection) {
|
||||||
hashedCollection = {};
|
hashedCollection = {};
|
||||||
collection.forEach(function(it) {
|
collection.forEach(function(it) {
|
||||||
hashedCollection[it.id] = it;
|
hashedCollection[it[subTypeAdapter.primaryKey]] = it;
|
||||||
});
|
});
|
||||||
root[hashedProp] = hashedCollection;
|
root[hashedProp] = hashedCollection;
|
||||||
}
|
}
|
||||||
@ -311,7 +315,12 @@ export default EmberObject.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_hydrateEmbedded(type, obj, root) {
|
_hydrateEmbedded(type, obj, root) {
|
||||||
|
const adapter = this.adapterFor(type);
|
||||||
Object.keys(obj).forEach(k => {
|
Object.keys(obj).forEach(k => {
|
||||||
|
if (k === adapter.primaryKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const m = /(.+)\_id(s?)$/.exec(k);
|
const m = /(.+)\_id(s?)$/.exec(k);
|
||||||
if (m) {
|
if (m) {
|
||||||
const subType = m[1];
|
const subType = m[1];
|
||||||
@ -340,9 +349,13 @@ export default EmberObject.extend({
|
|||||||
throw new Error("Can't hydrate " + type + " of `null`");
|
throw new Error("Can't hydrate " + type + " of `null`");
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = obj.id;
|
const adapter = this.adapterFor(type);
|
||||||
|
|
||||||
|
const id = obj[adapter.primaryKey];
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error("Can't hydrate " + type + " without an `id`");
|
throw new Error(
|
||||||
|
`Can't hydrate ${type} without primaryKey: \`${adapter.primaryKey}\``
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
root = root || obj;
|
root = root || obj;
|
||||||
@ -357,7 +370,7 @@ export default EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
delete obj.id;
|
delete obj[adapter.primaryKey];
|
||||||
let klass = this.register.lookupFactory("model:" + type);
|
let klass = this.register.lookupFactory("model:" + type);
|
||||||
|
|
||||||
if (klass && klass.class) {
|
if (klass && klass.class) {
|
||||||
@ -369,7 +382,7 @@ export default EmberObject.extend({
|
|||||||
}
|
}
|
||||||
|
|
||||||
existing.setProperties(klass.munge(obj));
|
existing.setProperties(klass.munge(obj));
|
||||||
obj.id = id;
|
obj[adapter.primaryKey] = id;
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,21 @@ import TopicListAdapter from "discourse/adapters/topic-list";
|
|||||||
import TopicTrackingState from "discourse/models/topic-tracking-state";
|
import TopicTrackingState from "discourse/models/topic-tracking-state";
|
||||||
import { buildResolver } from "discourse-common/resolver";
|
import { buildResolver } from "discourse-common/resolver";
|
||||||
|
|
||||||
|
const CatAdapter = RestAdapter.extend({
|
||||||
|
primaryKey: "cat_id"
|
||||||
|
});
|
||||||
|
|
||||||
export default function(customLookup = () => {}) {
|
export default function(customLookup = () => {}) {
|
||||||
const resolver = buildResolver("discourse").create();
|
const resolver = buildResolver("discourse").create();
|
||||||
|
|
||||||
return Store.create({
|
return Store.create({
|
||||||
register: {
|
register: {
|
||||||
lookup(type) {
|
lookup(type) {
|
||||||
|
if (type === "adapter:cat") {
|
||||||
|
this._catAdapter =
|
||||||
|
this._catAdapter || CatAdapter.create({ owner: this });
|
||||||
|
return this._catAdapter;
|
||||||
|
}
|
||||||
if (type === "adapter:rest") {
|
if (type === "adapter:rest") {
|
||||||
if (!this._restAdapter) {
|
if (!this._restAdapter) {
|
||||||
this._restAdapter = RestAdapter.create({ owner: this });
|
this._restAdapter = RestAdapter.create({ owner: this });
|
||||||
|
@ -26,9 +26,23 @@ const colors = [
|
|||||||
{ id: 3, name: "Yellow" }
|
{ id: 3, name: "Yellow" }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const cats = [
|
||||||
|
{
|
||||||
|
cat_id: 1,
|
||||||
|
name: "souna"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
export default function(helpers) {
|
export default function(helpers) {
|
||||||
const { response, success, parsePostData } = helpers;
|
const { response, success, parsePostData } = helpers;
|
||||||
|
|
||||||
|
this.get("/cats", function() {
|
||||||
|
return response({
|
||||||
|
__rest_serializer: "1",
|
||||||
|
cats
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
this.get("/fruits/:id", function(request) {
|
this.get("/fruits/:id", function(request) {
|
||||||
const fruit = fruits.find(f => f.id === parseInt(request.params.id, 10));
|
const fruit = fruits.find(f => f.id === parseInt(request.params.id, 10));
|
||||||
return response({ __rest_serializer: "1", fruit, farmers, colors });
|
return response({ __rest_serializer: "1", fruit, farmers, colors });
|
||||||
|
@ -182,3 +182,9 @@ QUnit.test("findAll embedded", async assert => {
|
|||||||
|
|
||||||
assert.equal(fruits.objectAt(2).get("farmer.name"), "Luke Skywalker");
|
assert.equal(fruits.objectAt(2).get("farmer.name"), "Luke Skywalker");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QUnit.test("custom primaryKey", async assert => {
|
||||||
|
const store = createStore();
|
||||||
|
const cats = await store.findAll("cat");
|
||||||
|
assert.equal(cats.objectAt(0).name, "souna");
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user