getData.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // import { PipelineStage, Schema, SchemaTypes } from "mongoose";
  2. // export enum FilterType {
  3. // REGEX = "regex",
  4. // CONTAINS = "contains",
  5. // EXACT = "exact",
  6. // DATETIME_BEFORE = "datetimeBefore",
  7. // DATETIME_AFTER = "datetimeAfter",
  8. // NUMBER_LESSER_EQUAL = "numberLesserEqual",
  9. // NUMBER_LESSER = "numberLesser",
  10. // NUMBER_GREATER = "numberGreater",
  11. // NUMBER_GREATER_EQUAL = "numberGreaterEqual",
  12. // NUMBER_EQUAL = "numberEquals",
  13. // BOOLEAN = "boolean",
  14. // SPECIAL = "special"
  15. // }
  16. // export interface GetData {
  17. // getData(payload: {
  18. // page: number;
  19. // pageSize: number;
  20. // properties: string[];
  21. // sort: Record<string, "ascending" | "descending">;
  22. // queries: {
  23. // data: any;
  24. // filter: {
  25. // property: string;
  26. // };
  27. // filterType: FilterType;
  28. // }[];
  29. // operator: "and" | "or" | "nor";
  30. // }): Promise<{
  31. // data: any[];
  32. // count: number;
  33. // }>;
  34. // }
  35. // export default function getDataPlugin(schema: Schema) {
  36. // schema.static(
  37. // "getData",
  38. // async function getData(
  39. // payload: Parameters<GetData["getData"]>[0]
  40. // ): ReturnType<GetData["getData"]> {
  41. // const { page, pageSize, properties, sort, queries, operator } =
  42. // payload;
  43. // const getData = schema.get("getData");
  44. // if (!getData)
  45. // throw new Error("Schema doesn't have getData defined.");
  46. // const {
  47. // blacklistedProperties,
  48. // specialFilters,
  49. // specialProperties,
  50. // specialQueries
  51. // } = getData;
  52. // const pipeline: PipelineStage[] = [];
  53. // // If a query filter property or sort property is blacklisted, throw error
  54. // if (Array.isArray(blacklistedProperties)) {
  55. // if (
  56. // queries.some(query =>
  57. // blacklistedProperties.some(blacklistedProperty =>
  58. // blacklistedProperty.startsWith(
  59. // query.filter.property
  60. // )
  61. // )
  62. // )
  63. // )
  64. // throw new Error(
  65. // "Unable to filter by blacklisted property."
  66. // );
  67. // if (
  68. // Object.keys(sort).some(property =>
  69. // blacklistedProperties.some(blacklistedProperty =>
  70. // blacklistedProperty.startsWith(property)
  71. // )
  72. // )
  73. // )
  74. // throw new Error("Unable to sort by blacklisted property.");
  75. // }
  76. // // If a filter or property exists for a special property, add some custom pipeline steps
  77. // if (typeof specialProperties === "object")
  78. // Object.entries(specialProperties).forEach(
  79. // ([specialProperty, pipelineSteps]) => {
  80. // // Check if a filter with the special property exists
  81. // const filterExists =
  82. // queries
  83. // .map(query => query.filter.property)
  84. // .indexOf(specialProperty) !== -1;
  85. // // Check if a property with the special property exists
  86. // const propertyExists =
  87. // properties.indexOf(specialProperty) !== -1;
  88. // // If no such filter or property exists, skip this function
  89. // if (!filterExists && !propertyExists) return;
  90. // // Add the specified pipeline steps into the pipeline
  91. // pipeline.push(...pipelineSteps);
  92. // }
  93. // );
  94. // // Adds the match stage to aggregation pipeline, which is responsible for filtering
  95. // const filterQueries = queries.flatMap(query => {
  96. // const { data, filter, filterType } = query;
  97. // const { property } = filter;
  98. // const newQuery: any = {};
  99. // switch (filterType) {
  100. // case FilterType.REGEX:
  101. // newQuery[property] = new RegExp(
  102. // `${data.slice(1, data.length - 1)}`,
  103. // "i"
  104. // );
  105. // break;
  106. // case FilterType.CONTAINS:
  107. // newQuery[property] = new RegExp(
  108. // `${data.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")}`,
  109. // "i"
  110. // );
  111. // break;
  112. // case FilterType.EXACT:
  113. // newQuery[property] = data.toString();
  114. // break;
  115. // case FilterType.DATETIME_BEFORE:
  116. // newQuery[property] = { $lte: new Date(data) };
  117. // break;
  118. // case FilterType.DATETIME_AFTER:
  119. // newQuery[property] = { $gte: new Date(data) };
  120. // break;
  121. // case FilterType.NUMBER_LESSER_EQUAL:
  122. // newQuery[property] = { $lte: Number(data) };
  123. // break;
  124. // case FilterType.NUMBER_LESSER:
  125. // newQuery[property] = { $lt: Number(data) };
  126. // break;
  127. // case FilterType.NUMBER_GREATER:
  128. // newQuery[property] = { $gt: Number(data) };
  129. // break;
  130. // case FilterType.NUMBER_GREATER_EQUAL:
  131. // newQuery[property] = { $gte: Number(data) };
  132. // break;
  133. // case FilterType.NUMBER_EQUAL:
  134. // newQuery[property] = { $eq: Number(data) };
  135. // break;
  136. // case FilterType.BOOLEAN:
  137. // newQuery[property] = { $eq: !!data };
  138. // break;
  139. // case FilterType.SPECIAL:
  140. // if (
  141. // typeof specialFilters === "object" &&
  142. // typeof specialFilters[filter.property] ===
  143. // "function"
  144. // ) {
  145. // pipeline.push(
  146. // ...specialFilters[filter.property](data)
  147. // );
  148. // newQuery[property] = { $eq: true };
  149. // }
  150. // break;
  151. // default:
  152. // throw new Error(`Invalid filter type for "${filter}"`);
  153. // }
  154. // if (
  155. // typeof specialQueries === "object" &&
  156. // typeof specialQueries[filter.property] === "function"
  157. // ) {
  158. // return specialQueries[filter.property](newQuery);
  159. // }
  160. // return newQuery;
  161. // });
  162. // const filterQuery: any = {};
  163. // if (filterQueries.length > 0)
  164. // filterQuery[`$${operator}`] = filterQueries;
  165. // pipeline.push({ $match: filterQuery });
  166. // // Adds sort stage to aggregation pipeline if there is at least one column being sorted, responsible for sorting data
  167. // if (Object.keys(sort).length > 0)
  168. // pipeline.push({
  169. // $sort: Object.fromEntries(
  170. // Object.entries(sort).map(([property, direction]) => [
  171. // property,
  172. // direction === "ascending" ? 1 : -1
  173. // ])
  174. // )
  175. // });
  176. // // Adds first project stage to aggregation pipeline, responsible for including only the requested properties
  177. // pipeline.push({
  178. // $project: Object.fromEntries(
  179. // properties.map(property => [property, 1])
  180. // )
  181. // });
  182. // // Adds second project stage to aggregation pipeline, responsible for excluding some specific properties
  183. // if (
  184. // Array.isArray(blacklistedProperties) &&
  185. // blacklistedProperties.length > 0
  186. // )
  187. // pipeline.push({
  188. // $project: Object.fromEntries(
  189. // blacklistedProperties.map(property => [property, 0])
  190. // )
  191. // });
  192. // // Adds the facet stage to aggregation pipeline, responsible for returning a total document count, skipping and limitting the documents that will be returned
  193. // pipeline.push({
  194. // $facet: {
  195. // count: [{ $count: "count" }],
  196. // documents: [
  197. // { $skip: pageSize * (page - 1) },
  198. // { $limit: pageSize }
  199. // ]
  200. // }
  201. // });
  202. // // Executes the aggregation pipeline
  203. // const [result] = await this.aggregate(pipeline).exec();
  204. // if (result.count.length === 0) return { data: [], count: 0 };
  205. // properties.forEach(property => {
  206. // const type = schema.path(property);
  207. // if (type instanceof SchemaTypes.ObjectId) {
  208. // const { ref } = type?.options ?? {};
  209. // if (ref) {
  210. // result.documents = result.documents.map(
  211. // (document: any) => ({
  212. // ...document,
  213. // [property]: {
  214. // _name: ref,
  215. // _id: document[property]
  216. // }
  217. // })
  218. // );
  219. // }
  220. // } else if (
  221. // type instanceof SchemaTypes.Array &&
  222. // type.caster instanceof SchemaTypes.ObjectId
  223. // ) {
  224. // console.log("Array relation not implemented", property);
  225. // }
  226. // });
  227. // result.documents = result.documents.map((document: any) => ({
  228. // ...document,
  229. // // TODO properly support getModelName in TypeScript
  230. // // eslint-disable-next-line
  231. // // @ts-ignore
  232. // _name: schema.statics.getModelName()
  233. // }));
  234. // const { documents: data } = result;
  235. // const { count } = result.count[0];
  236. // return { data, count };
  237. // }
  238. // );
  239. // }