@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,124 @@
1
+ import Caster from '../caster';
2
+
3
+ /**
4
+ * @implements {Property}
5
+ */
6
+ export default class Relations {
7
+ /**
8
+ * @param {Model} model Instance of the model.
9
+ */
10
+ constructor (model) {
11
+ this.model = model;
12
+
13
+ _.each(model.constructor.relations(), (options, key) => {
14
+ this.set(key, _.has(options, 'default') ? options.default : null);
15
+ });
16
+ }
17
+
18
+ /**
19
+ * @param {Object} json.
20
+ */
21
+ fromJson (json) {
22
+ _.each(this.model.constructor.relations(), (options, key) => {
23
+ let value = _.get(json, options.jsonKey ?? _.snakeCase(key), _.get(json, _.camelCase(key)));
24
+
25
+ value = value
26
+ ? Relations._getCastedFromJsonValue(value, options)
27
+ : value;
28
+
29
+ this.set(key, value);
30
+ });
31
+ }
32
+
33
+ /**
34
+ * @return {Object} The attributes casted to a json object.
35
+ */
36
+ toJson () {
37
+ const json = {};
38
+
39
+ _.each(this.model.constructor.relations(), (options, key) => {
40
+ let jsonValue = this.get(key);
41
+
42
+ jsonValue = Relations._getCastedToJsonValue(jsonValue, options);
43
+
44
+ _.set(json, options.jsonKey ?? _.snakeCase(key), jsonValue);
45
+ });
46
+
47
+ return json;
48
+ }
49
+
50
+ /**
51
+ * @param {string} relation
52
+ *
53
+ * @returns {*} The value of the relation.
54
+ */
55
+ get (relation) {
56
+ return _.get(this.model, relation);
57
+ }
58
+
59
+ /**
60
+ * @param {string|Object} relation
61
+ * @param {*} value
62
+ *
63
+ * @returns {Relations}
64
+ */
65
+ set (relation, value = null) {
66
+ if (_.isObject(relation)) {
67
+ _.each(this.model.constructor.relations(), (options, key) => {
68
+ if (! _.has(relation, key)) return;
69
+
70
+ this.set(key, relation[key]);
71
+ });
72
+
73
+ return this;
74
+ }
75
+
76
+ this.model[relation] = value;
77
+
78
+ return this;
79
+ }
80
+
81
+ /**
82
+ * @private
83
+ *
84
+ * @param {*} value
85
+ * @param {Object} options
86
+ *
87
+ * @returns {*} The casted value.
88
+ */
89
+ static _getCastedFromJsonValue (value, options) {
90
+ if (_.has(options, 'type')) {
91
+ const cast = options.type;
92
+
93
+ if (_.isArray(value)) {
94
+ return _.map(value, (val) => Caster.fromJson(cast, val));
95
+ } else {
96
+ return Caster.fromJson(cast, value);
97
+ }
98
+ }
99
+
100
+ return value;
101
+ }
102
+
103
+ /**
104
+ * @private
105
+ *
106
+ * @param {*} value
107
+ * @param {Object} options
108
+ *
109
+ * @returns {*} The casted value.
110
+ */
111
+ static _getCastedToJsonValue (value, options) {
112
+ if (_.has(options, 'type')) {
113
+ const cast = options.type;
114
+
115
+ if (_.isArray(value)) {
116
+ return _.map(value, (val) => Caster.toJson(cast, val));
117
+ } else {
118
+ return Caster.toJson(cast, value);
119
+ }
120
+ }
121
+
122
+ return value;
123
+ }
124
+ }
@@ -0,0 +1,83 @@
1
+ import Response from './response';
2
+ import axios from 'axios';
3
+
4
+ export default class Connection {
5
+ constructor () {
6
+ this._abortController = null;
7
+
8
+ this._config = {};
9
+
10
+ this.running = false;
11
+ this.canceled = false;
12
+ this.failed = false;
13
+ }
14
+
15
+ cancel () {
16
+ if (! this._abortController) return this;
17
+
18
+ this._abortController.abort();
19
+
20
+ this.canceled = true;
21
+ }
22
+
23
+ setConfig (config) {
24
+ this._config = config;
25
+ }
26
+
27
+ async get (query, params) {
28
+ return this._execute(query, 'get', params);
29
+ }
30
+
31
+ async post (query, data) {
32
+ return this._execute(query, 'post', data);
33
+ }
34
+
35
+ async put (query, params) {
36
+ return this._execute(query, 'put', params);
37
+ }
38
+
39
+ async delete (query) {
40
+ return this._execute(query, 'delete');
41
+ }
42
+
43
+ async _execute (url, method, data) {
44
+ this.running = true;
45
+
46
+ if (! _.startsWith(url, '/')) {
47
+ url = `/${url}`;
48
+ }
49
+
50
+ const config = {
51
+ url: api.baseUrl + url,
52
+ method,
53
+ ...({
54
+ [method === 'get' ? 'params' : 'data']: data,
55
+ }),
56
+ signal: (this._abortController = new AbortController()).signal,
57
+ };
58
+
59
+ const request = axios(Object.assign(config, this._config));
60
+ const response = new Response();
61
+
62
+ await request
63
+ .then((axiosResponse) => {
64
+ response.set(axiosResponse.status, axiosResponse);
65
+ })
66
+ .catch((error) => {
67
+ this.failed = true;
68
+
69
+ let statusCode = 0;
70
+
71
+ if (error.response) {
72
+ statusCode = error.response.status;
73
+ }
74
+
75
+ response.set(statusCode, error);
76
+ })
77
+ .finally(() => {
78
+ this.running = false;
79
+ });
80
+
81
+ return response;
82
+ }
83
+ }
@@ -0,0 +1,27 @@
1
+ import Filter from './filter';
2
+
3
+ export default class Count extends Filter {
4
+ constructor () {
5
+ super();
6
+
7
+ this._relations = [];
8
+ }
9
+
10
+ filled () {
11
+ return this._relations.length > 0;
12
+ }
13
+
14
+ add (relations) {
15
+ this._relations.push(...relations);
16
+ }
17
+
18
+ toObject () {
19
+ const data = {};
20
+
21
+ if (this.filled()) {
22
+ data.count = this._relations;
23
+ }
24
+
25
+ return data;
26
+ }
27
+ }
@@ -0,0 +1,9 @@
1
+ export default class Filter {
2
+ filled () {
3
+ return !! this.toObject();
4
+ }
5
+
6
+ toObject () {
7
+ return null;
8
+ }
9
+ }
@@ -0,0 +1,33 @@
1
+ import Limit from './limit';
2
+ import Order from './order';
3
+ import Relations from './relations';
4
+ import Scopes from './scopes';
5
+ import Search from './search';
6
+ import Wheres from './wheres';
7
+ import WhereIn from './whereIn';
8
+ import Count from './count';
9
+ import Pluck from './pluck';
10
+
11
+ export default class Filters {
12
+ constructor () {
13
+ this.count = new Count();
14
+ this.limit = new Limit();
15
+ this.order = new Order();
16
+ this.relations = new Relations();
17
+ this.scopes = new Scopes();
18
+ this.search = new Search();
19
+ this.wheres = new Wheres();
20
+ this.whereIn = new WhereIn();
21
+ this.pluck = new Pluck();
22
+ }
23
+
24
+ toObject () {
25
+ const items = [];
26
+
27
+ for (let i = 0, filters = ['count', 'limit', 'order', 'relations', 'scopes', 'search', 'wheres', 'whereIn', 'pluck']; i < filters.length; i++) {
28
+ if (this[filters[i]].filled()) items.push(this[filters[i]].toObject());
29
+ }
30
+
31
+ return _.merge(...items);
32
+ }
33
+ }
@@ -0,0 +1,27 @@
1
+ import Filter from './filter';
2
+
3
+ export default class Limit extends Filter {
4
+ constructor () {
5
+ super();
6
+
7
+ this._amount = null;
8
+ }
9
+
10
+ filled () {
11
+ return !! this._amount;
12
+ }
13
+
14
+ amount (amount) {
15
+ this._amount = amount;
16
+ }
17
+
18
+ toObject () {
19
+ const data = {};
20
+
21
+ if (this.filled()) {
22
+ data.limit = this._amount;
23
+ }
24
+
25
+ return data;
26
+ }
27
+ }
@@ -0,0 +1,30 @@
1
+ import Filter from './filter';
2
+
3
+ export default class Order extends Filter {
4
+ constructor () {
5
+ super();
6
+
7
+ this._orders = [];
8
+ }
9
+
10
+ filled () {
11
+ return this._orders.length > 0;
12
+ }
13
+
14
+ add (column, direction) {
15
+ this._orders.push({
16
+ column,
17
+ direction,
18
+ });
19
+ }
20
+
21
+ toObject () {
22
+ const data = {};
23
+
24
+ if (this.filled()) {
25
+ data.orders = this._orders;
26
+ }
27
+
28
+ return data;
29
+ }
30
+ }
@@ -0,0 +1,28 @@
1
+ import Filter from './filter';
2
+ import Format from '../utilities/format';
3
+
4
+ export default class Pluck extends Filter {
5
+ constructor () {
6
+ super();
7
+
8
+ this._fields = [];
9
+ }
10
+
11
+ filled () {
12
+ return this._fields.length > 0;
13
+ }
14
+
15
+ add (fields) {
16
+ this._fields.push(..._.map(fields, Format.snakeCase));
17
+ }
18
+
19
+ toObject () {
20
+ const data = {};
21
+
22
+ if (this.filled()) {
23
+ data.pluck = this._fields;
24
+ }
25
+
26
+ return data;
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ import Filter from './filter';
2
+
3
+ export default class Relations extends Filter {
4
+ constructor () {
5
+ super();
6
+
7
+ this._relations = [];
8
+ }
9
+
10
+ filled () {
11
+ return this._relations.length > 0;
12
+ }
13
+
14
+ add (relations) {
15
+ this._relations.push(...relations);
16
+ }
17
+
18
+ toObject () {
19
+ const data = {};
20
+
21
+ if (this.filled()) {
22
+ data.with = this._relations;
23
+ }
24
+
25
+ return data;
26
+ }
27
+ }
@@ -0,0 +1,30 @@
1
+ import Filter from './filter';
2
+
3
+ export default class Relations extends Filter {
4
+ constructor () {
5
+ super();
6
+
7
+ this._scopes = [];
8
+ }
9
+
10
+ filled () {
11
+ return this._scopes.length > 0;
12
+ }
13
+
14
+ add (name, params) {
15
+ this._scopes.push({
16
+ name,
17
+ params,
18
+ });
19
+ }
20
+
21
+ toObject () {
22
+ const data = {};
23
+
24
+ if (this.filled()) {
25
+ data.scopes = this._scopes;
26
+ }
27
+
28
+ return data;
29
+ }
30
+ }
@@ -0,0 +1,34 @@
1
+ import Filter from './filter';
2
+ import Format from '../utilities/format';
3
+
4
+ export default class Search extends Filter {
5
+ constructor () {
6
+ super();
7
+
8
+ this._value = null;
9
+ this._columns = null;
10
+ }
11
+
12
+ filled () {
13
+ return this._value;
14
+ }
15
+
16
+ value (value) {
17
+ this._value = value;
18
+ }
19
+
20
+ columns (columns) {
21
+ this._columns = _.map(columns, Format.snakeCase);
22
+ }
23
+
24
+ toObject () {
25
+ const data = {};
26
+
27
+ if (this.filled()) {
28
+ data.search_value = this._value;
29
+ data.search_columns = this._columns;
30
+ }
31
+
32
+ return data;
33
+ }
34
+ }
@@ -0,0 +1,31 @@
1
+ import Filter from './filter';
2
+ import Format from '../utilities/format';
3
+
4
+ export default class Relations extends Filter {
5
+ constructor () {
6
+ super();
7
+
8
+ this._whereIns = [];
9
+ }
10
+
11
+ filled () {
12
+ return this._whereIns.length > 0;
13
+ }
14
+
15
+ add (column, values) {
16
+ this._whereIns.push({
17
+ column: Format.snakeCase(column),
18
+ values,
19
+ });
20
+ }
21
+
22
+ toObject () {
23
+ const data = {};
24
+
25
+ if (this.filled()) {
26
+ data.where_in = this._whereIns;
27
+ }
28
+
29
+ return data;
30
+ }
31
+ }
@@ -0,0 +1,32 @@
1
+ import Filter from './filter';
2
+ import Format from '../utilities/format';
3
+
4
+ export default class Wheres extends Filter {
5
+ constructor () {
6
+ super();
7
+
8
+ this._wheres = [];
9
+ }
10
+
11
+ filled () {
12
+ return this._wheres.length > 0;
13
+ }
14
+
15
+ add (column, operator, value) {
16
+ this._wheres.push({
17
+ column: Format.snakeCase(column),
18
+ operator,
19
+ value,
20
+ });
21
+ }
22
+
23
+ toObject () {
24
+ const data = {};
25
+
26
+ if (this.filled()) {
27
+ data.wheres = this._wheres;
28
+ }
29
+
30
+ return data;
31
+ }
32
+ }
package/src/index.js ADDED
@@ -0,0 +1,12 @@
1
+ import _ from 'lodash';
2
+ import Api from './api';
3
+ import Model from './builder/model';
4
+
5
+ window._ = _;
6
+
7
+ const api = new Api();
8
+ window.api = api;
9
+
10
+ export { Model };
11
+
12
+ export default api;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @mixin actionMixin
3
+ */
4
+ const actionMixin = {
5
+ /**
6
+ * @param {string} name
7
+ * @param {int} [id]
8
+ * @returns {this}
9
+ */
10
+ action (name, id) {
11
+ id ??= this._identifier;
12
+
13
+ this._action.name(name);
14
+ this._action.id(id);
15
+
16
+ return this;
17
+ },
18
+ };
19
+
20
+ export default actionMixin;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * @mixin filterMixin
3
+ */
4
+ const filterMixin = {
5
+ count (relations) {
6
+ if (! Array.isArray(relations)) relations = [relations];
7
+
8
+ this._filters.count.add(relations);
9
+
10
+ return this;
11
+ },
12
+
13
+ limit (amount) {
14
+ this._filters.limit.amount(amount);
15
+
16
+ return this;
17
+ },
18
+
19
+ order (input, direction = 'asc') {
20
+ // If a single column name (string) is specified
21
+ if (typeof input === 'string') {
22
+ this._filters.order.add(_.snakeCase(input), direction);
23
+ }
24
+
25
+ // If there is an array input
26
+ else if (Array.isArray(input)) {
27
+ input.forEach(item => {
28
+ // If the item is a string (single column name)
29
+ if (typeof item === 'string') {
30
+ this._filters.order.add(_.snakeCase(input), 'asc');
31
+ }
32
+
33
+ // If the item is an array ([column name, direction])
34
+ else if (Array.isArray(item)) {
35
+ const [column, direction = 'asc'] = item; // default value for dir is 'asc' if not specified
36
+
37
+ this._filters.order.add(_.snakeCase(column), direction);
38
+ }
39
+ });
40
+ }
41
+
42
+ return this;
43
+ },
44
+
45
+ with (relations) {
46
+ if (! Array.isArray(relations)) relations = [relations];
47
+
48
+ this._filters.relations.add(relations);
49
+
50
+ return this;
51
+ },
52
+
53
+ scope (name, ...params) {
54
+ this._filters.scopes.add(name, params);
55
+
56
+ return this;
57
+ },
58
+
59
+ search (value, columns = []) {
60
+ if (! Array.isArray(columns)) columns = [columns];
61
+
62
+ this._filters.search.value(value);
63
+ this._filters.search.columns(columns);
64
+
65
+ return this;
66
+ },
67
+
68
+ where (column, operator, value) {
69
+ if (arguments.length === 2) {
70
+ value = operator;
71
+ operator = '=';
72
+ }
73
+
74
+ this._filters.wheres.add(column, operator, value);
75
+
76
+ return this;
77
+ },
78
+
79
+ wheres (...params) {
80
+ return this.where(...params);
81
+ },
82
+
83
+ whereIn (column, values) {
84
+ if (! Array.isArray(values)) values = [values];
85
+
86
+ this._filters.whereIn.add(column, values);
87
+
88
+ return this;
89
+ },
90
+
91
+ whereIns (...params) {
92
+ return this.whereIn(...params);
93
+ },
94
+
95
+ pluck (fields) {
96
+ if (! Array.isArray(fields)) fields = [fields];
97
+
98
+ this._filters.pluck.add(fields);
99
+
100
+ return this;
101
+ },
102
+ };
103
+
104
+ export default filterMixin;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @mixin modifierMixin
3
+ */
4
+ const modifierMixin = {
5
+ appends (appends) {
6
+ if (! Array.isArray(appends)) appends = [appends];
7
+
8
+ this._modifiers.appends.add(appends);
9
+
10
+ return this;
11
+ },
12
+
13
+ hiddenFields (hiddenFields) {
14
+ if (! Array.isArray(hiddenFields)) hiddenFields = [hiddenFields];
15
+
16
+ this._modifiers.hiddenFields.add(hiddenFields);
17
+
18
+ return this;
19
+ },
20
+ };
21
+
22
+ export default modifierMixin;