Skip to content

Commit 8d1889f

Browse files
committed
Export a type erased JSON writer object
1 parent dae73e5 commit 8d1889f

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
@@ -280,6 +280,102 @@ template <>
280280
GRAPHQLRESPONSE_EXPORT IdType Value::release<IdType>();
281281
#endif // GRAPHQL_DLLEXPORTS
282282

283+
class Writer
284+
{
285+
private:
286+
struct Concept
287+
{
288+
virtual ~Concept() = default;
289+
290+
virtual void start_object() const = 0;
291+
virtual void add_member(const std::string& key) const = 0;
292+
virtual void end_object() const = 0;
293+
294+
virtual void start_array() const = 0;
295+
virtual void end_arrary() const = 0;
296+
297+
virtual void write_null() const = 0;
298+
virtual void write_string(const std::string& value) const = 0;
299+
virtual void write_bool(bool value) const = 0;
300+
virtual void write_int(int value) const = 0;
301+
virtual void write_float(double value) const = 0;
302+
};
303+
304+
template <class T>
305+
struct Model : Concept
306+
{
307+
Model(std::unique_ptr<T>&& pimpl)
308+
: _pimpl { std::move(pimpl) }
309+
{
310+
}
311+
312+
void start_object() const final
313+
{
314+
_pimpl->start_object();
315+
}
316+
317+
void add_member(const std::string& key) const final
318+
{
319+
_pimpl->add_member(key);
320+
}
321+
322+
void end_object() const final
323+
{
324+
_pimpl->end_object();
325+
}
326+
327+
void start_array() const final
328+
{
329+
_pimpl->start_array();
330+
}
331+
332+
void end_arrary() const final
333+
{
334+
_pimpl->end_arrary();
335+
}
336+
337+
void write_null() const final
338+
{
339+
_pimpl->write_null();
340+
}
341+
342+
void write_string(const std::string& value) const final
343+
{
344+
_pimpl->write_string(value);
345+
}
346+
347+
void write_bool(bool value) const final
348+
{
349+
_pimpl->write_bool(value);
350+
}
351+
352+
void write_int(int value) const final
353+
{
354+
_pimpl->write_int(value);
355+
}
356+
357+
void write_float(double value) const final
358+
{
359+
_pimpl->write_float(value);
360+
}
361+
362+
private:
363+
std::unique_ptr<T> _pimpl;
364+
};
365+
366+
const std::shared_ptr<const Concept> _concept;
367+
368+
public:
369+
template <class T>
370+
Writer(std::unique_ptr<T> writer)
371+
: _concept { std::static_pointer_cast<Concept>(
372+
std::make_shared<Model<T>>(std::move(writer))) }
373+
{
374+
}
375+
376+
GRAPHQLRESPONSE_EXPORT void write(Value value) const;
377+
};
378+
283379
} // namespace graphql::response
284380

285381
#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)