Passed
Pull Request — master (#106)
by Mark
01:33
created

Collection   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 123
dl 0
loc 167
rs 8.96
c 0
b 0
f 0
wmc 43

19 Functions

Rating   Name   Duplication   Size   Complexity  
A first 0 3 3
A whereBetween 0 5 1
A toObject 0 4 4
A pluck 0 19 4
A unique 0 8 2
A whereNotBetween 0 5 1
A merge 0 4 1
A whereNotIn 0 4 1
A whereNotNull 0 4 1
A toJSON 0 3 1
A random 0 3 1
A last 0 3 3
A whereNotInstanceOf 0 4 1
B _getRowFieldResult 0 18 8
A whereNull 0 4 1
A whereInstanceOf 0 4 1
A whereIfFunction 0 9 3
A whereIn 0 4 1
A where 0 11 5

How to fix   Complexity   

Complexity

Complex classes like Collection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import * as Operators from './Collection/Where/Operators';
2
3
/**
4
 *
5
 */
6
export default class Collection extends Array {
7
8
    constructor(...items) {
9
        super(...items);
10
    }
11
12
    get operators() {
13
        return {
14
            '==': Operators.equal,
15
            '!=': Operators.notEqual,
16
            '>=': Operators.gtAndEqual,
17
            '<=': Operators.ltAndEqual,
18
            '>': Operators.gt,
19
            '<': Operators.lt,
20
        }
21
    }
22
23
    first() {
24
        return this[0] ?? null;
25
    }
26
27
    last() {
28
        return this.slice(-1)[0] ?? null;
29
    }
30
31
    merge(array): Collection {
32
        this.push(...array);
33
        return this;
34
    }
35
36
    pluck(field: string, keyField = '') {
37
        const lookUpFields = field.split('.');
38
39
        if (keyField) {
40
            const lookUpKeyField = keyField.split('.');
41
            const result = {};
42
            for (const i in this) {
43
                result[this._getRowFieldResult(this[i], lookUpKeyField)] = this._getRowFieldResult(this[i], lookUpFields);
44
            }
45
            return result;
46
        }
47
48
        const result = [];
49
        for (const i in this) {
50
            result.push(this._getRowFieldResult(this[i], lookUpFields));
51
        }
52
53
        return result;
54
    }
55
56
    random() {
57
        return this[Math.round(((this.length - 1) * Math.random()))];
58
    }
59
60
    unique(field: string): Collection {
61
        const unique = {};
62
        for (const i in this) {
63
            unique[this[i][field]] = this[i];
64
        }
65
66
        return new Collection(...Object.values(unique));
67
    }
68
69
    where(field: string, operator: string, value = null): Collection {
70
        value = value ?? operator;
71
        operator = (operator === value) ? '==' : operator;
72
73
        if (!Object.prototype.hasOwnProperty.call(this.operators, operator)) {
74
            throw new Error("Invalid comparison operator used");
75
        }
76
77
        return this.whereIfFunction(field, (field, object) => {
78
            return this.operators[operator](object[field], value);
79
        })
80
    }
81
82
    whereBetween(field: string, values): Collection {
83
        return this.whereIfFunction(field, (field, object) => {
84
            const fieldValue = object[field];
85
            return fieldValue >= values[0] && fieldValue <= values[1]
86
        });
87
    }
88
89
    whereIfFunction(field: string, whereIfFunction: CallableFunction): Collection {
90
        const register = new Collection();
91
        for (const i in this) {
92
            if (whereIfFunction(field, this[i])) {
93
                register.push(this[i]);
94
            }
95
        }
96
        return register;
97
    }
98
99
    whereIn(field: string, values): Collection {
100
        return this.whereIfFunction(field, (field, object) => {
101
            return values.includes(object[field]);
102
        });
103
    }
104
105
    whereInstanceOf(classInstance): Collection {
106
        return this.whereIfFunction(null, (field, object) => {
107
            return object instanceof classInstance;
108
        });
109
    }
110
111
    whereNotBetween(field: string, values): Collection {
112
        return this.whereIfFunction(field, (field, object) => {
113
            const fieldValue = object[field];
114
            return !(fieldValue >= values[0] && fieldValue <= values[1])
115
        });
116
    }
117
118
    whereNotIn(field: string, values): Collection {
119
        return this.whereIfFunction(field, (field, object) => {
120
            return !values.includes(object[field]);
121
        });
122
    }
123
124
    whereNotInstanceOf(classInstance): Collection {
125
        return this.whereIfFunction(null, (field, object) => {
126
            return !(object instanceof classInstance);
127
        });
128
    }
129
130
    whereNotNull(field: string): Collection {
131
        return this.whereIfFunction(field, (field, object) => {
132
            return object[field] !== null;
133
        });
134
    }
135
136
    whereNull(field: string): Collection {
137
        return this.whereIfFunction(field, (field, object) => {
138
            return object[field] === null;
139
        });
140
    }
141
142
    toJSON() {
143
        return this.toObject();
144
    }
145
146
    toObject() {
147
       return this.map((item) => {
148
           return (item.toObject?.() ?? item);
149
       });
150
    }
151
152
    private _getRowFieldResult(row, lookUpFields) {
153
        let resultField = row[lookUpFields[0]] ?? null;
154
        for (let i = 1; i < lookUpFields.length; i++) {
155
            const currentField = lookUpFields[i];
156
157
            if (resultField === null) {
158
                break;
159
            }
160
161
            if (resultField instanceof Collection) {
162
                return resultField.pluck(lookUpFields[i]);
163
            }
164
165
            resultField = resultField[currentField] ?? null;
166
        }
167
168
        return resultField;
169
    }
170
}