1 | # @36node/query-normalizr
|
2 |
|
3 | [![version][0]][1] [![downloads][2]][3]
|
4 |
|
5 | query-normalizr 的作用: 将 url 中的 query 规则化成方便 sdk 和 service 层调用的数据格式。
|
6 |
|
7 | ## Install
|
8 |
|
9 | ```bash
|
10 | yarn add @36node/query-normalizr
|
11 | ```
|
12 |
|
13 | ## Usage
|
14 |
|
15 | ```js
|
16 | import normalizr from "@36node/query-normalizr";
|
17 |
|
18 | // koa app
|
19 | app.use(normalizr(options));
|
20 | ```
|
21 |
|
22 | ## API
|
23 |
|
24 | ### middleware
|
25 |
|
26 | ```js
|
27 | normalizr(options);
|
28 |
|
29 | // return koa middleware
|
30 | ```
|
31 |
|
32 | ### normalize
|
33 |
|
34 | ```js
|
35 | import { normalize } from "@36node/query-normalizr";
|
36 | import qs from "query-string";
|
37 |
|
38 | const queryStr =
|
39 | " _expand=department&_group=type&_limit=10&_offset=0&_populate=user&_select=name&_select=age&_sort=updatedAt&_sort=-createdAt&age_gt=10&age_lt=20&assignees=*&followers=none&level_gte=10&level_lte=20&plate_like=沪A&q=hello&tag_ne=pretty&title_like=hello&type=test1&type=test2";
|
40 |
|
41 | normalize(qs.parse(queryStr));
|
42 |
|
43 | /*
|
44 | return {
|
45 | limit: 10,
|
46 | offset: 0,
|
47 | sort: ["updatedAt", "-createdAt"],
|
48 | populate: "user",
|
49 | select: ["name", "age"],
|
50 | group: "type",
|
51 | filter: {
|
52 | age: {
|
53 | $gt: "10",
|
54 | $lt: "20",
|
55 | },
|
56 | assignees: {
|
57 | $ne: [],
|
58 | },
|
59 | followers: {
|
60 | $eq: [],
|
61 | },
|
62 | level: {
|
63 | $gte: "10",
|
64 | $lte: "20",
|
65 | },
|
66 | plate: {
|
67 | $regex: {},
|
68 | },
|
69 | $text: {
|
70 | $search: "internet",
|
71 | },
|
72 | tag: {
|
73 | $ne: "pretty",
|
74 | },
|
75 | title: {
|
76 | $regex: {},
|
77 | },
|
78 | type: {
|
79 | $in: ["test1", "test2"],
|
80 | },
|
81 | },
|
82 | _expand: "department",
|
83 | };
|
84 | */
|
85 | ```
|
86 |
|
87 | ### denormalize
|
88 |
|
89 | ```js
|
90 | import { denormalize } from "@36node/query-normalizr";
|
91 | import qs from "query-string";
|
92 |
|
93 | const queryObj = {
|
94 | limit: 10,
|
95 | offset: 0,
|
96 | sort: ["updatedAt", "-createdAt"],
|
97 | populate: "user",
|
98 | select: ["name", "age"],
|
99 | group: "type",
|
100 | filter: {
|
101 | age: {
|
102 | $gt: "10",
|
103 | $lt: "20",
|
104 | },
|
105 | assignees: {
|
106 | $ne: [],
|
107 | },
|
108 | followers: {
|
109 | $eq: [],
|
110 | },
|
111 | level: {
|
112 | $gte: "10",
|
113 | $lte: "20",
|
114 | },
|
115 | plate: {
|
116 | $regex: {},
|
117 | },
|
118 | $text: {
|
119 | $search: "internet",
|
120 | },
|
121 | tag: {
|
122 | $ne: "pretty",
|
123 | },
|
124 | title: {
|
125 | $regex: {},
|
126 | },
|
127 | type: {
|
128 | $in: ["test1", "test2"],
|
129 | },
|
130 | },
|
131 | _expand: "department",
|
132 | };
|
133 |
|
134 | qs.stringfy(denormalize(queryObj));
|
135 |
|
136 | // return " _expand=department&_group=type&_limit=10&_offset=0&_populate=user&_select=name&_select=age&_sort=updatedAt&_sort=-createdAt&age_gt=10&age_lt=20&assignees=%2A&followers=none&level_gte=10&level_lte=20&plate_like=%E6%B2%AAA&q=hello&tag_ne=pretty&title_like=hello&type=test1&type=test2"
|
137 | ```
|
138 |
|
139 | ## What is query normalizr
|
140 |
|
141 | ![image](https://user-images.githubusercontent.com/4343458/53739979-0c2d6f00-3ece-11e9-9c32-9516ecea9c25.png)
|
142 |
|
143 | ### Query in route (QIR)
|
144 |
|
145 | #### Array
|
146 |
|
147 | we use standard url query format to pass array data.
|
148 |
|
149 | ```curl
|
150 | a=1&a=2
|
151 | ```
|
152 |
|
153 | #### Filter
|
154 |
|
155 | Use `.` to access deep properties
|
156 |
|
157 | ```curl
|
158 | GET /posts?title=json-server&author=typicode
|
159 | GET /posts?id=1&id=2
|
160 | GET /comments?author.name=typicode
|
161 | ```
|
162 |
|
163 | ### Paginate
|
164 |
|
165 | Use `_offset` and optionally `_limit` to paginate returned data. (an `X-Total-Count` header is included in the response)
|
166 |
|
167 | ```curl
|
168 | GET /posts?_offset=10
|
169 | GET /posts?_offset=7&_limit=20
|
170 | ```
|
171 |
|
172 | node 10 items are return by default
|
173 |
|
174 | #### Sort
|
175 |
|
176 | Add `_sort`
|
177 |
|
178 | ```curl
|
179 | # asc
|
180 | GET /posts?_sort=views
|
181 |
|
182 | # desc
|
183 | GET /posts/1/comments?_sort=-votes
|
184 | ```
|
185 |
|
186 | For multiple fields, use the following format:
|
187 |
|
188 | ```curl
|
189 | GET /posts/1/comments?_sort=-votes&_sort=likes
|
190 | ```
|
191 |
|
192 | \_prefixing a path with `-` will flag that sort is descending order.
|
193 | When a path does not have the `-` prefix, it is ascending order.
|
194 |
|
195 | #### Operators
|
196 |
|
197 | Add `_gt`, `_lt`, `_gte` or `_lte` for getting a range
|
198 |
|
199 | ```curl
|
200 | GET /posts?views_gte=10&views_lte=20
|
201 | ```
|
202 |
|
203 | Add `_ne` to exclude a value
|
204 |
|
205 | ```curl
|
206 | GET /posts?id_ne=1
|
207 | ```
|
208 |
|
209 | Add `_like` to filter (RegExp supported)
|
210 |
|
211 | ```curl
|
212 | GET /posts?title_like=server
|
213 | ```
|
214 |
|
215 | ### Array wildcard
|
216 |
|
217 | If a field is an array, like:
|
218 |
|
219 | 1. `assignees=*` means assignees has at least one member.
|
220 | 2. `assignees=none` means assignees is an empty array.
|
221 |
|
222 | ### Full-text search
|
223 |
|
224 | Add `q`
|
225 |
|
226 | ```curl
|
227 | GET /posts?q=internet
|
228 | ```
|
229 |
|
230 | #### Select
|
231 |
|
232 | Specifies which document fields to include or exclude
|
233 |
|
234 | ```curl
|
235 | GET /posts?_select=title&_select=body
|
236 | GET /posts?_select=-comments&_select=-views
|
237 | ```
|
238 |
|
239 | _prefixing a path with `-` will flag that path as excluded.
|
240 | When a path does not have the `-` prefix, it is included_
|
241 | A projection must be either inclusive or exclusive.
|
242 | In other words, you must either list the fields to include (which excludes all others),
|
243 | or list the fields to exclude (which implies all other fields are included).
|
244 |
|
245 | ### Query in service (QIS)
|
246 |
|
247 | ```js
|
248 | {
|
249 | limit: 10,
|
250 | offset: 10,
|
251 | sort: "-createdBy", // if array should be: ["-createdBy", "views"]
|
252 | select: ["views", "body"], // if single should be: "views"
|
253 | populate: "author",
|
254 | filter: {
|
255 | age: {
|
256 | $lt: 10, // age_lt
|
257 | $gt: 5, // age_gt
|
258 | },
|
259 | tag: {
|
260 | $ne: "pretty", // tag_ne
|
261 | },
|
262 | name: "sherry",
|
263 | title: {
|
264 | $regex: /^hello .* world$/i, // like
|
265 | },
|
266 | assignees: { $ne: [] }, // *
|
267 | followers: { $eq: [] }, // none
|
268 | $text: { $search: "hello" }, // q
|
269 | }
|
270 | }
|
271 | ```
|
272 |
|
273 | ## Contributing
|
274 |
|
275 | 1. Fork it!
|
276 | 2. Create your feature branch: `git checkout -b my-new-feature`
|
277 | 3. Commit your changes: `git commit -am 'Add some feature'`
|
278 | 4. Push to the branch: `git push origin my-new-feature`
|
279 | 5. Submit a pull request :D
|
280 |
|
281 | ## Author
|
282 |
|
283 | **query-normalizr** © [36node](https://github.com/36node), Released under the [MIT](./LICENSE) License.
|
284 |
|
285 | Authored and maintained by 36node with help from contributors ([list](https://github.com/36node/query-normalizr/contributors)).
|
286 |
|
287 | > [github.com/zzswang](https://github.com/zzswang) · GitHub [@36node](https://github.com/36node) · Twitter [@y](https://twitter.com/y)
|
288 |
|
289 | [0]: https://img.shields.io/npm/v/@36node/query-normalizr.svg?style=flat
|
290 | [1]: https://npmjs.com/package/@36node/query-normalizr
|
291 | [2]: https://img.shields.io/npm/dm/@36node/query-normalizr.svg?style=flat
|
292 | [3]: https://npmjs.com/package/@36node/query-normalizr
|