DEV: Update RestModel and RestAdapter to native class syntax (#25544)

This commit also updates a handful of simple adapters which overrode the jsonMode or primaryKey options. These updates are necessary because class fields cannot be overwritten via `EmberObject`'s `.extend()` syntax. These options do not appear to be widely used by themes/plugins.
This commit is contained in:
David Taylor 2024-02-06 12:22:08 +00:00 committed by GitHub
parent c37c00e9d8
commit 7fcd7d53f9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 82 additions and 86 deletions

View File

@ -1,9 +1,9 @@
import RestAdapter from "discourse/adapters/rest";
export default RestAdapter.extend({
jsonMode: true,
export default class PendingPostAdapter extends RestAdapter {
jsonMode = true;
pathFor(_store, _type, params) {
return `/posts/${params.username}/pending.json`;
},
});
}
}

View File

@ -1,9 +1,9 @@
import RestAdapter from "discourse/adapters/rest";
export default RestAdapter.extend({
jsonMode: true,
export default class PublishedPageAdapter extends RestAdapter {
jsonMode = true;
pathFor(store, type, id) {
return `/pub/by-topic/${id}`;
},
});
}
}

View File

@ -26,8 +26,9 @@ function rethrow(error) {
throw error;
}
export default EmberObject.extend({
primaryKey: "id",
export default class RestAdapter extends EmberObject {
primaryKey = "id";
jsonMode = false;
storageKey(type, findArgs, options) {
if (options && options.cacheKey) {
@ -35,14 +36,14 @@ export default EmberObject.extend({
}
const hashedArgs = Math.abs(hashString(JSON.stringify(findArgs)));
return `${type}_${hashedArgs}`;
},
}
basePath(store, type) {
if (ADMIN_MODELS.includes(type.replace("_", "-"))) {
return "/admin/";
}
return "/";
},
}
appendQueryParams(path, findArgs, extension) {
if (findArgs) {
@ -66,39 +67,37 @@ export default EmberObject.extend({
}
}
return path;
},
}
pathFor(store, type, findArgs) {
let path =
this.basePath(store, type, findArgs) +
underscore(store.pluralize(this.apiNameFor(type)));
return this.appendQueryParams(path, findArgs);
},
}
apiNameFor(type) {
return type;
},
}
findAll(store, type, findArgs) {
return ajax(this.pathFor(store, type, findArgs)).catch(rethrow);
},
}
find(store, type, findArgs) {
return ajax(this.pathFor(store, type, findArgs)).catch(rethrow);
},
}
findStale(store, type, findArgs, options) {
if (this.cached) {
return this.cached[this.storageKey(type, findArgs, options)];
}
},
}
cacheFind(store, type, findArgs, opts, hydrated) {
this.cached = this.cached || {};
this.cached[this.storageKey(type, findArgs, opts)] = hydrated;
},
jsonMode: false,
}
getPayload(method, data) {
let payload = { method, data };
@ -109,7 +108,7 @@ export default EmberObject.extend({
}
return payload;
},
}
update(store, type, id, attrs) {
const data = {};
@ -122,7 +121,7 @@ export default EmberObject.extend({
).then(function (json) {
return new Result(json[typeField], json);
});
},
}
createRecord(store, type, attrs) {
const data = {};
@ -133,11 +132,11 @@ export default EmberObject.extend({
return new Result(json[typeField], json);
}
);
},
}
destroyRecord(store, type, record) {
return ajax(this.pathFor(store, type, record.get(this.primaryKey)), {
type: "DELETE",
});
},
});
}
}

View File

@ -1,9 +1,9 @@
import RestAdapter from "discourse/adapters/rest";
export default RestAdapter.extend({
jsonMode: true,
export default class ReviewableExplanationAdapter extends RestAdapter {
jsonMode = true;
pathFor(store, type, id) {
return `/review/${id}/explain.json`;
},
});
}
}

View File

@ -1,9 +1,9 @@
import RestAdapter from "discourse/adapters/rest";
export default RestAdapter.extend({
jsonMode: true,
export default class ReviewableAdapter extends RestAdapter {
jsonMode = true;
pathFor(store, type, findArgs) {
return this.appendQueryParams("/review", findArgs);
},
});
}
}

