Skip to content

Commit

Permalink
feat: issue #115 support rest select fields in query
Browse files Browse the repository at this point in the history
  • Loading branch information
cyp3rius committed Apr 15, 2022
1 parent eddd4b3 commit 5e7933d
Show file tree
Hide file tree
Showing 14 changed files with 123 additions and 31 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ Return a hierarchical tree structure of comments for specified instance of Conte

#### Strapi REST API properties support:

- [field selection](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/populating-fields.html#field-selection)
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)

### Get Comments (flat structure)
Expand Down Expand Up @@ -350,6 +351,7 @@ Return a flat structure of comments for specified instance of Content Type like
#### Strapi REST API properties support:

- [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/filtering-locale-publication.html#filtering)
- [field selection](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/populating-fields.html#field-selection)
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
- [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#pagination)

Expand Down
15 changes: 12 additions & 3 deletions __mocks__/initSetup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { get, set, isEmpty } from "lodash";
import { get, set, pick, isEmpty } from "lodash";

// @ts-ignore
export = (config: any = {}, toStore: boolean = false, database: any = {}) => {
Expand All @@ -18,9 +18,18 @@ export = (config: any = {}, toStore: boolean = false, database: any = {}) => {
const [handler, rest] = uid.split("::");
const [collection] = rest.split(".");
const values = get(mock.db, `${handler}.${collection}.records`, []);

const parseValues = (values: any[], args: any = {}) => values.map(_ => {
const { select = [] } = args;
if (!isEmpty(select)) {
return pick(_, [...select, 'threadOf', 'authorUser']); // Relation fields can't be "unselected"
}
return _;
})

return {
findOne: async () => new Promise((resolve) => resolve(values[0])),
findMany: async () => new Promise((resolve) => resolve(values)),
findOne: async (args: any) => new Promise((resolve) => resolve(parseValues(values, args)[0])),
findMany: async (args: any) => new Promise((resolve) => resolve(parseValues(values, args))),
findWithCount: async () =>
new Promise((resolve) => resolve([values, values.length])),
count: async () => new Promise((resolve) => resolve(values.length)),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"ts-node": "^10.7.0",
"strapi-typed": "^1.0.5",
"strapi-typed": "^1.0.7",
"typescript": "^4.5.5"
},
"peerDependencies": {
Expand Down
8 changes: 5 additions & 3 deletions server/controllers/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const controllers: IControllerClient = {
const {
sort: querySort,
pagination: queryPagination,
fields,
...filterQuery
} = query || {};

Expand All @@ -48,7 +49,8 @@ const controllers: IControllerClient = {
relation,
filterQuery,
sort || querySort,
pagination || queryPagination
pagination || queryPagination,
fields
)
);
} catch (e: ToBeFixed) {
Expand All @@ -63,14 +65,14 @@ const controllers: IControllerClient = {
const { params, query, sort } = ctx;
const { relation } = parseParams<{ relation: string }>(params);

const { sort: querySort, ...filterQuery } = query || {};
const { sort: querySort, fields, ...filterQuery } = query || {};

try {
assertParamsPresent<{ relation: string }>(params, ["relation"]);

return await this.getService<IServiceCommon>("common").findAllInHierarchy(
{
...flatInput(relation, filterQuery, sort || querySort),
...flatInput<Comment>(relation, filterQuery, sort || querySort, undefined, fields),
dropBlockedThreads: true,
}
);
Expand Down
6 changes: 6 additions & 0 deletions server/controllers/utils/__tests__/parsers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe("Test Comments controller parsers utils", () => {
page: 3,
pageSize: 5,
};
const fields = ["content"];

test("Should contain default property 'populate'", () => {
expect(flatInput()).toHaveProperty(
Expand Down Expand Up @@ -66,6 +67,11 @@ describe("Test Comments controller parsers utils", () => {
);
});

test("Should assign fields", () => {
const result = flatInput(relation, filters, sort, undefined, fields);
expect(result).toHaveProperty(["fields", 0], fields[0]);
});

test("Should build complex output", () => {
const day = 24 * 60 * 60 * 1000;
const now = Date.now().toString();
Expand Down
8 changes: 5 additions & 3 deletions server/controllers/utils/parsers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Id } from "strapi-typed";
import { Id, OnlyStrings, StrapiRequestQueryFieldsClause } from "strapi-typed";
import { ToBeFixed } from "../../../types";

export const flatInput = (
export const flatInput = <T, TKeys = keyof T>(
relation: Id,
query: ToBeFixed,
sort: ToBeFixed,
pagination?: ToBeFixed
pagination?: ToBeFixed,
fields?: StrapiRequestQueryFieldsClause<OnlyStrings<TKeys>>,
) => {
const filters = query?.filters || query;
const orOperator = (filters?.$or || []).filter(
Expand All @@ -24,5 +25,6 @@ export const flatInput = (
},
pagination,
sort,
fields,
};
};
1 change: 0 additions & 1 deletion server/graphql/queries/findAllInHierarchy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type findAllInHierarchyProps = {
relation: Id;
filters: ToBeFixed;
sort: ToBeFixed;
pagination: ToBeFixed;
};

export = ({ strapi, nexus }: StrapiGraphQLContext) => {
Expand Down
23 changes: 23 additions & 0 deletions server/services/__tests__/common.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ const setup = (config = {}, toStore = false, database = {}) => {
});
};

const filterOutUndefined = (_: any) => Object.keys(_).reduce((prev, curr) => {
if (_[curr] !== undefined) {
return {
...prev,
[curr]: _[curr],
}
}
return prev;
}, {});

afterEach(() => {
Object.defineProperty(global, "strapi", {});
});
Expand Down Expand Up @@ -412,6 +422,19 @@ describe("Test Comments service functions utils", () => {
expect(result).toHaveProperty(["data", 3, "content"], db[3].content);
});

test("Should return structure with selected fields only (+mandatory ones for logic)", async () => { // Default fields are: id, related, threadOf, gotThread
const result = await getPluginService<IServiceCommon>(
"common"
).findAllFlat({ query: { related }, fields: ['content'] }, relatedEntity);
expect(result).toHaveProperty("data");
expect(result).not.toHaveProperty("meta");
expect(result.data.length).toBe(4);
expect(Object.keys(filterOutUndefined(result.data[0]))).toHaveLength(6);
expect(Object.keys(filterOutUndefined(result.data[1]))).toHaveLength(6);
expect(Object.keys(filterOutUndefined(result.data[2]))).toHaveLength(6);
expect(Object.keys(filterOutUndefined(result.data[3]))).toHaveLength(6);
});

test("Should return structure with pagination", async () => {
const result = await getPluginService<IServiceCommon>(
"common"
Expand Down
4 changes: 2 additions & 2 deletions server/services/admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export = ({ strapi }: StrapiContext): IServiceAdmin => ({
$or: [{ removed: false }, { removed: null }],
};

let params: StrapiDBQueryArgs = {
let params: StrapiDBQueryArgs<keyof Comment> = {
where: !isEmpty(filters)
? {
...defaultWhere,
Expand Down Expand Up @@ -177,7 +177,7 @@ export = ({ strapi }: StrapiContext): IServiceAdmin => ({
},
},
});
const total = await strapi.db.query<number>(getModelUid("comment")).count({
const total = await strapi.db.query<Comment>(getModelUid("comment")).count({
where: params.where,
});
const relatedEntities =
Expand Down
20 changes: 16 additions & 4 deletions server/services/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
parseInt,
set,
get,
uniq,
} from "lodash";
import {
Id,
Expand All @@ -18,15 +19,17 @@ import {
StrapiPagination,
StrapiResponseMeta,
StrapiPaginatedResponse,
StrapiDBQueryArgs,
} from "strapi-typed";
import {
CommentsPluginConfig,
FindAllFlatProps,
FindAllInHierarhyProps,
IServiceCommon,
ToBeFixed,
Comment,
RelatedEntity
} from "../../types";
import { Comment, RelatedEntity } from "../../types/contentTypes";
import { REGEX, CONFIG_PARAMS } from "../utils/constants";
import PluginError from "./../utils/error";
import {
Expand Down Expand Up @@ -81,14 +84,15 @@ export = ({ strapi }: StrapiContext): IServiceCommon => ({
// Find comments in the flat structure
async findAllFlat(
this: IServiceCommon,
{ query = {}, populate = {}, sort, pagination }: FindAllFlatProps,
{ query = {}, populate = {}, sort, pagination, fields }: FindAllFlatProps<Comment>,
relatedEntity: RelatedEntity | null = null
): Promise<StrapiPaginatedResponse<Comment>> {
const defaultSelect: Array<keyof Comment> = ['id', 'related'];
const defaultPopulate = {
authorUser: true,
};

let queryExtension = {};
let queryExtension: StrapiDBQueryArgs<keyof Comment> = {};

if (sort && (isString(sort) || isArray(sort))) {
queryExtension = {
Expand All @@ -102,6 +106,13 @@ export = ({ strapi }: StrapiContext): IServiceCommon => ({
};
}

if (!isNil(fields)) {
queryExtension = {
...queryExtension,
select: isArray(fields) ? uniq([...fields, ...defaultSelect]) : fields
};
}

let meta: StrapiResponseMeta = {} as StrapiResponseMeta;
if (pagination && isObject(pagination)) {
const parsedpagination: StrapiPagination = Object.keys(pagination).reduce(
Expand Down Expand Up @@ -249,13 +260,14 @@ export = ({ strapi }: StrapiContext): IServiceCommon => ({
query,
populate = {},
sort,
fields,
startingFromId = null,
dropBlockedThreads = false,
}: FindAllInHierarhyProps,
relatedEntity?: RelatedEntity | null | boolean
): Promise<Array<Comment>> {
const entities = await this.findAllFlat(
{ query, populate, sort },
{ query, populate, sort, fields },
relatedEntity
);
return buildNestedStructure(
Expand Down
1 change: 1 addition & 0 deletions types/contentTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type CommentAuthorPartial = {

export type CommentReport = {
id: Id;
related: Comment | Id;
reason: any;
content: string;
resolved: boolean;
Expand Down
2 changes: 1 addition & 1 deletion types/controllers.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export interface IControllerAdmin {
ctx: StrapiRequestContext
): ThrowablePromisedResponse<SettingsCommentsPluginConfig>;
settingsUpdateConfig(
ctx: StrapiRequestContext
ctx: StrapiRequestContext<SettingsCommentsPluginConfig>
): ThrowablePromisedResponse<SettingsCommentsPluginConfig>;
settingsRestoreConfig(
ctx: StrapiRequestContext<SettingsCommentsPluginConfig>
Expand Down
16 changes: 8 additions & 8 deletions types/services.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import {
StrapiQueryParamsParsedFilters,
StrapiQueryParamsParsedOrderBy,
StrapiUser,
OnlyStrings,
StringMap,
StrapiRequestQueryFieldsClause,
} from "strapi-typed";
import { ToBeFixed } from "./common";
import {
Expand All @@ -26,17 +29,14 @@ export type AdminPaginatedResponse<T> = {
result: Array<T>;
} & StrapiResponseMeta;

export type FindAllFlatProps = {
export type FindAllFlatProps<T, TFields = keyof T> = {
query: {
threadOf?: number | string | null;
[key: string]: any;
} & {};
populate?: {
[key: string]: any;
};
sort?: {
[key: string]: any;
};
populate?: StringMap<any>;
sort?: StringMap<any>;
fields?: StrapiRequestQueryFieldsClause<OnlyStrings<TFields>>
pagination?: StrapiPagination;
};

Expand Down Expand Up @@ -74,7 +74,7 @@ export interface IServiceCommon {
getPluginStore(): Promise<StrapiStore>;
getLocalConfig<T>(path?: string, defaultValue?: any): T;
findAllFlat(
props: FindAllFlatProps,
props: FindAllFlatProps<Comment>,
relatedEntity?: RelatedEntity | null | boolean
): Promise<StrapiPaginatedResponse<Comment>>;
findAllInHierarchy(
Expand Down
46 changes: 41 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,31 @@
pluralize "^8.0.0"
subscriptions-transport-ws "0.9.19"

"@strapi/plugin-graphql@^4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@strapi/plugin-graphql/-/plugin-graphql-4.1.8.tgz#7c3c9698bd191cfed130ddc9f2024ea936228a0e"
integrity sha512-Y5GC2YUU1gCGa392GxH5jvN1YgGoPt5biZpCfBe2u2O/UWB1O+kDZy+OgK6aydN9kI8HFTwxWiaipcunNDYmCw==
dependencies:
"@apollo/federation" "^0.28.0"
"@graphql-tools/schema" "8.1.2"
"@graphql-tools/utils" "^8.0.2"
"@strapi/utils" "4.1.8"
apollo-server-core "3.1.2"
apollo-server-koa "3.1.2"
glob "^7.1.7"
graphql "^15.5.1"
graphql-depth-limit "^1.1.0"
graphql-iso-date "^3.6.1"
graphql-playground-middleware-koa "^1.6.21"
graphql-type-json "^0.3.2"
graphql-type-long "^0.1.1"
graphql-upload "^13.0.0"
koa-compose "^4.1.0"
lodash "4.17.21"
nexus "1.2.0"
pluralize "^8.0.0"
subscriptions-transport-ws "0.9.19"

"@strapi/[email protected]", "@strapi/utils@^4.1.6":
version "4.1.6"
resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.1.6.tgz#edfdec2470143b2437cc95a5119ef5fa7d892eb4"
Expand All @@ -804,6 +829,17 @@
lodash "4.17.21"
yup "0.32.9"

"@strapi/[email protected]", "@strapi/utils@^4.1.8":
version "4.1.8"
resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.1.8.tgz#22c5b10b145f0ce005aefdb5611552ac73d02b23"
integrity sha512-FMC9gNQ+cXQNRkOaIiom6NlMIqqzo1gA9W/MkR/qezKIsivp+2nC+RsY4amS70D58yU/kjr1BdN5FtnwuyzOLQ==
dependencies:
"@sindresorhus/slugify" "1.1.0"
date-fns "2.24.0"
http-errors "1.8.0"
lodash "4.17.21"
yup "0.32.9"

"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
Expand Down Expand Up @@ -3369,7 +3405,7 @@ minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"

minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5:
minimist@^1.2.0, minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
Expand Down Expand Up @@ -3987,10 +4023,10 @@ stack-utils@^2.0.3:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=

strapi-typed@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/strapi-typed/-/strapi-typed-1.0.5.tgz#2bf0574c767058ec0fc85c2d32c8d45d0910942d"
integrity sha512-00K1pnyCfT3Oe/Z4jjJrWDd02c43NWaTHdngVUIKHOEDiroQBOHz/MsFRrVOf5x7HF/rgGhNsCcq4n89HoNLig==
strapi-typed@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/strapi-typed/-/strapi-typed-1.0.7.tgz#6f7a9bc5619138a842f456d7fb7db7854ca5f2d5"
integrity sha512-g6mpK1GSwpse6rOJ6bCdpQYdL1glHrSxtFjn+drdeZL3k5jEsIzp+MXDGomeAo04mP7KycJ3l+j+ZM0r/ob2LQ==
dependencies:
"@strapi/plugin-graphql" "^4.1.6"
"@strapi/utils" "^4.1.6"
Expand Down

0 comments on commit 5e7933d

Please sign in to comment.