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.json.accessor;
31 
32 import aermicioi.aedi_property_reader.core.accessor;
33 import aermicioi.aedi.exception.not_found_exception : NotFoundException;
34 import std.json;
35 import std.exception;
36 import std.conv : text;
37 import std.experimental.logger;
38 import aermicioi.aedi_property_reader.core.traits : n;
39 
40 /**
41 Accessor allowing access through JSONValues that are associative arrays
42 **/
43 class JsonPropertyAccessor : PropertyAccessor!JSONValue {
44 
45     /**
46      Get a property out of component
47 
48      Params:
49          component = a component which has some properties identified by property.
50      Throws:
51          NotFoundException in case when no requested property is available.
52          InvalidArgumentException in case when passed arguments are somehow invalid for use.
53      Returns:
54          FieldType accessed property.
55      **/
56     JSONValue access(JSONValue component, in string property) const {
57 
58         if (this.has(component, property)) {
59             return component.object[property];
60         }
61 
62         throw new NotFoundException(text("Json ", component, " doesn't have ", property));
63     }
64 
65     /**
66      Check if requested property is present in component.
67 
68      Check if requested property is present in component.
69      The method could have allocation side effects due to the fact that
70      it is not restricted in calling access method of the accessor.
71 
72      Params:
73          component = component which is supposed to have property
74          property = speculated property that is to be tested if it is present in component
75      Returns:
76          true if property is in component
77      **/
78     bool has(in JSONValue component, in string property) const nothrow {
79 
80         try {
81 
82             return (component.type == JSON_TYPE.OBJECT) && ((property in component.object) !is null);
83         } catch (Exception e) {
84 
85             debug(trace) error("Failed to check property ", property, " existence in json ", component).n;
86         }
87 
88         return false;
89     }
90 
91     /**
92      Identify the type of supported component.
93 
94      Identify the type of supported component. It returns type info of component
95      if it is supported by accessor, otherwise it will return typeid(void) denoting that
96      the type isn't supported by accessor. The accessor is not limited to returning the type
97      info of passed component, it can actually return type info of super type or any type
98      given the returned type is implicitly convertible or castable to ComponentType.
99 
100      Params:
101          component = the component for which accessor should identify the underlying type
102 
103      Returns:
104          TypeInfo type information about passed component, or typeid(void) if component is not supported.
105      **/
106     TypeInfo componentType(JSONValue component) const nothrow {
107         return typeid(JSONValue);
108     }
109 
110 }
111 
112 /**
113 Accessor allowing access to properties in a JSONValue array
114 **/
115 class JsonIndexAccessor : PropertyAccessor!JSONValue {
116 
117     /**
118      Get a property out of component
119 
120      Params:
121          component = a component which has some properties identified by property.
122      Throws:
123          NotFoundException in case when no requested property is available.
124          InvalidArgumentException in case when passed arguments are somehow invalid for use.
125      Returns:
126          FieldType accessed property.
127      **/
128     JSONValue access(JSONValue component, in string property) const {
129 
130         if (this.has(component, property)) {
131             import std.conv : to;
132 
133             return component.array[property.to!size_t];
134         }
135 
136         throw new NotFoundException(text("Json ", component, " doesn't have child on index ", property));
137     }
138 
139     /**
140      Check if requested property is present in component.
141 
142      Check if requested property is present in component.
143      The method could have allocation side effects due to the fact that
144      it is not restricted in calling access method of the accessor.
145 
146      Params:
147          component = component which is supposed to have property
148          property = speculated property that is to be tested if it is present in component
149      Returns:
150          true if property is in component
151      **/
152     bool has(in JSONValue component, in string property) const nothrow {
153 
154         try {
155             import std.string : isNumeric;
156             import std.conv : to;
157 
158             return (component.type == JSON_TYPE.ARRAY) && property.isNumeric && (component.array.length > property.to!size_t);
159         } catch (Exception e) {
160 
161             debug(trace) error("Failed to check indexed property ", property, " existence in json ", component).n;
162         }
163 
164         return false;
165     }
166 
167     /**
168      Identify the type of supported component.
169 
170      Identify the type of supported component. It returns type info of component
171      if it is supported by accessor, otherwise it will return typeid(void) denoting that
172      the type isn't supported by accessor. The accessor is not limited to returning the type
173      info of passed component, it can actually return type info of super type or any type
174      given the returned type is implicitly convertible or castable to ComponentType.
175 
176      Params:
177          component = the component for which accessor should identify the underlying type
178 
179      Returns:
180          TypeInfo type information about passed component, or typeid(void) if component is not supported.
181      **/
182     TypeInfo componentType(JSONValue component) const nothrow {
183         return typeid(JSONValue);
184     }
185 }