Completed
Push — master ( c1e1cb...826c7a )
by Mark
25s queued 11s
created

Table.save   A

Complexity

Conditions 3

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 11
dl 0
loc 14
rs 9.85
c 0
b 0
f 0
1
import {Model} from "./Model";
2
import Collection from "./Collection";
3
import Index from "./Table/Index";
4
import {TableInterface, ModelInterface, ModelStaticInterface} from "../JeloquentInterfaces";
5
6
/**
7
 *
8
 */
9
export default class Table implements TableInterface {
10
11
    name: string;
12
13
    private _index: Index;
14
15
    private _model: ModelInterface;
16
17
    private _models: Map<string, ModelInterface>;
18
19
    private _primaryKeyFieldNames: Array<string>;
20
21
    constructor (model: ModelStaticInterface) {
22
        this.setup(model.getInstance());
23
    }
24
25
    get ids():string[] {
26
        return [...this._models.keys()];
27
    }
28
29
    get indexes(): Map<string, Map<string|number, Set<string|number>>> {
30
        return this._index.indexes;
31
    }
32
33
    get models(): Map<string|number, ModelInterface> {
34
        return this._models;
35
    }
36
37
    static make(model: ModelStaticInterface): Table {
38
        return new Table(model);
39
    }
40
41
    public addIndex(indexName:string, lookUpKey:string, id:string|number): void {
42
        this._index.addValue(indexName, lookUpKey, `${id}`);
43
    }
44
45
    public all(): Collection {
46
        const values = [...this._models.values()];
47
        const numberOfValues = values.length;
48
        const collection = new Collection();
49
        for (let i = 0; i < numberOfValues; i += 10000) {
50
            collection.push(...values.slice(i, i + 10000));
51
        }
52
53
        return collection;
54
    }
55
56
    /**
57
     * @deprecated
58
     */
59
    public allModels(): Map<string | number, ModelInterface> {
60
        return this.models;
61
    }
62
63
    public delete(id:string|number): void {
64
        if (!this._models.has(`${id}`)) {
65
            throw new Error('Record doesn\'t exists');
66
        }
67
68
        this._index.removeValueByModel(this.findOne(id));
69
70
        this._models.delete(`${id}`);
71
    }
72
73
    public find(id:number|string|object|Array<string|number|object>): Collection|ModelInterface|null {
74
        const hasComposedPrimaryKey = this._primaryKeyFieldNames.length > 1;
75
        if (Array.isArray(id)) {
76
            if (hasComposedPrimaryKey) {
77
                return this.findCollectionComposedPrimaryKey(id as Array<object>);
78
            }
79
            return this.findCollection(id as Array<string|number>);
80
        }
81
82
        if (hasComposedPrimaryKey) {
83
            return this.findOneComposedPrimaryKey(id as object);
84
        }
85
86
        return this.findOne(id as (string|number));
87
    }
88
89
    public getIndexByKey(key: string): Map<string|number, Set<string|number>> {
90
        return this._index.getIndexByKey(key);
91
    }
92
93
    public insert(model: ModelInterface): void {
94
        if (this._models.has(model.primaryKey)) {
95
            throw new Error('Record already exists');
96
        }
97
98
        if (!(model instanceof Model)) {
99
            throw new Error('Record should be instance of model');
100
        }
101
102
        model.resetDirty();
103
104
        if (model.primaryKey != null) {
105
            this._models.set(model.primaryKey, model);
106
        }
107
108
        this._index.addValueByModel(model);
109
    }
110
111
    public registerIndex(indexName:string): void {
112
        this._index.register(indexName);
113
    }
114
115
    public removeIndex(indexName:string, lookUpKey:string, id:string|number): void {
116
        this._index.removeValue(indexName, lookUpKey, id)
117
    }
118
119
    public save(model: ModelInterface) {
120
        if (!model.primaryKey.startsWith('_') && this.ids.includes(model._tmpId)) {
121
            //todo remove indexes for foreignKey
122
            //                                team_id  this.team_id
123
            Index.removeTmpIdFromIndex(model);
124
            this.delete(model._tmpId);
125
        }
126
127
        if (this.ids.includes(model.primaryKey)) {
128
            this.update(model);
129
            return;
130
        }
131
        this.insert(model);
132
    }
133
134
    public setupIndexes(): void {
135
        this._model.tableSetup(this);
136
    }
137
138
    public truncate(): void {
139
        this._models.clear();
140
        this._index.truncate();
141
    }
142
143
    public update(model: ModelInterface): void {
144
        if (!this.models.has(model.primaryKey)) {
145
            throw new Error('Record doesn\'t exists');
146
        }
147
148
        if (!(model instanceof Model)) {
149
            throw new Error('Record should be instance of model');
150
        }
151
152
        this._index.removeValueByModel(model);
153
154
        model.resetDirty();
155
156
        this._index.addValueByModel(model);
157
158
        this._models.set(model.primaryKey, model);
159
    }
160
161
    private findCollection(id:Array<string|number>): Collection {
162
        const result = [];
163
        for (let i = 0; i < id.length; i++) {
164
            result.push(
165
                this._models.get(`${id[i]}`)
166
            );
167
        }
168
        return new Collection(...result);
169
    }
170
171
    private findCollectionComposedPrimaryKey(id: Array<object>): Collection {
172
        const result = [];
173
        for (let i = 0; i < id.length; i++) {
174
            result.push(
175
                this._models.get(
176
                    this.toComposedKey(id[i])
177
                )
178
            );
179
        }
180
        return new Collection(...result);
181
    }
182
183
    private findOne(id: string|number): ModelInterface|null {
184
        return this._models.get(`${id}`) ?? null;
185
    }
186
187
    private findOneComposedPrimaryKey(id: object|string): ModelInterface|null {
188
        return this._models.get(this.toComposedKey(id)) ?? null;
189
    }
190
191
    private setup(model: ModelInterface) {
192
        this.name = model.className;
193
        this._primaryKeyFieldNames = model.primaryKeyName;
194
195
        this._model = model;
196
        this._models = new Map();
197
        this._index = new Index();
198
    }
199
200
    private toComposedKey(id:string|object): string|null {
201
        if (typeof id === 'string') {
202
            return id;
203
        }
204
205
        if (id === null) {
206
            return null;
207
        }
208
209
        const key = [];
210
        for (let i = 0; i < this._primaryKeyFieldNames.length; i++) {
211
            key.push(id[this._primaryKeyFieldNames[i]] ?? '');
212
        }
213
214
        return key.join('-');
215
    }
216
}