1- using Upsilon . Apps . PassKey . Core . Internal . Utils ;
2- using Upsilon . Apps . PassKey . Core . Public . Interfaces ;
1+ using Upsilon . Apps . Passkey . Core . Internal . Utils ;
2+ using Upsilon . Apps . Passkey . Core . Public . Interfaces ;
33
4- namespace Upsilon . Apps . PassKey . Core . Internal . Models
4+ namespace Upsilon . Apps . Passkey . Core . Internal . Models
55{
66 internal sealed class AutoSave
77 {
8- private Database ? _database ;
98 internal Database Database
109 {
11- get => _database ?? throw new NullReferenceException ( nameof ( Database ) ) ;
12- set => _database = value ;
10+ get => field ?? throw new NullReferenceException ( nameof ( Database ) ) ;
11+ set ;
1312 }
1413
15- public Queue < Change > Changes { get ; set ; } = new ( ) ;
14+ public Dictionary < string , List < Change > > Changes { get ; set ; } = [ ] ;
1615
17- internal T UpdateValue < T > ( string itemId , string itemName , string fieldName , bool needsReview , T oldValue , T value , string readableValue ) where T : notnull
16+ internal T UpdateValue < T > ( string itemId ,
17+ string itemName ,
18+ string fieldName ,
19+ bool needsReview ,
20+ T oldValue ,
21+ T newValue ,
22+ string readableValue ) where T : notnull
1823 {
19- if ( ISerializationCenter . AreDifferent ( Database . SerializationCenter , oldValue , value ) )
24+ if ( ISerializationCenter . AreDifferent ( Database . SerializationCenter , oldValue , newValue ) )
2025 {
21- _addChange ( itemId , itemName , string . Empty , fieldName , Database . SerializationCenter . Serialize ( value ) , readableValue , needsReview , Change . Type . Update ) ;
26+ _addChange ( itemId ,
27+ itemName ,
28+ string . Empty ,
29+ fieldName ,
30+ oldValue . SerializeWith ( Database . SerializationCenter ) ,
31+ newValue . SerializeWith ( Database . SerializationCenter ) ,
32+ readableValue ,
33+ needsReview ,
34+ Change . Type . Update ) ;
2235 }
2336
24- return value ;
37+ return newValue ;
2538 }
2639
27- internal T AddValue < T > ( string itemId , string itemName , string containerName , bool needsReview , T value ) where T : notnull
40+ internal T AddValue < T > ( string itemId ,
41+ string itemName ,
42+ string containerName ,
43+ bool needsReview ,
44+ T value ) where T : notnull
2845 {
29- _addChange ( itemId , itemName , containerName , string . Empty , Database . SerializationCenter . Serialize ( value ) , string . Empty , needsReview , Change . Type . Add ) ;
46+ _addChange ( itemId , itemName , containerName , string . Empty , value . SerializeWith ( Database . SerializationCenter ) , string . Empty , needsReview , Change . Type . Add ) ;
3047
3148 return value ;
3249 }
3350
34- internal T DeleteValue < T > ( string itemId , string itemName , string containerName , bool needsReview , T value ) where T : notnull
51+ internal T DeleteValue < T > ( string itemId ,
52+ string itemName ,
53+ string containerName ,
54+ bool needsReview ,
55+ T value ) where T : notnull
3556 {
36- _addChange ( itemId , itemName , containerName , string . Empty , Database . SerializationCenter . Serialize ( value ) , string . Empty , needsReview , Change . Type . Delete ) ;
57+ _addChange ( itemId , itemName , containerName , string . Empty , value . SerializeWith ( Database . SerializationCenter ) , string . Empty , needsReview , Change . Type . Delete ) ;
3758
3859 return value ;
3960 }
4061
41- private void _addChange ( string itemId , string itemName , string containerName , string fieldName , string value , string readableValue , bool needsReview , Change . Type action )
62+ private void _addChange ( string itemId ,
63+ string itemName ,
64+ string containerName ,
65+ string fieldName ,
66+ string newValue ,
67+ string readableValue ,
68+ bool needsReview ,
69+ Change . Type action )
70+ {
71+ _addChange ( itemId ,
72+ itemName ,
73+ containerName ,
74+ fieldName ,
75+ null ,
76+ newValue ,
77+ readableValue ,
78+ needsReview ,
79+ action ) ;
80+ }
81+
82+ private void _addChange ( string itemId ,
83+ string itemName ,
84+ string containerName ,
85+ string fieldName ,
86+ string ? oldValue ,
87+ string newValue ,
88+ string readableValue ,
89+ bool needsReview ,
90+ Change . Type action )
4291 {
43- Changes . Enqueue ( new Change
92+ string changeKey = $ "{ itemId } \t { fieldName } ";
93+ if ( ! Changes . ContainsKey ( changeKey ) )
94+ {
95+ Changes [ changeKey ] = [ ] ;
96+ }
97+
98+ Change currentChange = new ( )
4499 {
100+ Index = DateTime . Now . Ticks ,
45101 ActionType = action ,
46102 ItemId = itemId ,
47103 FieldName = fieldName ,
48- Value = value ,
49- } ) ;
104+ OldValue = oldValue ,
105+ NewValue = newValue ,
106+ } ;
107+
108+ _mergeChanges ( changeKey , currentChange ) ;
50109
51110 if ( Database . AutoSaveFileLocker == null )
52111 {
@@ -63,24 +122,60 @@ private void _addChange(string itemId, string itemName, string containerName, st
63122 Database . Logs . AddLog ( logMessage , needsReview ) ;
64123 }
65124
66- internal void MergeChange ( )
125+ private void _mergeChanges ( string changeKey , Change currentChange )
67126 {
68- while ( Changes . Count != 0 )
127+ Change ? lastUpdate = Changes [ changeKey ] . LastOrDefault ( x => x . ActionType == Change . Type . Update ) ;
128+
129+ if ( currentChange . ActionType != Change . Type . Update
130+ || lastUpdate is null )
69131 {
70- Database . User ? . Apply ( Changes . Dequeue ( ) ) ;
132+ Changes [ changeKey ] . Add ( currentChange ) ;
133+ return ;
71134 }
72135
73- Clear ( ) ;
136+ _ = Changes [ changeKey ] . Remove ( lastUpdate ) ;
137+ currentChange . OldValue = lastUpdate . OldValue ;
138+
139+ if ( currentChange . OldValue != currentChange . NewValue )
140+ {
141+ Changes [ changeKey ] . Add ( currentChange ) ;
142+ }
143+ else if ( Changes [ changeKey ] . Count == 0 )
144+ {
145+ _ = Changes . Remove ( changeKey ) ;
146+ }
74147 }
75148
76- internal void Clear ( )
149+ internal void ApplyChanges ( bool deleteFile )
150+ {
151+ List < Change > changes = Changes . Values . SelectMany ( x => x ) . OrderBy ( x => x . Index ) . ToList ( ) ;
152+
153+ foreach ( Change change in changes )
154+ {
155+ Database . User ? . Apply ( change ) ;
156+ }
157+
158+ if ( deleteFile )
159+ {
160+ Clear ( deleteFile : true ) ;
161+ }
162+ }
163+
164+ internal bool Any ( ) => Any ( string . Empty ) ;
165+
166+ internal bool Any ( string itemId ) => Changes . Any ( x => x . Key . StartsWith ( itemId ) ) ;
167+
168+ internal bool Any ( string itemId , string fieldName ) => Changes . Any ( x => x . Key == $ "{ itemId } \t { fieldName } ") ;
169+
170+ internal void Clear ( bool deleteFile )
77171 {
78172 Changes . Clear ( ) ;
79173
80174 Database . AutoSaveFileLocker ? . Dispose ( ) ;
81175 Database . AutoSaveFileLocker = null ;
82176
83- if ( File . Exists ( Database . AutoSaveFile ) )
177+ if ( deleteFile
178+ && File . Exists ( Database . AutoSaveFile ) )
84179 {
85180 File . Delete ( Database . AutoSaveFile ) ;
86181 }
0 commit comments