ng-qubee 1.0.11 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -67
- package/esm2022/lib/enums/sort.enum.mjs +6 -0
- package/esm2022/lib/errors/key-not-found.error.mjs +6 -0
- package/esm2022/lib/errors/unselectable-model.error.mjs +6 -0
- package/esm2022/lib/interfaces/config.interface.mjs +2 -0
- package/esm2022/lib/interfaces/fields.interface.mjs +2 -0
- package/esm2022/lib/interfaces/filters.interface.mjs +2 -0
- package/esm2022/lib/interfaces/normalized.interface.mjs +2 -0
- package/esm2022/lib/interfaces/paginated-object.interface.mjs +2 -0
- package/esm2022/lib/interfaces/pagination-config.interface.mjs +2 -0
- package/esm2022/lib/interfaces/query-builder-config.interface.mjs +2 -0
- package/esm2022/lib/interfaces/query-builder-state.interface.mjs +2 -0
- package/esm2022/lib/interfaces/sort.interface.mjs +2 -0
- package/esm2022/lib/models/paginated-collection.mjs +47 -0
- package/esm2022/lib/models/query-builder-options.mjs +12 -0
- package/esm2022/lib/models/response-options.mjs +17 -0
- package/esm2022/lib/ng-qubee.module.mjs +42 -0
- package/esm2022/lib/provide-ngqubee.mjs +39 -0
- package/esm2022/lib/services/nest.service.mjs +173 -0
- package/esm2022/lib/services/ng-qubee.service.mjs +319 -0
- package/esm2022/lib/services/pagination.service.mjs +23 -0
- package/esm2022/ng-qubee.mjs +5 -0
- package/esm2022/public-api.mjs +9 -0
- package/{fesm2015/ng-qubee.js → fesm2022/ng-qubee.mjs} +369 -217
- package/fesm2022/ng-qubee.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/interfaces/normalized.interface.d.ts +3 -0
- package/lib/interfaces/paginated-object.interface.d.ts +3 -0
- package/lib/interfaces/query-builder-state.interface.d.ts +1 -2
- package/lib/interfaces/sort.interface.d.ts +2 -1
- package/lib/models/paginated-collection.d.ts +18 -16
- package/lib/ng-qubee.module.d.ts +4 -1
- package/lib/provide-ngqubee.d.ts +21 -0
- package/lib/services/nest.service.d.ts +81 -0
- package/lib/{ng-qubee.service.d.ts → services/ng-qubee.service.d.ts} +30 -8
- package/lib/services/pagination.service.d.ts +5 -1
- package/package.json +20 -18
- package/public-api.d.ts +3 -2
- package/bundles/ng-qubee.umd.js +0 -927
- package/bundles/ng-qubee.umd.js.map +0 -1
- package/bundles/ng-qubee.umd.min.js +0 -16
- package/bundles/ng-qubee.umd.min.js.map +0 -1
- package/esm2015/lib/actions/query-builder.actions.js +0 -17
- package/esm2015/lib/enums/sort.enum.js +0 -6
- package/esm2015/lib/errors/key-not-found.error.js +0 -6
- package/esm2015/lib/errors/unselectable-model.error.js +0 -6
- package/esm2015/lib/interfaces/config.interface.js +0 -2
- package/esm2015/lib/interfaces/fields.interface.js +0 -2
- package/esm2015/lib/interfaces/filters.interface.js +0 -2
- package/esm2015/lib/interfaces/nest-state.interface.js +0 -2
- package/esm2015/lib/interfaces/pagination-config.interface.js +0 -2
- package/esm2015/lib/interfaces/query-builder-config.interface.js +0 -2
- package/esm2015/lib/interfaces/query-builder-state.interface.js +0 -2
- package/esm2015/lib/interfaces/sort.interface.js +0 -2
- package/esm2015/lib/models/paginated-collection.js +0 -45
- package/esm2015/lib/models/query-builder-options.js +0 -12
- package/esm2015/lib/models/response-options.js +0 -17
- package/esm2015/lib/ng-qubee.module.js +0 -33
- package/esm2015/lib/ng-qubee.service.js +0 -298
- package/esm2015/lib/reducers/query-builder.reducer.js +0 -51
- package/esm2015/lib/services/pagination.service.js +0 -18
- package/esm2015/lib/services/store.service.js +0 -26
- package/esm2015/ng-qubee.js +0 -6
- package/esm2015/public-api.js +0 -8
- package/fesm2015/ng-qubee.js.map +0 -1
- package/lib/actions/query-builder.actions.d.ts +0 -43
- package/lib/interfaces/nest-state.interface.d.ts +0 -4
- package/lib/reducers/query-builder.reducer.d.ts +0 -2
- package/lib/services/store.service.d.ts +0 -9
- package/ng-qubee.d.ts +0 -7
- package/ng-qubee.metadata.json +0 -1
|
@@ -1,25 +1,57 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { BehaviorSubject } from 'rxjs';
|
|
5
|
-
import { filter } from 'rxjs/operators';
|
|
6
|
-
import { createStore, combineReducers } from 'redux';
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { signal, computed, Injectable, Inject, Optional, NgModule, makeEnvironmentProviders } from '@angular/core';
|
|
3
|
+
import * as qs from 'qs';
|
|
4
|
+
import { BehaviorSubject, filter } from 'rxjs';
|
|
7
5
|
|
|
8
|
-
class
|
|
9
|
-
constructor(
|
|
10
|
-
|
|
11
|
-
this.fields = options.fields || 'fields';
|
|
12
|
-
this.filters = options.filters || 'filter';
|
|
13
|
-
this.includes = options.includes || 'include';
|
|
14
|
-
this.limit = options.limit || 'limit';
|
|
15
|
-
this.page = options.page || 'page';
|
|
16
|
-
this.sort = options.sort || 'sort';
|
|
6
|
+
class KeyNotFoundError extends Error {
|
|
7
|
+
constructor(key) {
|
|
8
|
+
super(`Cannot find the key ${key} inside the collection item: does it really exists?`);
|
|
17
9
|
}
|
|
18
10
|
}
|
|
19
11
|
|
|
20
|
-
class
|
|
21
|
-
constructor(
|
|
22
|
-
|
|
12
|
+
class PaginatedCollection {
|
|
13
|
+
constructor(data, page, from, to, total, perPage, prevPageUrl, nextPageUrl, lastPage, firstPageUrl, lastPageUrl) {
|
|
14
|
+
this.data = data;
|
|
15
|
+
this.page = page;
|
|
16
|
+
this.from = from;
|
|
17
|
+
this.to = to;
|
|
18
|
+
this.total = total;
|
|
19
|
+
this.perPage = perPage;
|
|
20
|
+
this.prevPageUrl = prevPageUrl;
|
|
21
|
+
this.nextPageUrl = nextPageUrl;
|
|
22
|
+
this.lastPage = lastPage;
|
|
23
|
+
this.firstPageUrl = firstPageUrl;
|
|
24
|
+
this.lastPageUrl = lastPageUrl;
|
|
25
|
+
//
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Normalize the collection to a paginated list of ids for state-managed applications.
|
|
29
|
+
*
|
|
30
|
+
* This method returns a single key object, where the key is the page number and the associated value is
|
|
31
|
+
* an array of ids. Each id is fetched by the collection items, looking up for the "id" key. If an id is supplied
|
|
32
|
+
* to this method, it will be used instead of the default "id" key.
|
|
33
|
+
*
|
|
34
|
+
* Please note that in case the key doesn't exist in the collection's item, a KeyNotFoundError is thrown
|
|
35
|
+
*
|
|
36
|
+
* @param k A key to use instead of the default "id": this will be searched inside each element of the collection
|
|
37
|
+
* @returns []
|
|
38
|
+
* @throws KeyNotFoundItem
|
|
39
|
+
*/
|
|
40
|
+
normalize(id) {
|
|
41
|
+
return {
|
|
42
|
+
[this.page]: this.data.reduce((ids, value) => {
|
|
43
|
+
if (id && id in value) {
|
|
44
|
+
ids.push(value[id]);
|
|
45
|
+
}
|
|
46
|
+
else if (value.hasOwnProperty('id')) {
|
|
47
|
+
ids.push(value['id']);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new KeyNotFoundError(id || 'id');
|
|
51
|
+
}
|
|
52
|
+
return ids;
|
|
53
|
+
}, [])
|
|
54
|
+
};
|
|
23
55
|
}
|
|
24
56
|
}
|
|
25
57
|
|
|
@@ -29,23 +61,25 @@ var SortEnum;
|
|
|
29
61
|
SortEnum["DESC"] = "desc";
|
|
30
62
|
})(SortEnum || (SortEnum = {}));
|
|
31
63
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const deleteFields = createAction('[Query Buillder] Delete Fields');
|
|
38
|
-
const deleteFilters = createAction('[Query Buillder] Delete Filters');
|
|
39
|
-
const deleteIncludes = createAction('[Query Buillder] Delete Includes');
|
|
40
|
-
const deleteSorts = createAction('[Query Buillder] Delete Sorts');
|
|
41
|
-
const reset = createAction('[Query Builder] Reset');
|
|
42
|
-
const setBaseUrl = createAction('[Query Buillder] Set Base URL');
|
|
43
|
-
const setLimit = createAction('[Query Buillder] Set Limit');
|
|
44
|
-
const setModel = createAction('[Query Builder] Set Model');
|
|
45
|
-
const setPage = createAction('[Query Builder] Set Page');
|
|
46
|
-
const updateUri = createAction('[Query Builder] Update URI');
|
|
64
|
+
class UnselectableModelError extends Error {
|
|
65
|
+
constructor(model) {
|
|
66
|
+
super(`Unselectable Model: the selected model (${model}) is not present neither in the "model" property, nor in the includes object.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
47
69
|
|
|
48
|
-
|
|
70
|
+
class QueryBuilderOptions {
|
|
71
|
+
constructor(options) {
|
|
72
|
+
this.appends = options.appends || 'append';
|
|
73
|
+
this.fields = options.fields || 'fields';
|
|
74
|
+
this.filters = options.filters || 'filter';
|
|
75
|
+
this.includes = options.includes || 'include';
|
|
76
|
+
this.limit = options.limit || 'limit';
|
|
77
|
+
this.page = options.page || 'page';
|
|
78
|
+
this.sort = options.sort || 'sort';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const INITIAL_STATE = {
|
|
49
83
|
baseUrl: '',
|
|
50
84
|
fields: {},
|
|
51
85
|
filters: {},
|
|
@@ -53,71 +87,172 @@ const initialState = {
|
|
|
53
87
|
limit: 15,
|
|
54
88
|
model: '',
|
|
55
89
|
page: 1,
|
|
56
|
-
|
|
57
|
-
uri: ''
|
|
58
|
-
};
|
|
59
|
-
const ɵ0 = builder => {
|
|
60
|
-
builder.addCase(addFields, (state, { payload: { fields } }) => (Object.assign(Object.assign({}, state), { fields: Object.assign(Object.assign({}, state.fields), fields) }))),
|
|
61
|
-
builder.addCase(addFilters, (state, { payload: { filters } }) => (Object.assign(Object.assign({}, state), { filters: Object.assign(Object.assign({}, state.filters), filters) }))),
|
|
62
|
-
builder.addCase(addIncludes, (state, { payload: { includes } }) => (Object.assign(Object.assign({}, state), { includes: [...state.includes, ...includes] }))),
|
|
63
|
-
builder.addCase(addSorts, (state, { payload: { sorts } }) => (Object.assign(Object.assign({}, state), { sort: Object.assign(Object.assign({}, state.sort), sorts) }))),
|
|
64
|
-
builder.addCase(deleteFields, (state, { payload: { fields } }) => {
|
|
65
|
-
const f = Object.assign({}, state.fields);
|
|
66
|
-
Object.keys(fields).forEach(k => {
|
|
67
|
-
if (!(k in state.fields)) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
f[k] = state.fields[k].filter(v => !fields[k].includes(v));
|
|
71
|
-
});
|
|
72
|
-
return Object.assign(Object.assign({}, state), { fields: f });
|
|
73
|
-
}),
|
|
74
|
-
builder.addCase(deleteFilters, (state, { payload: { filters } }) => {
|
|
75
|
-
const f = Object.assign({}, state.filters);
|
|
76
|
-
filters.forEach(k => delete f[k]);
|
|
77
|
-
return Object.assign(Object.assign({}, state), { filters: f });
|
|
78
|
-
}),
|
|
79
|
-
builder.addCase(deleteIncludes, (state, { payload: { includes } }) => {
|
|
80
|
-
return Object.assign(Object.assign({}, state), { includes: state.includes.filter(v => !includes.includes(v)) });
|
|
81
|
-
}),
|
|
82
|
-
builder.addCase(deleteSorts, (state, { payload: { sorts } }) => {
|
|
83
|
-
const s = Object.assign({}, state.sort);
|
|
84
|
-
sorts.forEach(v => delete s[v]);
|
|
85
|
-
return Object.assign(Object.assign({}, state), { sort: s });
|
|
86
|
-
}),
|
|
87
|
-
builder.addCase(reset, state => initialState),
|
|
88
|
-
builder.addCase(setBaseUrl, (state, { payload: { baseUrl } }) => (Object.assign(Object.assign({}, state), { baseUrl }))),
|
|
89
|
-
builder.addCase(setLimit, (state, { payload: { limit } }) => (Object.assign(Object.assign({}, state), { limit }))),
|
|
90
|
-
builder.addCase(setModel, (state, { payload: { model } }) => (Object.assign(Object.assign({}, state), { model }))),
|
|
91
|
-
builder.addCase(setPage, (state, { payload: { page } }) => (Object.assign(Object.assign({}, state), { page }))),
|
|
92
|
-
builder.addCase(updateUri, (state, { payload: { uri } }) => (Object.assign(Object.assign({}, state), { uri })));
|
|
90
|
+
sorts: []
|
|
93
91
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
class StoreService {
|
|
92
|
+
class NestService {
|
|
97
93
|
constructor() {
|
|
98
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Private writable signal that holds the Query Builder state
|
|
96
|
+
*
|
|
97
|
+
* @type {IQueryBuilderState}
|
|
98
|
+
*/
|
|
99
|
+
this._nest = signal(this._clone(INITIAL_STATE));
|
|
100
|
+
/**
|
|
101
|
+
* A computed signal that makes readonly the writable signal _nest
|
|
102
|
+
*
|
|
103
|
+
* @type {Signal<IQueryBuilderState>}
|
|
104
|
+
*/
|
|
105
|
+
this.nest = computed(() => this._clone(this._nest()));
|
|
106
|
+
// Nothing to see here 👮🏻♀️
|
|
99
107
|
}
|
|
100
|
-
|
|
101
|
-
|
|
108
|
+
set baseUrl(baseUrl) {
|
|
109
|
+
this._nest.update(nest => ({
|
|
110
|
+
...nest,
|
|
111
|
+
baseUrl
|
|
112
|
+
}));
|
|
102
113
|
}
|
|
103
|
-
|
|
104
|
-
this.
|
|
114
|
+
set limit(limit) {
|
|
115
|
+
this._nest.update(nest => ({
|
|
116
|
+
...nest,
|
|
117
|
+
limit
|
|
118
|
+
}));
|
|
105
119
|
}
|
|
106
|
-
|
|
107
|
-
this.
|
|
120
|
+
set model(model) {
|
|
121
|
+
this._nest.update(nest => ({
|
|
122
|
+
...nest,
|
|
123
|
+
model
|
|
124
|
+
}));
|
|
108
125
|
}
|
|
126
|
+
set page(page) {
|
|
127
|
+
this._nest.update(nest => ({
|
|
128
|
+
...nest,
|
|
129
|
+
page
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
_clone(obj) {
|
|
133
|
+
return JSON.parse(JSON.stringify(obj));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Add selectable fields for the given model to the request
|
|
137
|
+
*
|
|
138
|
+
* @param {IFields} fields
|
|
139
|
+
* @return {void}
|
|
140
|
+
* @todo Avoid duplicated fields
|
|
141
|
+
*/
|
|
142
|
+
addFields(fields) {
|
|
143
|
+
this._nest.update(nest => ({
|
|
144
|
+
...nest,
|
|
145
|
+
fields: { ...nest.fields, ...fields }
|
|
146
|
+
}));
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Add filters to the request
|
|
150
|
+
*
|
|
151
|
+
* @param {IFilters} filters
|
|
152
|
+
* @todo Avoid duplicated filters
|
|
153
|
+
*/
|
|
154
|
+
addFilters(filters) {
|
|
155
|
+
this._nest.update(nest => ({
|
|
156
|
+
...nest,
|
|
157
|
+
filters: { ...nest.filters, ...filters }
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Add resources to include with the request
|
|
162
|
+
*
|
|
163
|
+
* @param {string[]} includes models to include to the request
|
|
164
|
+
* @return {void}
|
|
165
|
+
* @todo Avoid duplicated includes
|
|
166
|
+
*/
|
|
167
|
+
addIncludes(includes) {
|
|
168
|
+
this._nest.update(nest => ({
|
|
169
|
+
...nest,
|
|
170
|
+
includes: [...nest.includes, ...includes]
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Add a field that should be used for sorting data
|
|
175
|
+
*
|
|
176
|
+
* @param {ISort} sort
|
|
177
|
+
* @return {void}
|
|
178
|
+
*/
|
|
179
|
+
addSort(sort) {
|
|
180
|
+
this._nest.update(nest => ({
|
|
181
|
+
...nest,
|
|
182
|
+
sorts: [...nest.sorts, sort]
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Remove fields for the given model
|
|
187
|
+
*
|
|
188
|
+
* @param {IFields} fields
|
|
189
|
+
*/
|
|
190
|
+
deleteFields(fields) {
|
|
191
|
+
const f = Object.assign({}, this.nest().fields);
|
|
192
|
+
Object.keys(fields).forEach(k => {
|
|
193
|
+
if (!(k in f)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
f[k] = this._nest().fields[k].filter(v => !fields[k].includes(v));
|
|
197
|
+
});
|
|
198
|
+
this._nest.update(nest => ({
|
|
199
|
+
...nest,
|
|
200
|
+
fields: f
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
*
|
|
205
|
+
* @param filters
|
|
206
|
+
* @todo Create a clone of the filter obj before assigning to f
|
|
207
|
+
*/
|
|
208
|
+
deleteFilters(...filters) {
|
|
209
|
+
const f = Object.assign({}, this._nest().filters);
|
|
210
|
+
filters.forEach(k => delete f[k]);
|
|
211
|
+
this._nest.update(nest => ({
|
|
212
|
+
...nest,
|
|
213
|
+
filters: f
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
*
|
|
218
|
+
* @param includes
|
|
219
|
+
*/
|
|
220
|
+
deleteIncludes(...includes) {
|
|
221
|
+
this._nest.update(nest => ({
|
|
222
|
+
...nest,
|
|
223
|
+
includes: nest.includes.filter(v => !includes.includes(v))
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* @param sorts
|
|
229
|
+
*/
|
|
230
|
+
deleteSorts(...sorts) {
|
|
231
|
+
const s = [...this._nest().sorts];
|
|
232
|
+
sorts.forEach(field => {
|
|
233
|
+
const p = this.nest().sorts.findIndex(sort => sort.field === field);
|
|
234
|
+
if (p > -1) {
|
|
235
|
+
s.splice(p, 1);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
this._nest.update(nest => ({
|
|
239
|
+
...nest,
|
|
240
|
+
sorts: s
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
reset() {
|
|
244
|
+
this._nest.update(_ => this._clone(INITIAL_STATE));
|
|
245
|
+
}
|
|
246
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NestService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
247
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NestService }); }
|
|
109
248
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
providedIn: 'root'
|
|
114
|
-
},] }
|
|
115
|
-
];
|
|
116
|
-
StoreService.ctorParameters = () => [];
|
|
249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NestService, decorators: [{
|
|
250
|
+
type: Injectable
|
|
251
|
+
}], ctorParameters: () => [] });
|
|
117
252
|
|
|
118
253
|
class NgQubeeService {
|
|
119
|
-
constructor(
|
|
120
|
-
this.
|
|
254
|
+
constructor(_nestService, options = {}) {
|
|
255
|
+
this._nestService = _nestService;
|
|
121
256
|
/**
|
|
122
257
|
* This property serves as an accumulator for holding the composed string with each query param
|
|
123
258
|
*/
|
|
@@ -125,9 +260,6 @@ class NgQubeeService {
|
|
|
125
260
|
this._uri$ = new BehaviorSubject('');
|
|
126
261
|
this.uri$ = this._uri$.asObservable().pipe(filter(uri => !!uri));
|
|
127
262
|
this._options = new QueryBuilderOptions(options);
|
|
128
|
-
this._store.subscribe(() => {
|
|
129
|
-
this._uri$.next(this._store.state.nest.uri);
|
|
130
|
-
});
|
|
131
263
|
}
|
|
132
264
|
_parseFields(s) {
|
|
133
265
|
if (!Object.keys(s.fields).length) {
|
|
@@ -150,7 +282,7 @@ class NgQubeeService {
|
|
|
150
282
|
Object.assign(f, { [`${this._options.fields}[${k}]`]: s.fields[k].join(',') });
|
|
151
283
|
}
|
|
152
284
|
}
|
|
153
|
-
const param = `${this._prepend(s.model)}${stringify(f, { encode: false })}`;
|
|
285
|
+
const param = `${this._prepend(s.model)}${qs.stringify(f, { encode: false })}`;
|
|
154
286
|
this._uri += param;
|
|
155
287
|
return param;
|
|
156
288
|
}
|
|
@@ -160,11 +292,11 @@ class NgQubeeService {
|
|
|
160
292
|
return this._uri;
|
|
161
293
|
}
|
|
162
294
|
const f = {
|
|
163
|
-
[this._options.filters]: keys.reduce((acc, key) => {
|
|
295
|
+
[`${this._options.filters}`]: keys.reduce((acc, key) => {
|
|
164
296
|
return Object.assign(acc, { [key]: s.filters[key].join(',') });
|
|
165
297
|
}, {})
|
|
166
298
|
};
|
|
167
|
-
const param = `${this._prepend(s.model)}${stringify(f, { encode: false })}`;
|
|
299
|
+
const param = `${this._prepend(s.model)}${qs.stringify(f, { encode: false })}`;
|
|
168
300
|
this._uri += param;
|
|
169
301
|
return param;
|
|
170
302
|
}
|
|
@@ -188,14 +320,13 @@ class NgQubeeService {
|
|
|
188
320
|
}
|
|
189
321
|
_parseSort(s) {
|
|
190
322
|
let param = '';
|
|
191
|
-
|
|
192
|
-
if (!fields.length) {
|
|
323
|
+
if (!s.sorts.length) {
|
|
193
324
|
return param;
|
|
194
325
|
}
|
|
195
326
|
param = `${this._prepend(s.model)}${this._options.sort}=`;
|
|
196
|
-
|
|
197
|
-
param += `${
|
|
198
|
-
if (idx <
|
|
327
|
+
s.sorts.forEach((sort, idx) => {
|
|
328
|
+
param += `${sort.order === SortEnum.DESC ? '-' : ''}${sort.field}`;
|
|
329
|
+
if (idx < s.sorts.length - 1) {
|
|
199
330
|
param += ',';
|
|
200
331
|
}
|
|
201
332
|
});
|
|
@@ -206,17 +337,25 @@ class NgQubeeService {
|
|
|
206
337
|
if (!s.model) {
|
|
207
338
|
throw new Error('Set the model property BEFORE adding filters or calling the url() / get() methods');
|
|
208
339
|
}
|
|
340
|
+
// Cleanup the previously generated URI
|
|
341
|
+
this._uri = '';
|
|
209
342
|
this._parseIncludes(s);
|
|
210
343
|
this._parseFields(s);
|
|
211
344
|
this._parseFilters(s);
|
|
212
345
|
this._parseLimit(s);
|
|
213
346
|
this._parsePage(s);
|
|
214
347
|
this._parseSort(s);
|
|
215
|
-
|
|
348
|
+
return this._uri;
|
|
216
349
|
}
|
|
217
350
|
_prepend(model) {
|
|
218
351
|
return this._uri ? '&' : `/${model}?`;
|
|
219
352
|
}
|
|
353
|
+
// private _removeArgIfEmpty(arg: string): string {
|
|
354
|
+
// const params = new URL(this._uri).searchParams;
|
|
355
|
+
// if (!params.get(arg)) {
|
|
356
|
+
// params.delete(arg);
|
|
357
|
+
// }
|
|
358
|
+
// }
|
|
220
359
|
/**
|
|
221
360
|
* Add fields to the select statement for the given model
|
|
222
361
|
*
|
|
@@ -228,11 +367,7 @@ class NgQubeeService {
|
|
|
228
367
|
if (!fields.length) {
|
|
229
368
|
return this;
|
|
230
369
|
}
|
|
231
|
-
this.
|
|
232
|
-
fields: {
|
|
233
|
-
[model]: fields
|
|
234
|
-
}
|
|
235
|
-
}));
|
|
370
|
+
this._nestService.addFields({ [model]: fields });
|
|
236
371
|
return this;
|
|
237
372
|
}
|
|
238
373
|
/**
|
|
@@ -247,11 +382,9 @@ class NgQubeeService {
|
|
|
247
382
|
if (!values.length) {
|
|
248
383
|
return this;
|
|
249
384
|
}
|
|
250
|
-
this.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
}));
|
|
385
|
+
this._nestService.addFilters({
|
|
386
|
+
[field]: values
|
|
387
|
+
});
|
|
255
388
|
return this;
|
|
256
389
|
}
|
|
257
390
|
/**
|
|
@@ -261,41 +394,61 @@ class NgQubeeService {
|
|
|
261
394
|
* @returns
|
|
262
395
|
*/
|
|
263
396
|
addIncludes(...models) {
|
|
264
|
-
if (!models) {
|
|
397
|
+
if (!models.length) {
|
|
265
398
|
return this;
|
|
266
399
|
}
|
|
267
|
-
this.
|
|
268
|
-
includes: models
|
|
269
|
-
}));
|
|
400
|
+
this._nestService.addIncludes(models);
|
|
270
401
|
return this;
|
|
271
402
|
}
|
|
272
403
|
/**
|
|
273
404
|
* Add a field with a sort criteria
|
|
274
405
|
*
|
|
275
406
|
* @param field Field to use for sorting
|
|
276
|
-
* @param {SortEnum}
|
|
407
|
+
* @param {SortEnum} order A value from the SortEnum enumeration
|
|
277
408
|
* @returns {this}
|
|
278
409
|
*/
|
|
279
|
-
addSort(field,
|
|
280
|
-
this.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
410
|
+
addSort(field, order) {
|
|
411
|
+
this._nestService.addSort({
|
|
412
|
+
field,
|
|
413
|
+
order
|
|
414
|
+
});
|
|
415
|
+
return this;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Delete selected fields for the given models in the current query builder state
|
|
419
|
+
*
|
|
420
|
+
* ```
|
|
421
|
+
* ngQubeeService.deleteFields({
|
|
422
|
+
* users: ['email', 'password'],
|
|
423
|
+
* address: ['zipcode']
|
|
424
|
+
* });
|
|
425
|
+
* ```
|
|
426
|
+
*
|
|
427
|
+
* @param {IFields} fields
|
|
428
|
+
* @returns
|
|
429
|
+
*/
|
|
430
|
+
deleteFields(fields) {
|
|
431
|
+
this._nestService.deleteFields(fields);
|
|
285
432
|
return this;
|
|
286
433
|
}
|
|
287
434
|
/**
|
|
288
435
|
* Delete selected fields for the given model in the current query builder state
|
|
289
436
|
*
|
|
437
|
+
* ```
|
|
438
|
+
* ngQubeeService.deleteFieldsByModel('users', 'email', 'password']);
|
|
439
|
+
* ```
|
|
440
|
+
*
|
|
290
441
|
* @param model Model that holds the fields
|
|
291
442
|
* @param {string[]} fields Fields to delete from the state
|
|
292
443
|
* @returns {this}
|
|
293
444
|
*/
|
|
294
|
-
|
|
445
|
+
deleteFieldsByModel(model, ...fields) {
|
|
295
446
|
if (!fields.length) {
|
|
296
447
|
return this;
|
|
297
448
|
}
|
|
298
|
-
this.
|
|
449
|
+
this._nestService.deleteFields({
|
|
450
|
+
[model]: fields
|
|
451
|
+
});
|
|
299
452
|
return this;
|
|
300
453
|
}
|
|
301
454
|
/**
|
|
@@ -308,7 +461,7 @@ class NgQubeeService {
|
|
|
308
461
|
if (!filters.length) {
|
|
309
462
|
return this;
|
|
310
463
|
}
|
|
311
|
-
this.
|
|
464
|
+
this._nestService.deleteFilters(...filters);
|
|
312
465
|
return this;
|
|
313
466
|
}
|
|
314
467
|
/**
|
|
@@ -321,7 +474,7 @@ class NgQubeeService {
|
|
|
321
474
|
if (!includes.length) {
|
|
322
475
|
return this;
|
|
323
476
|
}
|
|
324
|
-
this.
|
|
477
|
+
this._nestService.deleteIncludes(...includes);
|
|
325
478
|
return this;
|
|
326
479
|
}
|
|
327
480
|
/**
|
|
@@ -331,7 +484,7 @@ class NgQubeeService {
|
|
|
331
484
|
* @returns {this}
|
|
332
485
|
*/
|
|
333
486
|
deleteSorts(...sorts) {
|
|
334
|
-
this.
|
|
487
|
+
this._nestService.deleteSorts(...sorts);
|
|
335
488
|
return this;
|
|
336
489
|
}
|
|
337
490
|
/**
|
|
@@ -340,9 +493,7 @@ class NgQubeeService {
|
|
|
340
493
|
* @returns {Observable<string>} An observable that emits the generated uri
|
|
341
494
|
*/
|
|
342
495
|
generateUri() {
|
|
343
|
-
|
|
344
|
-
this._uri = '';
|
|
345
|
-
this._parse(this._store.state.nest);
|
|
496
|
+
this._uri$.next(this._parse(this._nestService.nest()));
|
|
346
497
|
return this.uri$;
|
|
347
498
|
}
|
|
348
499
|
/**
|
|
@@ -351,7 +502,7 @@ class NgQubeeService {
|
|
|
351
502
|
* @returns {this}
|
|
352
503
|
*/
|
|
353
504
|
reset() {
|
|
354
|
-
this.
|
|
505
|
+
this._nestService.reset();
|
|
355
506
|
return this;
|
|
356
507
|
}
|
|
357
508
|
/**
|
|
@@ -361,7 +512,7 @@ class NgQubeeService {
|
|
|
361
512
|
* @returns {this}
|
|
362
513
|
*/
|
|
363
514
|
setBaseUrl(baseUrl) {
|
|
364
|
-
this.
|
|
515
|
+
this._nestService.baseUrl = baseUrl;
|
|
365
516
|
return this;
|
|
366
517
|
}
|
|
367
518
|
/**
|
|
@@ -371,7 +522,7 @@ class NgQubeeService {
|
|
|
371
522
|
* @returns {this}
|
|
372
523
|
*/
|
|
373
524
|
setLimit(limit) {
|
|
374
|
-
this.
|
|
525
|
+
this._nestService.limit = limit;
|
|
375
526
|
return this;
|
|
376
527
|
}
|
|
377
528
|
/**
|
|
@@ -382,7 +533,7 @@ class NgQubeeService {
|
|
|
382
533
|
* @returns {this}
|
|
383
534
|
*/
|
|
384
535
|
setModel(model) {
|
|
385
|
-
this.
|
|
536
|
+
this._nestService.model = model;
|
|
386
537
|
return this;
|
|
387
538
|
}
|
|
388
539
|
/**
|
|
@@ -392,67 +543,20 @@ class NgQubeeService {
|
|
|
392
543
|
* @returns {this}
|
|
393
544
|
*/
|
|
394
545
|
setPage(page) {
|
|
395
|
-
this.
|
|
546
|
+
this._nestService.page = page;
|
|
396
547
|
return this;
|
|
397
548
|
}
|
|
549
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeService, deps: [{ token: NestService }, { token: 'QUERY_PARAMS_CONFIG', optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
550
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeService }); }
|
|
398
551
|
}
|
|
399
|
-
NgQubeeService
|
|
400
|
-
|
|
401
|
-
]
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
class KeyNotFoundError extends Error {
|
|
408
|
-
constructor(key) {
|
|
409
|
-
super(`Cannot find the key ${key} inside the collection item: does it really exists?`);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
class PaginatedCollection {
|
|
414
|
-
constructor(data, page, from, to, total, perPage, prevPageUrl, nextPageUrl, lastPage, firstPageUrl, lastPageUrl) {
|
|
415
|
-
this.data = data;
|
|
416
|
-
this.page = page;
|
|
417
|
-
this.from = from;
|
|
418
|
-
this.to = to;
|
|
419
|
-
this.total = total;
|
|
420
|
-
this.perPage = perPage;
|
|
421
|
-
this.prevPageUrl = prevPageUrl;
|
|
422
|
-
this.nextPageUrl = nextPageUrl;
|
|
423
|
-
this.lastPage = lastPage;
|
|
424
|
-
this.firstPageUrl = firstPageUrl;
|
|
425
|
-
this.lastPageUrl = lastPageUrl;
|
|
426
|
-
//
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Normalize the collection to a paginated list of ids for state-managed applciations.
|
|
430
|
-
*
|
|
431
|
-
* This method returns a single key object, where the key is the page number and the associated value is
|
|
432
|
-
* an array of ids. Each id is fetched by the collection items, looking up for the "id" key. If an id is supplied
|
|
433
|
-
* to this method, it will be used instead of the default "id" key.
|
|
434
|
-
*
|
|
435
|
-
* Please note that in case the key doesn't exist in the collection's item, the array will be empty
|
|
436
|
-
*
|
|
437
|
-
* @param k A key to use instead of the default "id": this will be searched inside each element of the collection
|
|
438
|
-
*/
|
|
439
|
-
normalize(id) {
|
|
440
|
-
return {
|
|
441
|
-
[this.page]: this.data.reduce((ids, value) => {
|
|
442
|
-
if (id && value[id]) {
|
|
443
|
-
ids.push(value[id]);
|
|
444
|
-
}
|
|
445
|
-
else if (value.hasOwnProperty('id')) {
|
|
446
|
-
ids.push(value['id']);
|
|
447
|
-
}
|
|
448
|
-
else {
|
|
449
|
-
throw new KeyNotFoundError(id || 'id');
|
|
450
|
-
}
|
|
451
|
-
return ids;
|
|
452
|
-
}, [])
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
}
|
|
552
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeService, decorators: [{
|
|
553
|
+
type: Injectable
|
|
554
|
+
}], ctorParameters: () => [{ type: NestService }, { type: undefined, decorators: [{
|
|
555
|
+
type: Inject,
|
|
556
|
+
args: ['QUERY_PARAMS_CONFIG']
|
|
557
|
+
}, {
|
|
558
|
+
type: Optional
|
|
559
|
+
}] }] });
|
|
456
560
|
|
|
457
561
|
class ResponseOptions {
|
|
458
562
|
constructor(options) {
|
|
@@ -478,41 +582,89 @@ class PaginationService {
|
|
|
478
582
|
paginate(response) {
|
|
479
583
|
return new PaginatedCollection(response[this._options.data], response[this._options.currentPage], response[this._options.from], response[this._options.to], response[this._options.total], response[this._options.perPage], response[this._options.prevPageUrl], response[this._options.nextPageUrl], response[this._options.lastPage], response[this._options.firstPageUrl], response[this._options.lastPageUrl]);
|
|
480
584
|
}
|
|
585
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: PaginationService, deps: [{ token: 'RESPONSE_OPTIONS', optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
586
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: PaginationService }); }
|
|
481
587
|
}
|
|
482
|
-
PaginationService
|
|
483
|
-
|
|
484
|
-
]
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
588
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: PaginationService, decorators: [{
|
|
589
|
+
type: Injectable
|
|
590
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
591
|
+
type: Inject,
|
|
592
|
+
args: ['RESPONSE_OPTIONS']
|
|
593
|
+
}, {
|
|
594
|
+
type: Optional
|
|
595
|
+
}] }] });
|
|
488
596
|
|
|
489
|
-
const ɵ0$1 = (store) => new NgQubeeService(store, {});
|
|
490
597
|
// @dynamic
|
|
491
598
|
class NgQubeeModule {
|
|
492
599
|
static forRoot(config = {}) {
|
|
493
600
|
return {
|
|
494
601
|
ngModule: NgQubeeModule,
|
|
495
|
-
providers: [
|
|
496
|
-
|
|
602
|
+
providers: [
|
|
603
|
+
NestService,
|
|
604
|
+
{
|
|
605
|
+
deps: [NestService],
|
|
497
606
|
provide: NgQubeeService,
|
|
498
|
-
useFactory: (
|
|
607
|
+
useFactory: (nestService) => new NgQubeeService(nestService, Object.assign({}, config.request))
|
|
499
608
|
}, {
|
|
500
609
|
provide: PaginationService,
|
|
501
|
-
useFactory: () => new PaginationService(Object.assign({},
|
|
502
|
-
}
|
|
610
|
+
useFactory: () => new PaginationService(Object.assign({}, config.response))
|
|
611
|
+
}
|
|
612
|
+
]
|
|
503
613
|
};
|
|
504
614
|
}
|
|
615
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
616
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeModule }); }
|
|
617
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeModule, providers: [{
|
|
618
|
+
deps: [NestService],
|
|
619
|
+
provide: NgQubeeService,
|
|
620
|
+
useFactory: (nestService) => new NgQubeeService(nestService, {})
|
|
621
|
+
}] }); }
|
|
622
|
+
}
|
|
623
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.3", ngImport: i0, type: NgQubeeModule, decorators: [{
|
|
624
|
+
type: NgModule,
|
|
625
|
+
args: [{
|
|
626
|
+
providers: [{
|
|
627
|
+
deps: [NestService],
|
|
628
|
+
provide: NgQubeeService,
|
|
629
|
+
useFactory: (nestService) => new NgQubeeService(nestService, {})
|
|
630
|
+
}]
|
|
631
|
+
}]
|
|
632
|
+
}] });
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Sets up providers necessary to enable `NgQubee` functionality for the application.
|
|
636
|
+
*
|
|
637
|
+
* @usageNotes
|
|
638
|
+
*
|
|
639
|
+
* Basic example of how you can add NgQubee to your application:
|
|
640
|
+
* ```
|
|
641
|
+
* const config = {};
|
|
642
|
+
*
|
|
643
|
+
* bootstrapApplication(AppComponent, {
|
|
644
|
+
* providers: [provideNgQubee(config)]
|
|
645
|
+
* });
|
|
646
|
+
* ```
|
|
647
|
+
*
|
|
648
|
+
* @publicApi
|
|
649
|
+
* @param config Configuration object compliant to the IConfig interface
|
|
650
|
+
* @returns A set of providers to setup NgQubee
|
|
651
|
+
*/
|
|
652
|
+
function provideNgQubee(config = {}) {
|
|
653
|
+
return makeEnvironmentProviders([
|
|
654
|
+
{
|
|
655
|
+
provide: NestService,
|
|
656
|
+
useClass: NestService
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
deps: [NestService],
|
|
660
|
+
provide: NgQubeeService,
|
|
661
|
+
useFactory: (nestService) => new NgQubeeService(nestService, Object.assign({}, config.request))
|
|
662
|
+
}, {
|
|
663
|
+
provide: PaginationService,
|
|
664
|
+
useFactory: () => new PaginationService(Object.assign({}, config.response))
|
|
665
|
+
}
|
|
666
|
+
]);
|
|
505
667
|
}
|
|
506
|
-
NgQubeeModule._config = {};
|
|
507
|
-
NgQubeeModule.decorators = [
|
|
508
|
-
{ type: NgModule, args: [{
|
|
509
|
-
providers: [{
|
|
510
|
-
deps: [StoreService],
|
|
511
|
-
provide: NgQubeeService,
|
|
512
|
-
useFactory: ɵ0$1
|
|
513
|
-
}]
|
|
514
|
-
},] }
|
|
515
|
-
];
|
|
516
668
|
|
|
517
669
|
/*
|
|
518
670
|
* Public API Surface of angular-query-builder
|
|
@@ -522,5 +674,5 @@ NgQubeeModule.decorators = [
|
|
|
522
674
|
* Generated bundle index. Do not edit.
|
|
523
675
|
*/
|
|
524
676
|
|
|
525
|
-
export { NgQubeeModule, NgQubeeService, PaginatedCollection, PaginationService,
|
|
526
|
-
//# sourceMappingURL=ng-qubee.
|
|
677
|
+
export { NgQubeeModule, NgQubeeService, PaginatedCollection, PaginationService, provideNgQubee };
|
|
678
|
+
//# sourceMappingURL=ng-qubee.mjs.map
|