@weapnl/js-junction 0.0.1

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.
Files changed (43) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/README.md +348 -0
  3. package/babel.config.json +5 -0
  4. package/dist/index.js +4369 -0
  5. package/docker-compose.yml +14 -0
  6. package/index.d.ts +150 -0
  7. package/package.json +34 -0
  8. package/src/api.js +226 -0
  9. package/src/batch.js +39 -0
  10. package/src/builder/caster.js +67 -0
  11. package/src/builder/model.js +259 -0
  12. package/src/builder/properties/accessors.js +116 -0
  13. package/src/builder/properties/attributes.js +118 -0
  14. package/src/builder/properties/counts.js +79 -0
  15. package/src/builder/properties/property.js +37 -0
  16. package/src/builder/properties/relations.js +124 -0
  17. package/src/connection.js +83 -0
  18. package/src/filters/count.js +27 -0
  19. package/src/filters/filter.js +9 -0
  20. package/src/filters/filters.js +33 -0
  21. package/src/filters/limit.js +27 -0
  22. package/src/filters/order.js +30 -0
  23. package/src/filters/pluck.js +28 -0
  24. package/src/filters/relations.js +27 -0
  25. package/src/filters/scopes.js +30 -0
  26. package/src/filters/search.js +34 -0
  27. package/src/filters/whereIn.js +31 -0
  28. package/src/filters/wheres.js +32 -0
  29. package/src/index.js +12 -0
  30. package/src/mixins/actionMixin.js +20 -0
  31. package/src/mixins/filterMixin.js +104 -0
  32. package/src/mixins/modifierMixin.js +22 -0
  33. package/src/mixins/paginationMixin.js +20 -0
  34. package/src/modifiers/appends.js +28 -0
  35. package/src/modifiers/hiddenFields.js +27 -0
  36. package/src/modifiers/modifier.js +9 -0
  37. package/src/modifiers/modifiers.js +19 -0
  38. package/src/request/action.js +29 -0
  39. package/src/request/pagination.js +35 -0
  40. package/src/request.js +317 -0
  41. package/src/response.js +33 -0
  42. package/src/utilities/format.js +11 -0
  43. package/webpack.config.js +28 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @mixin paginationMixin
