Fixed recommendation order (#18060)
fixes https://github.com/TryGhost/Product/issues/3851 - Order was not applied via the CRUD plugin - Removed usage of CRUD findAll, and swapped to Bookshelf fetchAll instead, to decrease dependencies of invisible Bookshelf plugins logic - Reverted page and limit options possibility via findAll method
This commit is contained in:
parent
acae53d9ed
commit
f566729ed6
@ -1,3 +1,5 @@
|
||||
import {Knex} from 'knex';
|
||||
|
||||
type Entity<T> = {
|
||||
id: T;
|
||||
deleted: boolean;
|
||||
@ -11,9 +13,12 @@ type Order<T> = {
|
||||
export type ModelClass<T> = {
|
||||
destroy: (data: {id: T}) => Promise<void>;
|
||||
findOne: (data: {id: T}, options?: {require?: boolean}) => Promise<ModelInstance<T> | null>;
|
||||
findAll: (options: {filter?: string; order?: string, page?: number, limit?: number | 'all'}) => Promise<ModelInstance<T>[]>;
|
||||
add: (data: object) => Promise<ModelInstance<T>>;
|
||||
getFilteredCollection: (options: {filter?: string}) => {count(): Promise<number>};
|
||||
getFilteredCollection: (options: {filter?: string}) => {
|
||||
count(): Promise<number>,
|
||||
query: (f: (q: Knex.QueryBuilder) => void) => void,
|
||||
fetchAll: () => Promise<ModelInstance<T>[]>
|
||||
};
|
||||
}
|
||||
|
||||
export type ModelInstance<T> = {
|
||||
@ -64,22 +69,44 @@ export abstract class BookshelfRepository<IDType, T extends Entity<IDType>> {
|
||||
return model ? this.modelToEntity(model) : null;
|
||||
}
|
||||
|
||||
async getAll({filter, order}: { filter?: string; order?: OrderOption<T> } = {}): Promise<T[]> {
|
||||
const models = await this.Model.findAll({
|
||||
filter,
|
||||
order: this.#orderToString(order)
|
||||
}) as ModelInstance<IDType>[];
|
||||
async #fetchAll({filter, order, page, limit}: { filter?: string; order?: OrderOption<T>; page?: number; limit?: number }): Promise<T[]> {
|
||||
const collection = this.Model.getFilteredCollection({filter});
|
||||
const orderString = this.#orderToString(order);
|
||||
|
||||
if ((limit && page) || orderString) {
|
||||
collection
|
||||
.query((q) => {
|
||||
if (limit && page) {
|
||||
q.limit(limit);
|
||||
q.offset(limit * (page - 1));
|
||||
}
|
||||
|
||||
if (orderString) {
|
||||
q.orderByRaw(
|
||||
orderString
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const models = await collection.fetchAll();
|
||||
return (await Promise.all(models.map(model => this.modelToEntity(model)))).filter(entity => !!entity) as T[];
|
||||
}
|
||||
|
||||
async getPage({filter, order, page, limit}: { filter?: string; order?: OrderOption<T>; page: number; limit: number }): Promise<T[]> {
|
||||
const models = await this.Model.findAll({
|
||||
async getAll({filter, order}: { filter?: string; order?: OrderOption<T> } = {}): Promise<T[]> {
|
||||
return this.#fetchAll({
|
||||
filter,
|
||||
order: this.#orderToString(order),
|
||||
limit,
|
||||
page
|
||||
order
|
||||
});
|
||||
}
|
||||
|
||||
async getPage({filter, order, page, limit}: { filter?: string; order?: OrderOption<T>; page: number; limit: number }): Promise<T[]> {
|
||||
return this.#fetchAll({
|
||||
filter,
|
||||
order,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
return (await Promise.all(models.map(model => this.modelToEntity(model)))).filter(entity => !!entity) as T[];
|
||||
}
|
||||
|
||||
async getCount({filter}: { filter?: string } = {}): Promise<number> {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import assert from 'assert';
|
||||
import {BookshelfRepository, ModelClass, ModelInstance} from '../src/index';
|
||||
import {Knex} from 'knex';
|
||||
|
||||
type SimpleEntity = {
|
||||
id: string;
|
||||
@ -37,6 +38,10 @@ class SimpleBookshelfRepository extends BookshelfRepository<string, SimpleEntity
|
||||
class Model implements ModelClass<string> {
|
||||
items: ModelInstance<string>[] = [];
|
||||
|
||||
orderRaw?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
|
||||
constructor() {
|
||||
this.items = [];
|
||||
}
|
||||
@ -53,9 +58,10 @@ class Model implements ModelClass<string> {
|
||||
}
|
||||
return Promise.resolve(item ?? null);
|
||||
}
|
||||
findAll(options: {filter?: string | undefined; order?: string | undefined; page?: number; limit?: number | 'all'}): Promise<ModelInstance<string>[]> {
|
||||
|
||||
fetchAll(): Promise<ModelInstance<string>[]> {
|
||||
const sorted = this.items.slice().sort((a, b) => {
|
||||
for (const order of options.order?.split(',') ?? []) {
|
||||
for (const order of this.orderRaw?.split(',') ?? []) {
|
||||
const [field, direction] = order.split(' ');
|
||||
|
||||
const aValue = a.get(field as string) as number;
|
||||
@ -68,7 +74,7 @@ class Model implements ModelClass<string> {
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return Promise.resolve(sorted);
|
||||
return Promise.resolve(sorted.slice(this.offset ?? 0, (this.offset ?? 0) + (this.limit ?? sorted.length)));
|
||||
}
|
||||
|
||||
add(data: object): Promise<ModelInstance<string>> {
|
||||
@ -100,6 +106,24 @@ class Model implements ModelClass<string> {
|
||||
count() {
|
||||
return Promise.resolve(this.items.length);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
query(f: (q: Knex.QueryBuilder) => void) {
|
||||
return f({
|
||||
limit: (limit: number) => {
|
||||
this.limit = limit;
|
||||
return this;
|
||||
},
|
||||
offset: (offset: number) => {
|
||||
this.offset = offset;
|
||||
return this;
|
||||
},
|
||||
orderByRaw: (order: string) => {
|
||||
this.orderRaw = order;
|
||||
return this;
|
||||
}
|
||||
} as any as Knex.QueryBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
describe('BookshelfRepository', function () {
|
||||
|
@ -44,12 +44,6 @@ module.exports = function (Bookshelf) {
|
||||
});
|
||||
}
|
||||
|
||||
if (options.page && options.limit) {
|
||||
itemCollection
|
||||
.query('limit', options.limit)
|
||||
.query('offset', options.limit * (options.page - 1));
|
||||
}
|
||||
|
||||
const result = await itemCollection.fetchAll(options);
|
||||
if (options.withRelated) {
|
||||
_.each(result.models, function each(item) {
|
||||
|
@ -45,7 +45,7 @@ module.exports = function (Bookshelf) {
|
||||
case 'findOne':
|
||||
return baseOptions.concat(extraOptions, ['columns', 'require', 'mongoTransformer']);
|
||||
case 'findAll':
|
||||
return baseOptions.concat(extraOptions, ['filter', 'columns', 'mongoTransformer', 'page', 'limit']);
|
||||
return baseOptions.concat(extraOptions, ['filter', 'columns', 'mongoTransformer']);
|
||||
case 'findPage':
|
||||
return baseOptions.concat(extraOptions, ['filter', 'order', 'autoOrder', 'page', 'limit', 'columns', 'mongoTransformer']);
|
||||
default:
|
||||
|
@ -221,10 +221,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 0",
|
||||
"title": "Recommendation 0",
|
||||
"reason": "Reason 14",
|
||||
"title": "Recommendation 14",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation0.com/",
|
||||
"url": "https://recommendation14.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -233,10 +233,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 1",
|
||||
"title": "Recommendation 1",
|
||||
"reason": "Reason 13",
|
||||
"title": "Recommendation 13",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation1.com/",
|
||||
"url": "https://recommendation13.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -245,10 +245,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 2",
|
||||
"title": "Recommendation 2",
|
||||
"reason": "Reason 12",
|
||||
"title": "Recommendation 12",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation2.com/",
|
||||
"url": "https://recommendation12.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -257,10 +257,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 3",
|
||||
"title": "Recommendation 3",
|
||||
"reason": "Reason 11",
|
||||
"title": "Recommendation 11",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation3.com/",
|
||||
"url": "https://recommendation11.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -269,10 +269,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 4",
|
||||
"title": "Recommendation 4",
|
||||
"reason": "Reason 10",
|
||||
"title": "Recommendation 10",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation4.com/",
|
||||
"url": "https://recommendation10.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -281,10 +281,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 5",
|
||||
"title": "Recommendation 5",
|
||||
"reason": "Reason 9",
|
||||
"title": "Recommendation 9",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation5.com/",
|
||||
"url": "https://recommendation9.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -293,10 +293,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 6",
|
||||
"title": "Recommendation 6",
|
||||
"reason": "Reason 8",
|
||||
"title": "Recommendation 8",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation6.com/",
|
||||
"url": "https://recommendation8.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -317,10 +317,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 8",
|
||||
"title": "Recommendation 8",
|
||||
"reason": "Reason 6",
|
||||
"title": "Recommendation 6",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation8.com/",
|
||||
"url": "https://recommendation6.com/",
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -330,7 +330,7 @@ exports[`Recommendations Admin API Can request pages 2: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "2964",
|
||||
"content-length": "2979",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
@ -359,10 +359,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 9",
|
||||
"title": "Recommendation 9",
|
||||
"reason": "Reason 5",
|
||||
"title": "Recommendation 5",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation9.com/",
|
||||
"url": "https://recommendation5.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -371,10 +371,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 10",
|
||||
"title": "Recommendation 10",
|
||||
"reason": "Reason 4",
|
||||
"title": "Recommendation 4",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation10.com/",
|
||||
"url": "https://recommendation4.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -383,10 +383,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 11",
|
||||
"title": "Recommendation 11",
|
||||
"reason": "Reason 3",
|
||||
"title": "Recommendation 3",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation11.com/",
|
||||
"url": "https://recommendation3.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -395,10 +395,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 12",
|
||||
"title": "Recommendation 12",
|
||||
"reason": "Reason 2",
|
||||
"title": "Recommendation 2",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation12.com/",
|
||||
"url": "https://recommendation2.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -407,10 +407,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 13",
|
||||
"title": "Recommendation 13",
|
||||
"reason": "Reason 1",
|
||||
"title": "Recommendation 1",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation13.com/",
|
||||
"url": "https://recommendation1.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -419,10 +419,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 14",
|
||||
"title": "Recommendation 14",
|
||||
"reason": "Reason 0",
|
||||
"title": "Recommendation 0",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation14.com/",
|
||||
"url": "https://recommendation0.com/",
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -432,7 +432,7 @@ exports[`Recommendations Admin API Can request pages 4: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "1790",
|
||||
"content-length": "1775",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
@ -507,7 +507,7 @@ exports[`Recommendations Admin API Uses default limit of 5 1: [headers] 1`] = `
|
||||
Object {
|
||||
"access-control-allow-origin": "http://127.0.0.1:2369",
|
||||
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
|
||||
"content-length": "1573",
|
||||
"content-length": "1585",
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
|
||||
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
|
||||
|
@ -201,7 +201,8 @@ describe('Recommendations Admin API', function () {
|
||||
favicon: null,
|
||||
featuredImage: null,
|
||||
excerpt: null,
|
||||
oneClickSubscribe: false
|
||||
oneClickSubscribe: false,
|
||||
createdAt: new Date(i * 5000) // Reliable ordering
|
||||
});
|
||||
|
||||
await recommendationsService.repository.save(recommendation);
|
||||
|
@ -20,10 +20,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 0",
|
||||
"title": "Recommendation 0",
|
||||
"reason": "Reason 6",
|
||||
"title": "Recommendation 6",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation0.com/",
|
||||
"url": "https://recommendation6.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -32,10 +32,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 1",
|
||||
"title": "Recommendation 1",
|
||||
"reason": "Reason 5",
|
||||
"title": "Recommendation 5",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation1.com/",
|
||||
"url": "https://recommendation5.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -44,10 +44,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 2",
|
||||
"title": "Recommendation 2",
|
||||
"reason": "Reason 4",
|
||||
"title": "Recommendation 4",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation2.com/",
|
||||
"url": "https://recommendation4.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -68,10 +68,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 4",
|
||||
"title": "Recommendation 4",
|
||||
"reason": "Reason 2",
|
||||
"title": "Recommendation 2",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation4.com/",
|
||||
"url": "https://recommendation2.com/",
|
||||
},
|
||||
],
|
||||
}
|
||||
@ -110,10 +110,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 5",
|
||||
"title": "Recommendation 5",
|
||||
"reason": "Reason 1",
|
||||
"title": "Recommendation 1",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation5.com/",
|
||||
"url": "https://recommendation1.com/",
|
||||
},
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
@ -122,10 +122,10 @@ Object {
|
||||
"featured_image": null,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"one_click_subscribe": false,
|
||||
"reason": "Reason 6",
|
||||
"title": "Recommendation 6",
|
||||
"reason": "Reason 0",
|
||||
"title": "Recommendation 0",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"url": "https://recommendation6.com/",
|
||||
"url": "https://recommendation0.com/",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ describe('Recommendations Content API', function () {
|
||||
favicon: null,
|
||||
featuredImage: null,
|
||||
excerpt: null,
|
||||
oneClickSubscribe: false
|
||||
oneClickSubscribe: false,
|
||||
createdAt: new Date(i * 5000) // Reliable ordering
|
||||
});
|
||||
|
||||
await recommendationsService.repository.save(recommendation);
|
||||
|
Loading…
Reference in New Issue
Block a user