View File

@ -1,3 +1,4 @@
import { tracked } from "@glimmer/tracking";
import { getOwner, setOwner } from "@ember/application";
import { warn } from "@ember/debug";
import EmberObject from "@ember/object";
@ -5,16 +6,38 @@ import { equal } from "@ember/object/computed";
import { Promise } from "rsvp";
import { getOwnerWithFallback } from "discourse-common/lib/get-owner";
const RestModel = EmberObject.extend({
isNew: equal("__state", "new"),
isCreated: equal("__state", "created"),
isSaving: false,
export default class RestModel extends EmberObject {
// Overwrite and JSON will be passed through here before `create` and `update`
static munge(json) {
return json;
}
beforeCreate() {},
afterCreate() {},
static create(args) {
args = args || {};
beforeUpdate() {},
afterUpdate() {},
args.__munge = this.munge;
const createArgs = this.munge(args, args.store);
// Some Discourse code calls `model.create()` directly without going through the
// store. In that case the owner is not set, and injections will fail. This workaround ensures
// the owner is always present. Eventually we should use the store for everything to fix this.
const receivedOwner = getOwner(createArgs);
if (!receivedOwner || receivedOwner.isDestroyed) {
setOwner(createArgs, getOwnerWithFallback());
}
return super.create(createArgs);
}
@tracked isSaving = false;
@equal("__state", "new") isNew;
@equal("__state", "created") isCreated;
beforeCreate() {}
afterCreate() {}
beforeUpdate() {}
afterUpdate() {}
update(props) {
if (this.isSaving) {
@ -44,7 +67,7 @@ const RestModel = EmberObject.extend({
return res;
})
.finally(() => this.set("isSaving", false));
},
}
_saveNew(props) {
if (this.isSaving) {
@ -77,45 +100,19 @@ const RestModel = EmberObject.extend({
return res;
})
.finally(() => this.set("isSaving", false));
},
}
createProperties() {
throw new Error(
"You must overwrite `createProperties()` before saving a record"
);
},
}
save(props) {
return this.isNew ? this._saveNew(props) : this.update(props);
},
}
destroyRecord() {
return this.store.destroyRecord(this.__type, this);
},
});
RestModel.reopenClass({
// Overwrite and JSON will be passed through here before `create` and `update`
munge(json) {
return json;
},
create(args) {
args = args || {};
args.__munge = this.munge;
const createArgs = this.munge(args, args.store);
// Some Discourse code calls `model.create()` directly without going through the
// store. In that case the owner is not set, and injections will fail. This workaround ensures
// the owner is always present. Eventually we should use the store for everything to fix this.
const receivedOwner = getOwner(createArgs);
if (!receivedOwner || receivedOwner.isDestroyed) {
setOwner(createArgs, getOwnerWithFallback());
}
return this._super(createArgs);
},
});
export default RestModel;
}
}

View File

@ -9,19 +9,19 @@ import { currentSettings } from "discourse/tests/helpers/site-settings";
import deprecated from "discourse-common/lib/deprecated";
import { buildResolver } from "discourse-common/resolver";
const CatAdapter = RestAdapter.extend({
primaryKey: "cat_id",
});
class CatAdapter extends RestAdapter {
primaryKey = "cat_id";
}
const CachedCatAdapter = RestAdapter.extend({
primaryKey: "cat_id",
cache: true,
class CachedCatAdapter extends RestAdapter {
primaryKey = "cat_id";
cache = true;
apiNameFor() {
return "cat";
},
});
}
}
const CachedCat = RestModel.extend({
class CachedCat extends RestModel {
init(...args) {
// Simulate an implicit injection
Object.defineProperty(this, "injectedProperty", {
@ -29,9 +29,9 @@ const CachedCat = RestModel.extend({
enumerable: true,
value: "hello world",
});
this._super(...args);
},
});
return super.init(...args);
}
}
export default function (customLookup = () => {}) {
deprecated(