1
- using System . Collections . Generic ;
1
+ using System ;
2
+ using System . Collections . Generic ;
2
3
using System . IO ;
3
4
using System . Linq ;
4
5
using System . Reflection ;
5
6
using Aquarius . TimeSeries . Client . ServiceModels . Acquisition ;
6
7
using Humanizer ;
7
8
using NodaTime ;
8
9
using NodaTime . Text ;
10
+ using PointZilla . PointReaders ;
9
11
using ServiceStack . Logging ;
12
+ using PublishNote = Aquarius . TimeSeries . Client . ServiceModels . Publish . Note ;
10
13
11
14
namespace PointZilla
12
15
{
@@ -38,6 +41,12 @@ public void WritePoints(List<TimeSeriesPoint> points, List<TimeSeriesNote> notes
38
41
Directory . CreateDirectory ( dir ) ;
39
42
}
40
43
44
+ var publishNotes = notes
45
+ . Select ( Convert )
46
+ . ToList ( ) ;
47
+
48
+ var notesLookup = new MetadataLookup < PublishNote > ( publishNotes ) ;
49
+
41
50
using ( var writer = new StreamWriter ( csvPath ) )
42
51
{
43
52
var offsetPattern = OffsetPattern . CreateWithInvariantCulture ( "m" ) ;
@@ -58,16 +67,30 @@ public void WritePoints(List<TimeSeriesPoint> points, List<TimeSeriesNote> notes
58
67
writer . WriteLine ( $ "#") ;
59
68
writer . WriteLine ( $ "# CSV data starts at line 15.") ;
60
69
writer . WriteLine ( $ "#") ;
61
- writer . WriteLine ( $ "ISO 8601 UTC, Value, Grade, Qualifiers") ;
70
+
71
+ var optionalNotesHeader = Context . SaveNotesMode == SaveNotesMode . WithPoints
72
+ ? ", Notes"
73
+ : string . Empty ;
74
+
75
+ writer . WriteLine ( $ "ISO 8601 UTC, Value, Grade, Qualifiers{ optionalNotesHeader } ") ;
62
76
63
77
foreach ( var point in points )
64
78
{
65
79
var time = point . Time ?? Instant . MinValue ;
66
80
67
- writer . WriteLine ( $ "{ InstantPattern . ExtendedIsoPattern . Format ( time ) } , { point . Value : G12} , { point . GradeCode } , { FormatQualifiers ( point . Qualifiers ) } ") ;
81
+ var line = $ "{ InstantPattern . ExtendedIsoPattern . Format ( time ) } , { point . Value : G12} , { point . GradeCode } , { FormatQualifiers ( point . Qualifiers ) } ";
82
+
83
+ if ( Context . SaveNotesMode == SaveNotesMode . WithPoints )
84
+ {
85
+ var pointNotes = string . Join ( "\r \n " , notesLookup . GetMany ( time . ToDateTimeOffset ( ) ) . Select ( note => note . NoteText ) ) ;
86
+
87
+ line += $ ", { CsvEscapedColumn ( pointNotes ) } ";
88
+ }
89
+
90
+ writer . WriteLine ( line ) ;
68
91
}
69
92
70
- if ( ! Context . IgnoreNotes && notes . Any ( ) )
93
+ if ( Context . SaveNotesMode == SaveNotesMode . SeparateCsv )
71
94
{
72
95
var notesCsvPath = Path . ChangeExtension ( csvPath , ".Notes.csv" ) ;
73
96
@@ -93,37 +116,32 @@ public void WritePoints(List<TimeSeriesPoint> points, List<TimeSeriesNote> notes
93
116
if ( ! note . TimeRange . HasValue )
94
117
continue ;
95
118
96
- writer . WriteLine ( $ "{ InstantPattern . ExtendedIsoPattern . Format ( note . TimeRange . Value . Start ) } , { InstantPattern . ExtendedIsoPattern . Format ( note . TimeRange . Value . End ) } , { CsvEscapedColumn ( note . NoteText ) } ") ;
119
+ notesWriter . WriteLine ( $ "{ InstantPattern . ExtendedIsoPattern . Format ( note . TimeRange . Value . Start ) } , { InstantPattern . ExtendedIsoPattern . Format ( note . TimeRange . Value . End ) } , { CsvEscapedColumn ( note . NoteText ) } ") ;
97
120
}
98
121
}
99
122
}
100
123
}
101
124
}
102
125
103
- private static string CsvEscapedColumn ( string text )
126
+ private static PublishNote Convert ( TimeSeriesNote note )
104
127
{
105
- return ! CharactersRequiringEscaping . Any ( text . Contains )
106
- ? text
107
- : $ "\" { text . Replace ( "\" " , "\" \" " ) } \" ";
128
+ return new PublishNote
129
+ {
130
+ StartTime = note . TimeRange ? . Start . ToDateTimeOffset ( ) ?? DateTimeOffset . MinValue ,
131
+ EndTime = note . TimeRange ? . End . ToDateTimeOffset ( ) ?? DateTimeOffset . MaxValue ,
132
+ NoteText = note . NoteText
133
+ } ;
108
134
}
109
135
110
- private static readonly char [ ] CharactersRequiringEscaping = new [ ]
111
- {
112
- ',' ,
113
- '"' ,
114
- '\n ' ,
115
- '\r '
116
- } ;
117
-
118
136
public static void SetPointZillaCsvFormat ( Context context )
119
137
{
120
138
// Match PointZilla Export format below
121
139
122
140
// # CSV data starts at line 15.
123
141
// #
124
- // ISO 8601 UTC, Value, Grade, Qualifiers
125
- // 2015-12-04T00:01:00Z, 3.523200823975, 500,
126
- // 2015-12-04T00:02:00Z, 3.525279357147, 500,
142
+ // ISO 8601 UTC, Value, Grade, Qualifiers, Notes
143
+ // 2015-12-04T00:01:00Z, 3.523200823975, 500, ,
144
+ // 2015-12-04T00:02:00Z, 3.525279357147, 500, ,
127
145
128
146
context . CsvSkipRows = 0 ;
129
147
context . CsvComment = "#" ;
@@ -134,6 +152,7 @@ public static void SetPointZillaCsvFormat(Context context)
134
152
context . CsvValueField = Field . Parse ( "Value" , nameof ( context . CsvValueField ) ) ;
135
153
context . CsvGradeField = Field . Parse ( "Grade" , nameof ( context . CsvGradeField ) ) ;
136
154
context . CsvQualifiersField = Field . Parse ( "Qualifiers" , nameof ( context . CsvQualifiersField ) ) ;
155
+ context . CsvNotesField = Field . Parse ( "Notes" , nameof ( context . CsvNotesField ) ) ;
137
156
context . CsvIgnoreInvalidRows = true ;
138
157
context . CsvRealign = false ;
139
158
}
@@ -194,20 +213,31 @@ private static (string StartText, string EndText) CreatePeriod(Instant start, In
194
213
start == Instant . MinValue ? "StartOfRecord" : InstantPattern . ExtendedIsoPattern . Format ( start ) ,
195
214
end == Instant . MaxValue ? "EndOfRecord" : InstantPattern . ExtendedIsoPattern . Format ( end )
196
215
) ;
197
-
198
216
}
199
217
200
218
private static string FormatQualifiers ( List < string > qualifiers )
201
219
{
202
220
if ( qualifiers == null || ! qualifiers . Any ( ) )
203
221
return string . Empty ;
204
222
205
- if ( qualifiers . Count == 1 )
206
- return qualifiers . First ( ) ;
223
+ return CsvEscapedColumn ( string . Join ( "," , qualifiers ) ) ;
224
+ }
207
225
208
- return $ "\" { string . Join ( "," , qualifiers ) } \" ";
226
+ private static string CsvEscapedColumn ( string text )
227
+ {
228
+ return ! CharactersRequiringEscaping . Any ( text . Contains )
229
+ ? text
230
+ : $ "\" { text . Replace ( "\" " , "\" \" " ) } \" ";
209
231
}
210
232
233
+ private static readonly char [ ] CharactersRequiringEscaping = new [ ]
234
+ {
235
+ ',' ,
236
+ '"' ,
237
+ '\n ' ,
238
+ '\r '
239
+ } ;
240
+
211
241
private static string SanitizeFilename ( string s )
212
242
{
213
243
return Path . GetInvalidFileNameChars ( ) . Aggregate ( s , ( current , ch ) => current . Replace ( ch , '_' ) ) ;
0 commit comments