|
3 | 3 |
|
4 | 4 | #include <graphqlservice/JSONResponse.h> |
5 | 5 |
|
| 6 | +#define RAPIDJSON_NAMESPACE facebook::graphql::rapidjson |
| 7 | +#define RAPIDJSON_NAMESPACE_BEGIN namespace facebook { namespace graphql { namespace rapidjson { |
| 8 | +#define RAPIDJSON_NAMESPACE_END } /* namespace rapidjson */ } /* namespace graphql */ } /* namespace facebook */ |
| 9 | +#include <rapidjson/rapidjson.h> |
| 10 | + |
| 11 | +#include <rapidjson/stringbuffer.h> |
| 12 | +#include <rapidjson/writer.h> |
| 13 | +#include <rapidjson/reader.h> |
| 14 | + |
| 15 | +#include <stack> |
| 16 | + |
6 | 17 | namespace facebook { |
7 | 18 | namespace graphql { |
8 | | -namespace rapidjson { |
| 19 | +namespace response { |
9 | 20 |
|
10 | | -Value convertResponse(Document::AllocatorType& allocator, response::Value&& response) |
| 21 | +void writeResponse(rapidjson::Writer<rapidjson::StringBuffer>& writer, Value&& response) |
11 | 22 | { |
12 | 23 | switch (response.type()) |
13 | 24 | { |
14 | | - case response::Type::Map: |
| 25 | + case Type::Map: |
15 | 26 | { |
16 | | - Value result(Type::kObjectType); |
17 | | - auto members = response.release<response::MapType>(); |
| 27 | + auto members = response.release<MapType>(); |
| 28 | + |
| 29 | + writer.StartObject(); |
18 | 30 |
|
19 | 31 | for (auto& entry : members) |
20 | 32 | { |
21 | | - result.AddMember( |
22 | | - Value(entry.first.c_str(), static_cast<SizeType>(entry.first.size()), allocator), |
23 | | - convertResponse(allocator, std::move(entry.second)), allocator); |
| 33 | + writer.Key(entry.first.c_str()); |
| 34 | + writeResponse(writer, std::move(entry.second)); |
24 | 35 | } |
25 | 36 |
|
26 | | - return result; |
| 37 | + writer.EndObject(); |
| 38 | + break; |
27 | 39 | } |
28 | 40 |
|
29 | | - case response::Type::List: |
| 41 | + case Type::List: |
30 | 42 | { |
31 | | - Value result(Type::kArrayType); |
32 | | - auto elements = response.release<response::ListType>(); |
| 43 | + auto elements = response.release<ListType>(); |
| 44 | + |
| 45 | + writer.StartArray(); |
33 | 46 |
|
34 | | - result.Reserve(static_cast<SizeType>(elements.size()), allocator); |
35 | 47 | for (auto& entry : elements) |
36 | 48 | { |
37 | | - result.PushBack(convertResponse(allocator, std::move(entry)), allocator); |
| 49 | + writeResponse(writer, std::move(entry)); |
38 | 50 | } |
39 | 51 |
|
40 | | - return result; |
| 52 | + writer.EndArray(); |
| 53 | + break; |
41 | 54 | } |
42 | 55 |
|
43 | | - case response::Type::String: |
44 | | - case response::Type::EnumValue: |
| 56 | + case Type::String: |
| 57 | + case Type::EnumValue: |
45 | 58 | { |
46 | | - Value result(Type::kStringType); |
47 | | - auto value = response.release<response::StringType>(); |
| 59 | + auto value = response.release<StringType>(); |
48 | 60 |
|
49 | | - result.SetString(value.c_str(), static_cast<SizeType>(value.size()), allocator); |
50 | | - |
51 | | - return result; |
| 61 | + writer.String(value.c_str()); |
| 62 | + break; |
52 | 63 | } |
53 | 64 |
|
54 | | - case response::Type::Null: |
| 65 | + case Type::Null: |
55 | 66 | { |
56 | | - Value result(Type::kNullType); |
57 | | - |
58 | | - return result; |
| 67 | + writer.Null(); |
| 68 | + break; |
59 | 69 | } |
60 | 70 |
|
61 | | - case response::Type::Boolean: |
| 71 | + case Type::Boolean: |
62 | 72 | { |
63 | | - Value result(response.get<response::BooleanType>() |
64 | | - ? Type::kTrueType |
65 | | - : Type::kFalseType); |
66 | | - |
67 | | - return result; |
| 73 | + writer.Bool(response.get<BooleanType>()); |
| 74 | + break; |
68 | 75 | } |
69 | 76 |
|
70 | | - case response::Type::Int: |
| 77 | + case Type::Int: |
71 | 78 | { |
72 | | - Value result(Type::kNumberType); |
73 | | - |
74 | | - result.SetInt(response.get<response::IntType>()); |
75 | | - |
76 | | - return result; |
| 79 | + writer.Int(response.get<IntType>()); |
| 80 | + break; |
77 | 81 | } |
78 | 82 |
|
79 | | - case response::Type::Float: |
| 83 | + case Type::Float: |
80 | 84 | { |
81 | | - Value result(Type::kNumberType); |
82 | | - |
83 | | - result.SetDouble(response.get<response::FloatType>()); |
84 | | - |
85 | | - return result; |
| 85 | + writer.Double(response.get<FloatType>()); |
| 86 | + break; |
86 | 87 | } |
87 | 88 |
|
88 | | - case response::Type::Scalar: |
| 89 | + case Type::Scalar: |
89 | 90 | { |
90 | | - return convertResponse(allocator, response.release<response::ScalarType>()); |
| 91 | + writeResponse(writer, response.release<ScalarType>()); |
| 92 | + break; |
91 | 93 | } |
92 | 94 |
|
93 | 95 | default: |
94 | 96 | { |
95 | | - return Value(Type::kNullType); |
| 97 | + writer.Null(); |
| 98 | + break; |
96 | 99 | } |
97 | 100 | } |
98 | 101 | } |
99 | 102 |
|
100 | | -Document convertResponse(response::Value&& response) |
| 103 | +std::string toJSON(Value&& response) |
101 | 104 | { |
102 | | - Document document; |
103 | | - auto result = convertResponse(document.GetAllocator(), std::move(response)); |
| 105 | + rapidjson::StringBuffer buffer; |
| 106 | + rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); |
104 | 107 |
|
105 | | - static_cast<Value&>(document).Swap(result); |
106 | | - |
107 | | - return document; |
| 108 | + writeResponse(writer, std::move(response)); |
| 109 | + return buffer.GetString(); |
108 | 110 | } |
109 | 111 |
|
110 | | - |
111 | | -response::Value convertResponse(const Value& value) |
| 112 | +struct ResponseHandler |
| 113 | + : rapidjson::BaseReaderHandler<rapidjson::UTF8<>, ResponseHandler> |
112 | 114 | { |
113 | | - switch (value.GetType()) |
| 115 | + ResponseHandler() |
114 | 116 | { |
115 | | - case Type::kNullType: |
116 | | - return response::Value(); |
| 117 | + // Start with a single null value. |
| 118 | + _responseStack.push({}); |
| 119 | + } |
117 | 120 |
|
118 | | - case Type::kFalseType: |
119 | | - return response::Value(false); |
| 121 | + Value getResponse() |
| 122 | + { |
| 123 | + auto response = std::move(_responseStack.top()); |
120 | 124 |
|
121 | | - case Type::kTrueType: |
122 | | - return response::Value(true); |
| 125 | + _responseStack.pop(); |
123 | 126 |
|
124 | | - case Type::kObjectType: |
125 | | - { |
126 | | - response::Value response(response::Type::Map); |
| 127 | + return response; |
| 128 | + } |
127 | 129 |
|
128 | | - response.reserve(static_cast<size_t>(value.MemberCount())); |
129 | | - for (const auto& member : value.GetObject()) |
130 | | - { |
131 | | - response.emplace_back(member.name.GetString(), |
132 | | - convertResponse(member.value)); |
133 | | - } |
| 130 | + bool Null() |
| 131 | + { |
| 132 | + setValue(Value()); |
| 133 | + return true; |
| 134 | + } |
134 | 135 |
|
135 | | - return response; |
136 | | - } |
| 136 | + bool Bool(bool b) |
| 137 | + { |
| 138 | + setValue(Value(b)); |
| 139 | + return true; |
| 140 | + } |
137 | 141 |
|
138 | | - case Type::kArrayType: |
139 | | - { |
140 | | - response::Value response(response::Type::List); |
| 142 | + bool Int(int i) |
| 143 | + { |
| 144 | + auto value = Value(Type::Int); |
141 | 145 |
|
142 | | - response.reserve(static_cast<size_t>(value.Size())); |
143 | | - for (const auto& element : value.GetArray()) |
144 | | - { |
145 | | - response.emplace_back(convertResponse(element)); |
146 | | - } |
| 146 | + value.set<IntType>(std::move(i)); |
| 147 | + setValue(std::move(value)); |
| 148 | + return true; |
| 149 | + } |
147 | 150 |
|
148 | | - return response; |
149 | | - } |
| 151 | + bool Uint(unsigned int i) |
| 152 | + { |
| 153 | + return Int(static_cast<int>(i)); |
| 154 | + } |
150 | 155 |
|
151 | | - case Type::kStringType: |
152 | | - return response::Value(std::string(value.GetString())); |
| 156 | + bool Int64(int64_t i) |
| 157 | + { |
| 158 | + return Int(static_cast<int>(i)); |
| 159 | + } |
153 | 160 |
|
154 | | - case Type::kNumberType: |
| 161 | + bool Uint64(uint64_t i) |
| 162 | + { |
| 163 | + return Int(static_cast<int>(i)); |
| 164 | + } |
| 165 | + |
| 166 | + bool Double(double d) |
| 167 | + { |
| 168 | + auto value = Value(Type::Float); |
| 169 | + |
| 170 | + value.set<FloatType>(std::move(d)); |
| 171 | + setValue(std::move(value)); |
| 172 | + return true; |
| 173 | + } |
| 174 | + |
| 175 | + bool String(const Ch* str, rapidjson::SizeType /*length*/, bool /*copy*/) |
| 176 | + { |
| 177 | + setValue(Value(std::string(str))); |
| 178 | + return true; |
| 179 | + } |
| 180 | + |
| 181 | + bool StartObject() |
| 182 | + { |
| 183 | + _responseStack.push(Value(Type::Map)); |
| 184 | + return true; |
| 185 | + } |
| 186 | + |
| 187 | + bool Key(const Ch* str, rapidjson::SizeType /*length*/, bool /*copy*/) |
| 188 | + { |
| 189 | + _key = str; |
| 190 | + return true; |
| 191 | + } |
| 192 | + |
| 193 | + bool EndObject(rapidjson::SizeType /*count*/) |
| 194 | + { |
| 195 | + setValue(getResponse()); |
| 196 | + return true; |
| 197 | + } |
| 198 | + |
| 199 | + bool StartArray() |
| 200 | + { |
| 201 | + _responseStack.push(Value(Type::List)); |
| 202 | + return true; |
| 203 | + } |
| 204 | + |
| 205 | + bool EndArray(rapidjson::SizeType /*count*/) |
| 206 | + { |
| 207 | + setValue(getResponse()); |
| 208 | + return true; |
| 209 | + } |
| 210 | + |
| 211 | +private: |
| 212 | + void setValue(Value&& value) |
| 213 | + { |
| 214 | + switch (_responseStack.top().type()) |
155 | 215 | { |
156 | | - response::Value response(value.IsInt() |
157 | | - ? response::Type::Int |
158 | | - : response::Type::Float); |
| 216 | + case Type::Map: |
| 217 | + _responseStack.top().emplace_back(std::move(_key), std::move(value)); |
| 218 | + break; |
159 | 219 |
|
160 | | - if (value.IsInt()) |
161 | | - { |
162 | | - response.set<response::IntType>(value.GetInt()); |
163 | | - } |
164 | | - else |
165 | | - { |
166 | | - response.set<response::FloatType>(value.GetDouble()); |
167 | | - } |
| 220 | + case Type::List: |
| 221 | + _responseStack.top().emplace_back(std::move(value)); |
| 222 | + break; |
168 | 223 |
|
169 | | - return response; |
| 224 | + default: |
| 225 | + _responseStack.top() = std::move(value); |
| 226 | + break; |
170 | 227 | } |
171 | | - |
172 | | - default: |
173 | | - return response::Value(); |
174 | 228 | } |
175 | | -} |
176 | 229 |
|
177 | | -response::Value convertResponse(const Document& document) |
| 230 | + std::string _key; |
| 231 | + std::stack<Value> _responseStack; |
| 232 | +}; |
| 233 | + |
| 234 | +Value parseJSON(const std::string& json) |
178 | 235 | { |
179 | | - return convertResponse(static_cast<const Value&>(document)); |
| 236 | + ResponseHandler handler; |
| 237 | + rapidjson::Reader reader; |
| 238 | + rapidjson::StringStream ss(json.c_str()); |
| 239 | + |
| 240 | + reader.Parse(ss, handler); |
| 241 | + |
| 242 | + return handler.getResponse(); |
180 | 243 | } |
181 | 244 |
|
182 | | -} /* namespace rapidjson */ |
| 245 | +} /* namespace response */ |
183 | 246 | } /* namespace graphql */ |
184 | 247 | } /* namespace facebook */ |
0 commit comments