Skip to content

Commit 172dff7

Browse files
committed
Export a type erased JSON writer object
1 parent 80dba3a commit 172dff7

File tree

3 files changed

+228
-70
lines changed

3 files changed

+228
-70
lines changed

include/graphqlservice/GraphQLResponse.h

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,102 @@ GRAPHQLRESPONSE_EXPORT IdType Value::release<IdType>();
263263

264264
using AwaitableValue = internal::Awaitable<Value>;
265265

266+
class Writer
267+
{
268+
private:
269+
struct Concept
270+
{
271+
virtual ~Concept() = default;
272+
273+
virtual void start_object() const = 0;
274+
virtual void add_member(const std::string& key) const = 0;
275+
virtual void end_object() const = 0;
276+
277+
virtual void start_array() const = 0;
278+
virtual void end_arrary() const = 0;
279+
280+
virtual void write_null() const = 0;
281+
virtual void write_string(const std::string& value) const = 0;
282+
virtual void write_bool(bool value) const = 0;
283+
virtual void write_int(int value) const = 0;
284+
virtual void write_float(double value) const = 0;
285+
};
286+
287+
template <class T>
288+
struct Model : Concept
289+
{
290+
Model(std::unique_ptr<T>&& pimpl)
291+
: _pimpl { std::move(pimpl) }
292+
{
293+
}
294+
295+
void start_object() const final
296+
{
297+
_pimpl->start_object();
298+
}
299+
300+
void add_member(const std::string& key) const final
301+
{
302+
_pimpl->add_member(key);
303+
}
304+
305+
void end_object() const final
306+
{
307+
_pimpl->end_object();
308+
}
309+
310+
void start_array() const final
311+
{
312+
_pimpl->start_array();
313+
}
314+
315+
void end_arrary() const final
316+
{
317+
_pimpl->end_arrary();
318+
}
319+
320+
void write_null() const final
321+
{
322+
_pimpl->write_null();
323+
}
324+
325+
void write_string(const std::string& value) const final
326+
{
327+
_pimpl->write_string(value);
328+
}
329+
330+
void write_bool(bool value) const final
331+
{
332+
_pimpl->write_bool(value);
333+
}
334+
335+
void write_int(int value) const final
336+
{
337+
_pimpl->write_int(value);
338+
}
339+
340+
void write_float(double value) const final
341+
{
342+
_pimpl->write_float(value);
343+
}
344+
345+
private:
346+
std::unique_ptr<T> _pimpl;
347+
};
348+
349+
const std::shared_ptr<const Concept> _concept;
350+
351+
public:
352+
template <class T>
353+
Writer(std::unique_ptr<T> writer)
354+
: _concept { std::static_pointer_cast<Concept>(
355+
std::make_shared<Model<T>>(std::move(writer))) }
356+
{
357+
}
358+
359+
GRAPHQLRESPONSE_EXPORT void write(Value value) const;
360+
};
361+
266362
} // namespace graphql::response
267363

268364
#endif // GRAPHQLRESPONSE_H

src/GraphQLResponse.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,4 +695,86 @@ const Value& Value::operator[](size_t index) const
695695
return std::get<ListType>(_data).at(index);
696696
}
697697

698+
void Writer::write(Value response) const
699+
{
700+
switch (response.type())
701+
{
702+
case Type::Map:
703+
{
704+
auto members = response.release<MapType>();
705+
706+
_concept->start_object();
707+
708+
for (auto& entry : members)
709+
{
710+
_concept->add_member(entry.first);
711+
write(std::move(entry.second));
712+
}
713+
714+
_concept->end_object();
715+
break;
716+
}
717+
718+
case Type::List:
719+
{
720+
auto elements = response.release<ListType>();
721+
722+
_concept->start_array();
723+
724+
for (auto& entry : elements)
725+
{
726+
write(std::move(entry));
727+
}
728+
729+
_concept->end_arrary();
730+
break;
731+
}
732+
733+
case Type::String:
734+
case Type::EnumValue:
735+
{
736+
auto value = response.release<StringType>();
737+
738+
_concept->write_string(value);
739+
break;
740+
}
741+
742+
case Type::Null:
743+
{
744+
_concept->write_null();
745+
break;
746+
}
747+
748+
case Type::Boolean:
749+
{
750+
_concept->write_bool(response.get<BooleanType>());
751+
break;
752+
}
753+
754+
case Type::Int:
755+
{
756+
_concept->write_int(response.get<IntType>());
757+
break;
758+
}
759+
760+
case Type::Float:
761+
{
762+
_concept->write_float(response.get<FloatType>());
763+
break;
764+
}
765+
766+
case Type::Scalar:
767+
{
768+
write(response.release<ScalarType>());
769+
break;
770+
}
771+
772+
default:
773+
{
774+
_concept->write_null();
775+
break;
776+
}
777+
}
778+
}
779+
698780
} // namespace graphql::response

