1 /**
2 License:
3     Boost Software License - Version 1.0 - August 17th, 2003
4 
5     Permission is hereby granted, free of charge, to any person or organization
6     obtaining a copy of the software and accompanying documentation covered by
7     this license (the "Software") to use, reproduce, display, distribute,
8     execute, and transmit the Software, and to prepare derivative works of the
9     Software, and to permit third-parties to whom the Software is furnished to
10     do so, all subject to the following:
11 
12     The copyright notices in the Software and this entire statement, including
13     the above license grant, this restriction and the following disclaimer,
14     must be included in all copies of the Software, in whole or in part, and
15     all derivative works of the Software, unless such copies or derivative
16     works are solely in the form of machine-executable object code generated by
17     a source language processor.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28     Alexandru Ermicioi
29 **/
30 module aermicioi.aedi_property_reader.csv.csv;
31 
32 import std.experimental.allocator;
33 import std.experimental.logger;
34 import std.range : array;
35 import aermicioi.aedi.configurer.annotation.annotation;
36 import aermicioi.aedi_property_reader.convertor.convertor;
37 import aermicioi.aedi_property_reader.convertor.accessor;
38 import aermicioi.aedi_property_reader.convertor.setter;
39 import aermicioi.aedi_property_reader.convertor.std_conv;
40 import aermicioi.aedi_property_reader.convertor.inspector;
41 import aermicioi.aedi_property_reader.convertor.type_guesser;
42 import aermicioi.aedi_property_reader.core.document;
43 import aermicioi.aedi_property_reader.core.core;
44 
45 alias CsvDocumentContainer = PolicyDocument!(
46     string[string][],
47     string[string],
48     WithContainerScanning!(
49         aermicioi.aedi_property_reader.core.config,
50     )(),
51     WithInitializer!(
52         StdConvStringPrebuiltConvertorsFactory
53     )(),
54     WithContainerScanning!(
55         aermicioi.aedi_property_reader.csv.csv,
56     )(),
57     WithConvertorAggregation!CombinedConvertor(),
58     WithLocatorForUnregisteredComponents("csv-document-locator"),
59     WithDefaultRegisterers
60 );
61 
62 @component
63 auto runtimeCsvTypeGuesser(
64     TypeGuesser!string guesser
65 ) {
66     return new DelegatingObjectTypeGuesser!(string[string], string)(
67         new SimpleTypeGuesser!(string[string])(),
68         guesser
69     );
70 }
71 
72 @component
73 auto propertyAccessor() {
74     return new AssociativeArrayAccessor!(string[string]);
75 }
76 
77 @component
78 auto rootAccessor(
79     Convertor defaultConvertor
80 ) {
81     return new KeyConvertingAccessor!(string[string][], string[string], string, size_t)(
82             new ArrayAccessor!(string[string][]),
83             defaultConvertor
84         );
85 }
86 
87 @component
88 auto runtimeEntryAccessor(
89     PropertyAccessor!(string[string], string) propertyAccessor,
90 ) {
91     return new WrappingFieldAccessor!(string[string], string)(propertyAccessor);
92 }
93 
94 @component
95 auto runtimeRootPathAccessor(
96     PropertyAccessor!(string[string], string) propertyAccessor,
97     PropertyAccessor!(string[string][], string[string]) rootAccessor,
98     Convertor defaultConvertor
99 ) {
100     auto accessor = new AggregatePropertyAccessor!(Object, Object)(
101         new UnwrappingComponentAccessor!(string[string][], Object)(
102             new WrappingFieldAccessor!(string[string][], string[string])(
103                 rootAccessor
104             )
105         ),
106         new UnwrappingComponentAccessor!(string[string], Object)(
107             new WrappingFieldAccessor!(string[string], string)(
108                 propertyAccessor
109             )
110         )
111     );
112 
113     return new WrappingComponentAccessor!(string[string][], Object)(
114         dsl(
115             accessor,
116             accessor
117         )
118     );
119 }
120 
121 /**
122 Create a csv document container
123 
124 Params:
125     data = associative array with parsed csv content
126     allocator = allocator used to convert types
127 
128 Returns:
129     DocumentContainer!(string[string][], string[string])
130 **/
131 auto csv(
132     string[string][] data
133 ) {
134     CsvDocumentContainer container = CsvDocumentContainer(data);
135 
136     return container;
137 }
138 
139 /**
140 ditto
141 **/
142 auto csv() {
143     return csv(cast(string[string][]) []);
144 }
145 
146 /**
147 Create a csv document container from a csv file or text.
148 
149 Params:
150     fileOrData = file path or csv text
151     accessor = accessor used for accessing data
152     allocator = allocator used to convert types
153     returnEmpty = either to return an empty document container if csv file or text is invalid.
154 
155 Returns:
156     DocumentContainer!(string[string][], string[string])
157 **/
158 auto csv(
159     string fileOrData,
160     bool returnEmpty = true
161 ) {
162 
163     import std.file : exists, readText;
164     import std.csv : csvReader, CSVException;
165 
166     try {
167         if (fileOrData.exists) {
168             return fileOrData.readText.csvReader!(string[string])(null).array.csv();
169         }
170 
171         return fileOrData.csvReader!(string[string])(null).array.csv();
172     } catch (CSVException e) {
173         debug(trace) trace("Error parsing csv: ", e);
174 
175         if (returnEmpty) {
176             debug(trace) trace("Providing empty container");
177             return csv();
178         }
179 
180         throw new Exception(
181             "Could not create csv convertor container from file or content passed in pathOrData: " ~ fileOrData,
182             e
183         );
184     }
185 }