|
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