3
+ */
4
+ const paginationMixin = {
5
+ /**
6
+ * @param {int} page
7
+ * @param {int} [perPage]
8
+ * @param {null|int} [findPageForId] Find the page the given id is on.
9
+ * @returns {this}
10
+ */
11
+ pagination (page, perPage = 25, findPageForId = null) {
12
+ this._pagination.page(page);
13
+ this._pagination.perPage(perPage);
14
+ this._pagination.findPageForId(findPageForId);
15
+
16
+ return this;
17
+ },
18
+ };
19
+
20
+ export default paginationMixin;
@@ -0,0 +1,28 @@
1
+ import Modifier from './modifier';
2
+ import Format from '../utilities/format';
3
+
4
+ export default class Appends extends Modifier {
5
+ constructor () {
6
+ super();
7
+
8
+ this._appends = [];
9
+ }
10
+
11
+ filled () {
12
+ return this._appends.length > 0;
13
+ }
14
+
15
+ add (appends) {
16
+ this._appends.push(..._.map(appends, Format.snakeCase));
17
+ }
18
+
19
+ toObject () {
20
+ const data = {};
21
+
22
+ if (this.filled()) {
23
+ data.appends = this._appends;
24
+ }
25
+
26
+ return data;
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ import Modifier from './modifier';
2
+
3
+ export default class HiddenFields extends Modifier {
4
+ constructor () {
5
+ super();
6
+
7
+ this._fields = [];
8
+ }
9
+
10
+ filled () {
11
+ return this._fields.length > 0;
12
+ }
13
+
14
+ add (fields) {
15
+ this._fields.push(...fields);
16
+ }
17
+
18
+ toObject () {
19
+ const data = {};
20
+
21
+ if (this.filled()) {
22
+ data.hidden_fields = this._fields;
23
+ }
24
+
25
+ return data;
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ export default class Modifier {
2
+ filled () {
3
+ return !! this.toObject();
4
+ }
5
+
6
+ toObject () {
7
+ return null;
8
+ }
9
+ }
@@ -0,0 +1,19 @@
1
+ import Appends from './appends';
2
+ import HiddenFields from './hiddenFields';
3
+
4
+ export default class Modifiers {
5
+ constructor () {
6
+ this.appends = new Appends();
7
+ this.hiddenFields = new HiddenFields();
8
+ }
9
+
10
+ toObject () {
11
+ const items = [];
12
+
13
+ for (let i = 0, modifiers = ['appends', 'hiddenFields']; i < modifiers.length; i++) {
14
+ if (this[modifiers[i]].filled()) items.push(this[modifiers[i]].toObject());
15
+ }
16
+
17
+ return _.merge(...items);
18
+ }
19
+ }
@@ -0,0 +1,29 @@
1
+ export default class Action {
2
+ constructor () {
3
+ this._name = null;
4
+ this._id = null;
5
+ }
6
+
7
+ filled () {
8
+ return !! this._name;
9
+ }
10
+
11
+ name (name) {
12
+ this._name = name;
13
+ }
14
+
15
+ id (id) {
16
+ this._id = id;
17
+ }
18
+
19
+ toObject () {
20
+ if (! this.filled()) return null;
21
+
22
+ const data = {};
23
+
24
+ data.action = this._name;
25
+ if (this._id) data.id = this._id;
26
+
27
+ return data;
28
+ }
29
+ }
@@ -0,0 +1,35 @@
1
+ export default class Pagination {
2
+ constructor () {
3
+ this._page = null;
4
+ this._perPage = null;
5
+ this._findPageForId = null;
6
+ }
7
+
8
+ filled () {
9
+ return this._perPage && (this._page || this._findPageForId);
10
+ }
11
+
12
+ page (page) {
13
+ this._page = page;
14
+ }
15
+
16
+ perPage (perPage) {
17
+ this._perPage = perPage;
18
+ }
19
+
20
+ findPageForId (id) {
21
+ this._findPageForId = id;
22
+ }
23
+
24
+ toObject () {
25
+ const data = {};
26
+
27
+ if (this.filled()) {
28
+ data.page = this._page;
29
+ data.paginate = this._perPage;
30
+ data.page_for_id = this._findPageForId;
31
+ }
32
+
33
+ return data;
34
+ }
35
+ }
package/src/request.js ADDED
@@ -0,0 +1,317 @@
1
+ import Action from './request/action';
2
+ import Connection from './connection';
3
+ import Filters from './filters/filters';
4
+ import Modifiers from './modifiers/modifiers';
5
+ import Pagination from './request/pagination';
6
+
7
+ import actionMixin from './mixins/actionMixin';
8
+ import filterMixin from './mixins/filterMixin';
9
+ import modifierMixin from './mixins/modifierMixin';
10
+ import paginationMixin from './mixins/paginationMixin';
11
+
12
+ /**
13
+ * @mixes actionMixin
14
+ * @mixes filterMixin
15
+ * @mixes modifierMixin
16
+ * @mixes paginationMixin
17
+ */
18
+ export default class Request {
19
+ constructor () {
20
+ this.url = null;
21
+
22
+ this._action = new Action();
23
+ this._filters = new Filters();
24
+ this._modifiers = new Modifiers();
25
+ this._pagination = new Pagination();
26
+ this._customParameters = [];
27
+
28
+ this._onSuccess = () => {};
29
+ this._onError = () => {};
30
+ this._onValidationError = () => {};
31
+ this._onUnauthorized = () => {};
32
+ this._onForbidden = () => {};
33
+
34
+ this._connection = new Connection();
35
+
36
+ this._response = null;
37
+ }
38
+
39
+ get response () {
40
+ return this._response;
41
+ }
42
+
43
+ /**
44
+ * @param {string} url
45
+ *
46
+ * @returns {this} The current instance.
47
+ */
48
+ setUrl (url) {
49
+ this.url = url;
50
+
51
+ return this;
52
+ }
53
+
54
+ /**
55
+ * @returns {this} The current instance.
56
+ */
57
+ cancel () {
58
+ this._connection.cancel();
59
+
60
+ return this;
61
+ }
62
+
63
+ /**
64
+ * @returns {this} The current instance.
65
+ */
66
+ async get () {
67
+ const url = this.url ?? this.constructor.endpoint;
68
+
69
+ this._response = await this._connection.get(
70
+ `${url}`,
71
+ this.bodyParameters,
72
+ );
73
+
74
+ await this.triggerResponseEvents(this._response);
75
+
76
+ return this;
77
+ }
78
+
79
+ /**
80
+ * @param {Object} data
81
+ *
82
+ * @returns {this} The current instance.
83
+ */
84
+ async post (data = {}) {
85
+ const url = this.url ?? this.constructor.endpoint;
86
+
87
+ this._response = await this._connection.post(
88
+ `${url}`,
89
+ data,
90
+ );
91
+
92
+ await this.triggerResponseEvents(this._response);
93
+
94
+ return this;
95
+ }
96
+
97
+ /**
98
+ * @param {Object} data
99
+ *
100
+ * @returns {this} The current instance.
101
+ */
102
+ async put (data = {}) {
103
+ const url = this.url ?? this.constructor.endpoint;
104
+
105
+ this._response = await this._connection.put(
106
+ `${url}`,
107
+ { ...data, ...this.bodyParameters },
108
+ );
109
+
110
+ await this.triggerResponseEvents(this._response);
111
+
112
+ return this;
113
+ }
114
+
115
+ /**
116
+ * @returns {this} The current instance.
117
+ */
118
+ async delete () {
119
+ const url = this.url ?? this.constructor.endpoint;
120
+
121
+ this._response = await this._connection.delete(
122
+ `${url}`,
123
+ );
124
+
125
+ await this.triggerResponseEvents(this._response);
126
+
127
+ return this;
128
+ }
129
+
130
+ /**
131
+ * @param {Object} files
132
+ * @param {Object} data
133
+ *
134
+ * @returns {this} The current instance.
135
+ */
136
+ async storeFiles (files = {}, data = {}) {
137
+ const url = this.url ?? this.constructor.endpoint;
138
+
139
+ this._connection.setConfig({
140
+ headers: {
141
+ 'Content-Type': 'multipart/form-data',
142
+ },
143
+ });
144
+
145
+ const formData = this._createFormData(_.merge({}, files, data));
146
+
147
+ this._response = await this._connection.post(
148
+ `${url}?${this.bodyParameters}`,
149
+ formData,
150
+ );
151
+
152
+ await this.triggerResponseEvents(this._response);
153
+
154
+ return this;
155
+ }
156
+
157
+ /**
158
+ * @returns {Object} Filter and modifier query parameters.
159
+ */
160
+ get bodyParameters () {
161
+ return _.merge(..._.compact([
162
+ this._filters.toObject(),
163
+ this._modifiers.toObject(),
164
+ this._pagination.toObject(),
165
+ this._action.toObject(),
166
+ ...this._customParameters,
167
+ ]));
168
+ }
169
+
170
+ /**
171
+ * @param {function(Response.data)} callback
172
+ *
173
+ * @returns {this} The current instance.
174
+ */
175
+ onSuccess (callback = () => {}) {
176
+ this._onSuccess = callback;
177
+
178
+ return this;
179
+ }
180
+
181
+ /**
182
+ * @param {function(Response)} callback
183
+ *
184
+ * @returns {this} The current instance.
185
+ */
186
+ onError (callback = () => {}) {
187
+ this._onError = callback;
188
+
189
+ return this;
190
+ }
191
+
192
+ /**
193
+ * @param {function(Response.validation)} callback
194
+ *
195
+ * @returns {this} The current instance.
196
+ */
197
+ onValidationError (callback = () => {}) {
198
+ this._onValidationError = callback;
199
+
200
+ return this;
201
+ }
202
+
203
+ /**
204
+ * @param {function(Response)} callback
205
+ *
206
+ * @returns {this} The current instance.
207
+ */
208
+ onUnauthorized (callback = () => {}) {
209
+ this._onUnauthorized = callback;
210
+
211
+ return this;
212
+ }
213
+
214
+ /**
215
+ * @param {function(Response)} callback
216
+ *
217
+ * @returns {this} The current instance.
218
+ */
219
+ onForbidden (callback = () => {}) {
220
+ this._onForbidden = callback;
221
+
222
+ return this;
223
+ }
224
+
225
+ /**
226
+ * @param {Response} response
227
+ * @param {*} successResponse
228
+ */
229
+ async triggerResponseEvents (response, successResponse = null) {
230
+ if (response.statusCode >= 200 && response.statusCode < 300) {
231
+ if (! this._onSuccess) return;
232
+
233
+ return await this._onSuccess(...[successResponse, response.data].filter((value) => !! value));
234
+ }
235
+
236
+ switch (response.statusCode) {
237
+ case 401:
238
+ if (this._onUnauthorized) await this._onUnauthorized(response);
239
+ break;
240
+ case 403:
241
+ if (this._onForbidden) await this._onForbidden(response);
242
+ break;
243
+ case 422:
244
+ const validation = {
245
+ message: response.validation.message,
246
+ errors: {},
247
+ };
248
+
249
+ _.each(response.validation.errors, (value, key) => {
250
+ return _.set(validation.errors, key, value);
251
+ });
252
+
253
+ if (this._onValidationError) await this._onValidationError(validation);
254
+ break;
255
+ default:
256
+ if (this._onError) await this._onError(response);
257
+ break;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Add custom parameters to the request.
263
+ *
264
+ * @param {Array} parameters
265
+ *
266
+ * @returns {this} The current instance.
267
+ */
268
+ customParameters (parameters = []) {
269
+ this._customParameters.push(...parameters);
270
+
271
+ return this;
272
+ }
273
+
274
+ /**
275
+ * Convert data to FormData.
276
+ *
277
+ * @param {Object} data
278
+ *
279
+ * @returns {FormData}
280
+ */
281
+ _createFormData (data = {}) {
282
+ const formData = new FormData();
283
+
284
+ function appendFormData (data, name) {
285
+ name = name || '';
286
+
287
+ if (data instanceof File) {
288
+ formData.append(name, data);
289
+ } else if (data === true || data === false) {
290
+ formData.append(name, data ? '1' : '0');
291
+ } else if (_.isArray(data) || _.isObject(data)) {
292
+ if (_.size(data) <= 0) {
293
+ formData.append(name, '');
294
+ } else {
295
+ _.forOwn(data, (dataItem, key) => {
296
+ const newName = name === ''
297
+ ? key
298
+ : name + '[' + key + ']';
299
+
300
+ appendFormData(dataItem, newName);
301
+ });
302
+ }
303
+ } else {
304
+ formData.append(name, data);
305
+ }
306
+ }
307
+
308
+ appendFormData(data);
309
+
310
+ return formData;
311
+ }
312
+ }
313
+
314
+ Object.assign(Request.prototype, actionMixin);
315
+ Object.assign(Request.prototype, filterMixin);
316
+ Object.assign(Request.prototype, modifierMixin);
317
+ Object.assign(Request.prototype, paginationMixin);
@@ -0,0 +1,33 @@
1
+ export default class Response {
2
+ constructor () {
3
+ this._axiosResponse = null;
4
+
5
+ this.statusCode = null;
6
+
7
+ this.data = null;
8
+
9
+ this.validation = null;
10
+ }
11
+
12
+ get failed () {
13
+ return this.statusCode >= 400;
14
+ }
15
+
16
+ set (statusCode, axiosResponse) {
17
+ this._axiosResponse = axiosResponse;
18
+
19
+ this.statusCode = statusCode;
20
+
21
+ switch (this.statusCode) {
22
+ case 200:
23
+ this.data = this._axiosResponse.data;
24
+ break;
25
+ case 400:
26
+ this.data = this._axiosResponse.response.data;
27
+ break;
28
+ case 422:
29
+ this.validation = this._axiosResponse.response.data;
30
+ break;
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,11 @@
1
+ export default class Format {
2
+ static snakeCase (value) {
3
+ const relations = _.split(value, '.');
4
+ const attribute = relations.pop();
5
+
6
+ return _.join([
7
+ ...relations,
8
+ _.snakeCase(attribute),
9
+ ], '.');
10
+ }
11
+ }
@@ -0,0 +1,28 @@
1
+ const path = require('path');
2
+ const webpack = require('webpack');
3
+
4
+ module.exports = {
5
+ entry: ['babel-polyfill', path.resolve(__dirname, 'src/index.js')],
6
+ output: {
7
+ path: path.resolve(__dirname, 'dist'),
8
+ filename: 'index.js',
9
+ library: 'Api',
10
+ libraryTarget: 'umd',
11
+ },
12
+ plugins: [
13
+ new webpack.ProvidePlugin({
14
+ _: 'lodash',
15
+ axios: 'axios',
16
+ }),
17
+ ],
18
+ module: {
19
+ rules: [
20
+ {
21
+ test: /\.(js)$/,
22
+ exclude: /node_modules/,
23
+ use: 'babel-loader',
24
+ },
25
+ ],
26
+ },
27
+ mode: 'development',
28
+ };