• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 13331632524

14 Feb 2025 02:51PM UTC coverage: 22.015% (-69.6%) from 91.622%
13331632524

Pull #15372

github

web-flow
Merge d52d57714 into bcb78ae0a
Pull Request #15372: chore(*): test ci passing

1990 of 15592 branches covered (12.76%)

431 of 964 new or added lines in 18 files covered. (44.71%)

19956 existing lines in 307 files now uncovered.

6452 of 29307 relevant lines covered (22.02%)

249.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

16.36
/projects/igniteui-angular/src/lib/services/transaction/base-transaction.ts
1
import { TransactionService, Transaction, State, StateUpdateEvent, TransactionType } from './transaction';
2
import { EventEmitter } from '@angular/core';
3
import { isObject, mergeObjects } from '../../core/utils';
4
import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../../data-operations/data-clone-strategy';
5

6
export class IgxBaseTransactionService<T extends Transaction, S extends State> implements TransactionService<T, S> {
7
    /**
8
     * Gets/Sets the data clone strategy used to clone data
9
     */
10
    public get cloneStrategy(): IDataCloneStrategy {
UNCOV
11
        return this._cloneStrategy;
×
12
    }
13

14
    public set cloneStrategy(strategy: IDataCloneStrategy) {
15
        if (strategy) {
39✔
16
            this._cloneStrategy = strategy;
39✔
17
        }
18
    }
19

20
    /**
21
     * @returns if there are any transactions in the Redo stack
22
     */
23
    public get canRedo(): boolean {
24
        return false;
×
25
    }
26

27
    /**
28
     * @returns if there are any transactions in the Undo stack
29
     */
30
    public get canUndo(): boolean {
31
        return false;
×
32
    }
33

34
    /**
35
     * Returns whether transaction is enabled for this service
36
     */
37
    public get enabled(): boolean {
38
        return this._isPending;
57,888✔
39
    }
40

41
    /**
42
     * Event fired when transaction state has changed - add transaction, commit all transactions, undo and redo
43
     */
44
    public onStateUpdate = new EventEmitter<StateUpdateEvent>();
39✔
45

46
    protected _isPending = false;
39✔
47
    protected _pendingTransactions: T[] = [];
39✔
48
    protected _pendingStates: Map<any, S> = new Map();
39✔
49
    private _cloneStrategy: IDataCloneStrategy = new DefaultDataCloneStrategy();
39✔
50

51
    /**
52
     * Adds provided  transaction with recordRef if any
53
     *
54
     * @param transaction Transaction to be added
55
     * @param recordRef Reference to the value of the record in the data source related to the changed item
56
     */
57
    public add(transaction: T, recordRef?: any): void {
UNCOV
58
        if (this._isPending) {
×
UNCOV
59
            this.updateState(this._pendingStates, transaction, recordRef);
×
UNCOV
60
            this._pendingTransactions.push(transaction);
×
61
        }
62
    }
63

64
    /**
65
     * Returns all recorded transactions in chronological order
66
     *
67
     * @param id Optional record id to get transactions for
68
     * @returns All transaction in the service or for the specified record
69
     */
70
    public getTransactionLog(_id?: any): T[] {
UNCOV
71
        return [];
×
72
    }
73

74
    /**
75
     * Remove the last transaction if any
76
     */
77
    public undo(): void { }
78

79
     /**
80
      * Applies the last undone transaction if any
81
      */
82
    public redo(): void { }
83

84
    /**
85
     * Returns aggregated changes from all transactions
86
     *
87
     * @param mergeChanges If set to true will merge each state's value over relate recordRef
88
     * and will record resulting value in the related transaction
89
     * @returns Collection of aggregated transactions for each changed record
90
     */
91
    public getAggregatedChanges(mergeChanges: boolean): T[] {
UNCOV
92
        const result: T[] = [];
×
UNCOV
93
        this._pendingStates.forEach((state: S, key: any) => {
×
UNCOV
94
            const value = mergeChanges ? this.getAggregatedValue(key, mergeChanges) : state.value;
×
UNCOV
95
            result.push({ id: key, newValue: value, type: state.type } as T);
×
96
        });
UNCOV
97
        return result;
×
98
    }
99

100
    /**
101
     * Returns the state of the record with provided id
102
     *
103
     * @param id The id of the record
104
     * @param pending Should get pending state
105
     * @returns State of the record if any
106
     */
107
    public getState(id: any): S {
108
        return this._pendingStates.get(id);
3,559✔
109
    }
110

111
    /**
112
     * Returns value of the required id including all uncommitted changes
113
     *
114
     * @param id The id of the record to return value for
115
     * @param mergeChanges If set to true will merge state's value over relate recordRef
116
     * and will return merged value
117
     * @returns Value with changes or **null**
118
     */
119
    public getAggregatedValue(id: any, mergeChanges: boolean): any {
UNCOV
120
        const state = this._pendingStates.get(id);
×
UNCOV
121
        if (!state) {
×
UNCOV
122
            return null;
×
123
        }
UNCOV
124
        if (mergeChanges && state.recordRef) {
×
UNCOV
125
            return this.updateValue(state);
×
126
        }
UNCOV
127
        return state.value;
×
128
    }
129

130
    /**
131
     * Applies all transactions over the provided data
132
     *
133
     * @param data Data source to update
134
     * @param id Optional record id to commit transactions for
135
     */
136
    public commit(_data: any[], _id?: any): void { }
137

138
    /**
139
     * Clears all transactions
140
     *
141
     * @param id Optional record id to clear transactions for
142
     */
143
    public clear(_id?: any): void {
144
        this._pendingStates.clear();
×
145
        this._pendingTransactions = [];
×
146
    }
147

148
    /**
149
     * Starts pending transactions. All transactions passed after call to startPending
150
     * will not be added to transaction log
151
     */
152
    public startPending(): void {
UNCOV
153
        this._isPending = true;
×
154
    }
155

156
    /**
157
     * Clears all pending transactions and aggregated pending state. If commit is set to true
158
     * commits pending states as single transaction
159
     *
160
     * @param commit Should commit the pending states
161
     */
162
    public endPending(_commit: boolean): void {
UNCOV
163
        this._isPending = false;
×
UNCOV
164
        this._pendingStates.clear();
×
UNCOV
165
        this._pendingTransactions = [];
×
166
    }
167

168

169
    /**
170
     * Updates the provided states collection according to passed transaction and recordRef
171
     *
172
     * @param states States collection to apply the update to
173
     * @param transaction Transaction to apply to the current state
174
     * @param recordRef Reference to the value of the record in data source, if any, where transaction should be applied
175
     */
176
    protected updateState(states: Map<any, S>, transaction: T, recordRef?: any): void {
UNCOV
177
        let state = states.get(transaction.id);
×
UNCOV
178
        if (state) {
×
UNCOV
179
            if (isObject(state.value)) {
×
UNCOV
180
                mergeObjects(state.value, transaction.newValue);
×
181
            } else {
182
                state.value = transaction.newValue;
×
183
            }
184
        } else {
UNCOV
185
            state = { value: this.cloneStrategy.clone(transaction.newValue), recordRef, type: transaction.type } as S;
×
UNCOV
186
            states.set(transaction.id, state);
×
187
        }
188

UNCOV
189
        this.cleanState(transaction.id, states);
×
190
    }
191

192
    /**
193
     * Updates the recordRef of the provided state with all the changes in the state. Accepts primitive and object value types
194
     *
195
     * @param state State to update value for
196
     * @returns updated value including all the changes in provided state
197
     */
198
    protected updateValue(state: S) {
UNCOV
199
        return this.mergeValues(state.recordRef, state.value);
×
200
    }
201

202
    /**
203
     * Merges second values in first value and the result in empty object. If values are primitive type
204
     * returns second value if exists, or first value.
205
     *
206
     * @param first Value to merge into
207
     * @param second Value to merge
208
     */
209
    protected mergeValues<U>(first: U, second: U): U {
UNCOV
210
        if (isObject(first) || isObject(second)) {
×
UNCOV
211
            return mergeObjects(this.cloneStrategy.clone(first), second);
×
212
        } else {
UNCOV
213
            return second ? second : first;
×
214
        }
215
    }
216

217
    /**
218
     * Compares the state with recordRef and clears all duplicated values. If any state ends as
219
     * empty object removes it from states.
220
     *
221
     * @param state State to clean
222
     */
223
    protected cleanState(id: any, states: Map<any, S>): void {
UNCOV
224
        const state = states.get(id);
×
225
        //  do nothing if
226
        //  there is no state, or
227
        //  there is no state value (e.g. DELETED transaction), or
228
        //  there is no recordRef (e.g. ADDED transaction)
UNCOV
229
        if (state && state.value && state.recordRef) {
×
230
            //  if state's value is object compare each key with the ones in recordRef
231
            //  if values in any key are the same delete it from state's value
232
            //  if state's value is not object, simply compare with recordRef and remove
233
            //  the state if they are equal
UNCOV
234
            if (isObject(state.recordRef)) {
×
UNCOV
235
                for (const key of Object.keys(state.value)) {
×
UNCOV
236
                    if (JSON.stringify(state.recordRef[key]) === JSON.stringify(state.value[key])) {
×
UNCOV
237
                        delete state.value[key];
×
238
                    }
239
                }
240

241
                //  if state's value is empty remove the state from the states, only if state is not DELETE type
UNCOV
242
                if (state.type !== TransactionType.DELETE && Object.keys(state.value).length === 0) {
×
UNCOV
243
                    states.delete(id);
×
244
                }
245
            } else {
UNCOV
246
                if (state.recordRef === state.value) {
×
247
                    states.delete(id);
×
248
                }
249
            }
250
        }
251
    }
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc