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"; import RestAdapter from "discourse/adapters/rest";
export default RestAdapter.extend({ export default class PendingPostAdapter extends RestAdapter {
jsonMode: true, jsonMode = true;
pathFor(_store, _type, params) { pathFor(_store, _type, params) {
return `/posts/${params.username}/pending.json`; return `/posts/${params.username}/pending.json`;
}, }
}); }

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
import { tracked } from "@glimmer/tracking";
import { getOwner, setOwner } from "@ember/application"; import { getOwner, setOwner } from "@ember/application";
import { warn } from "@ember/debug"; import { warn } from "@ember/debug";
import EmberObject from "@ember/object"; import EmberObject from "@ember/object";
@ -5,16 +6,38 @@ import { equal } from "@ember/object/computed";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import { getOwnerWithFallback } from "discourse-common/lib/get-owner"; import { getOwnerWithFallback } from "discourse-common/lib/get-owner";
const RestModel = EmberObject.extend({ export default class RestModel extends EmberObject {
isNew: equal("__state", "new"), // Overwrite and JSON will be passed through here before `create` and `update`
isCreated: equal("__state", "created"), static munge(json) {
isSaving: false, return json;
}
beforeCreate() {}, static create(args) {
afterCreate() {}, args = args || {};
beforeUpdate() {}, args.__munge = this.munge;
afterUpdate() {}, 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) { update(props) {
if (this.isSaving) { if (this.isSaving) {
@ -44,7 +67,7 @@ const RestModel = EmberObject.extend({
return res; return res;
}) })
.finally(() => this.set("isSaving", false)); .finally(() => this.set("isSaving", false));
}, }
_saveNew(props) { _saveNew(props) {
if (this.isSaving) { if (this.isSaving) {
@ -77,45 +100,19 @@ const RestModel = EmberObject.extend({
return res; return res;
}) })
.finally(() => this.set("isSaving", false)); .finally(() => this.set("isSaving", false));
}, }
createProperties() { createProperties() {
throw new Error( throw new Error(
"You must overwrite `createProperties()` before saving a record" "You must overwrite `createProperties()` before saving a record"
); );
}, }
save(props) { save(props) {
return this.isNew ? this._saveNew(props) : this.update(props); return this.isNew ? this._saveNew(props) : this.update(props);
}, }
destroyRecord() { destroyRecord() {
return this.store.destroyRecord(this.__type, this); 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 deprecated from "discourse-common/lib/deprecated";
import { buildResolver } from "discourse-common/resolver"; import { buildResolver } from "discourse-common/resolver";
const CatAdapter = RestAdapter.extend({ class CatAdapter extends RestAdapter {
primaryKey: "cat_id", primaryKey = "cat_id";
}); }
const CachedCatAdapter = RestAdapter.extend({ class CachedCatAdapter extends RestAdapter {
primaryKey: "cat_id", primaryKey = "cat_id";
cache: true, cache = true;
apiNameFor() { apiNameFor() {
return "cat"; return "cat";
}, }
}); }
const CachedCat = RestModel.extend({ class CachedCat extends RestModel {
init(...args) { init(...args) {
// Simulate an implicit injection // Simulate an implicit injection
Object.defineProperty(this, "injectedProperty", { Object.defineProperty(this, "injectedProperty", {
@ -29,9 +29,9 @@ const CachedCat = RestModel.extend({
enumerable: true, enumerable: true,
value: "hello world", value: "hello world",
}); });
this._super(...args); return super.init(...args);
}, }
}); }
export default function (customLookup = () => {}) { export default function (customLookup = () => {}) {
deprecated( deprecated(