src/JSONResponse.cpp

Lines changed: 50 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,94 +16,74 @@
1616

1717
namespace graphql::response {
1818

19-
void writeResponse(rapidjson::Writer<rapidjson::StringBuffer>& writer, Value&& response)
19+
class StringWriter
2020
{
21-
switch (response.type())
21+
public:
22+
StringWriter(rapidjson::StringBuffer& buffer)
23+
: _writer { buffer }
2224
{
23-
case Type::Map:
24-
{
25-
auto members = response.release<MapType>();
26-
27-
writer.StartObject();
28-
29-
for (auto& entry : members)
30-
{
31-
writer.Key(entry.first.c_str());
32-
writeResponse(writer, std::move(entry.second));
33-
}
34-
35-
writer.EndObject();
36-
break;
37-
}
38-
39-
case Type::List:
40-
{
41-
auto elements = response.release<ListType>();
42-
43-
writer.StartArray();
25+
}
4426

45-
for (auto& entry : elements)
46-
{
47-
writeResponse(writer, std::move(entry));
48-
}
27+
void start_object()
28+
{
29+
_writer.StartObject();
30+
}
4931

50-
writer.EndArray();
51-
break;
52-
}
32+
void add_member(const std::string& key)
33+
{
34+
_writer.Key(key.c_str());
35+
}
5336

54-
case Type::String:
55-
case Type::EnumValue:
56-
{
57-
auto value = response.release<StringType>();
37+
void end_object()
38+
{
39+
_writer.EndObject();
40+
}
5841

59-
writer.String(value.c_str());
60-
break;
61-
}
42+
void start_array()
43+
{
44+
_writer.StartArray();
45+
}
6246

63-
case Type::Null:
64-
{
65-
writer.Null();
66-
break;
67-
}
47+
void end_arrary()
48+
{
49+
_writer.EndArray();
50+
}
6851

69-
case Type::Boolean:
70-
{
71-
writer.Bool(response.get<BooleanType>());
72-
break;
73-
}
52+
void write_null()
53+
{
54+
_writer.Null();
55+
}
7456

75-
case Type::Int:
76-
{
77-
writer.Int(response.get<IntType>());
78-
break;
79-
}
57+
void write_string(const std::string& value)
58+
{
59+
_writer.String(value.c_str());
60+
}
8061

81-
case Type::Float:
82-
{
83-
writer.Double(response.get<FloatType>());
84-
break;
85-
}
62+
void write_bool(bool value)
63+
{
64+
_writer.Bool(value);
65+
}
8666

87-
case Type::Scalar:
88-
{
89-
writeResponse(writer, response.release<ScalarType>());
90-
break;
91-
}
67+
void write_int(int value)
68+
{
69+
_writer.Int(value);
70+
}
9271

93-
default:
94-
{
95-
writer.Null();
96-
break;
97-
}
72+
void write_float(double value)
73+
{
74+
_writer.Double(value);
9875
}
99-
}
76+
77+
private:
78+
rapidjson::Writer<rapidjson::StringBuffer> _writer;
79+
};
10080

10181
std::string toJSON(Value&& response)
10282
{
10383
rapidjson::StringBuffer buffer;
104-
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
84+
Writer writer { std::make_unique<StringWriter>(buffer) };
10585

106-
writeResponse(writer, std::move(response));
86+
writer.write(std::move(response));
10787
return buffer.GetString();
10888
}
10989

0 commit comments

Comments
 (0)