1919#include < gflags/gflags.h>
2020#include < glog/logging.h>
2121
22+ #include < argparse/argparse.hpp>
2223#include < fstream>
2324
2425#ifndef VERSION
2526#define VERSION " 0.0.0"
2627#endif
2728
28- DEFINE_string (query, " " , " cql2 query string" );
29- DEFINE_string (geojson, " " ,
30- " geojson data set with multiple features in one feature "
31- " collection to be queried" );
32- DEFINE_string (dot, " " , " generate dot file" );
33- DEFINE_uint32 (index, 0 ,
34- " the dot file will generated according to the feature with this "
35- " index in geojson file" );
36- DEFINE_bool (verbose, false , " Enable verbose output" );
37-
3829int main (int argc, char ** argv) {
39- gflags::SetUsageMessage (
40- " Usage: cql2 -query=\" city='Toronto'\" "
41- " -geojson=\" path/to/feature_collection.geojson\" -index=0" );
42- gflags::SetVersionString (VERSION);
43- gflags::ParseCommandLineFlags (&argc, &argv, true );
30+ argparse::ArgumentParser program (" cql2" , VERSION);
31+
32+ argparse::ArgumentParser parse_command (" parse" , " " ,
33+ argparse::default_arguments::help);
34+ parse_command.add_description (" parse a cql2 query and print dot file" );
35+ parse_command.add_argument (" query" ).help (" cql2 query string" );
36+ parse_command.add_argument (" -V" , " --verbose" )
37+ .help (" print verbose debug log" )
38+ .flag ();
39+ parse_command.add_argument (" -O" , " --output" ).help (" the output dot file" );
40+
41+ argparse::ArgumentParser filter_command (" filter" , " " ,
42+ argparse::default_arguments::help);
43+ filter_command.add_description (
44+ " filter features from geojson data collection" );
45+ filter_command.add_argument (" query" ).help (" cql2 query string" );
46+ filter_command.add_argument (" --features" )
47+ .help (
48+ " geojson file contains multiple features in one feature collection" );
49+ filter_command.add_argument (" -V" , " --verbose" )
50+ .help (" print verbose debug log" )
51+ .flag ();
52+
53+ argparse::ArgumentParser sql_command (" sql" , " " ,
54+ argparse::default_arguments::help);
55+ sql_command.add_argument (" query" ).help (" cql2 query string" );
56+ sql_command.add_argument (" -V" , " --verbose" )
57+ .help (" print verbose debug log" )
58+ .flag ();
59+
60+ argparse::ArgumentParser eval_command (" evaluate" , " " ,
61+ argparse::default_arguments::help);
62+ eval_command.add_argument (" query" ).help (" cql2 query string" );
63+ eval_command.add_argument (" --features" )
64+ .help (
65+ " geojson file contains multiple features in one feature collection" );
66+ eval_command.add_argument (" --index" )
67+ .help (" index of feature in the geojson file to be evaluated" )
68+ .scan <' i' , int >();
69+ eval_command.add_argument (" -O" , " --output" ).help (" the output dot file" );
70+ eval_command.add_argument (" -V" , " --verbose" )
71+ .help (" print verbose debug log" )
72+ .flag ();
73+
74+ program.add_subparser (parse_command);
75+ program.add_subparser (filter_command);
76+ program.add_subparser (sql_command);
77+ program.add_subparser (eval_command);
78+
79+ if (argc == 1 ) {
80+ std::cout << program;
81+ return 0 ;
82+ }
83+
84+ try {
85+ program.parse_args (argc, argv);
86+ } catch (const std::exception& e) {
87+ LOG (ERROR) << e.what ();
88+ return 1 ;
89+ }
4490
4591 google::InitGoogleLogging (argv[0 ]);
4692 FLAGS_colorlogtostderr = true ;
4793 google::InstallFailureSignalHandler ();
4894 google::LogToStderr ();
4995
50- if (FLAGS_query.empty ()) {
51- gflags::ShowUsageWithFlagsRestrict (argv[0 ], " main.cc" );
52- LOG (ERROR) << " you should provide query" ;
53- return -1 ;
54- }
55-
56- // print flags
57- LOG (INFO) << " ==== flags ====" ;
58- LOG (INFO) << " query: " << FLAGS_query;
59- LOG (INFO) << " geojson: " << FLAGS_geojson;
60- LOG (INFO) << " dot: " << FLAGS_dot;
61-
62- if (FLAGS_verbose) cql2cpp::AstNode::set_ostream (&std::cout);
63-
64- std::string error_msg;
65-
66- // case 1:
67- // we have only query without any feature
68- // just parse the query and may dump a dot file
69- if (FLAGS_geojson.empty ()) {
96+ if (program.is_subcommand_used (" parse" )) {
97+ if (parse_command.get <bool >(" --verbose" ))
98+ cql2cpp::AstNode::set_ostream (&std::cout);
7099 std::string dot;
100+ std::string error_msg;
71101 cql2cpp::Cql2Cpp<geos::io::GeoJSONFeature> cql2cpp;
72- if (cql2cpp.ToDot (FLAGS_query , &dot, &error_msg)) {
73- LOG (INFO) << error_msg;
74- if (not FLAGS_dot. empty ( )) {
75- std::string dot_filename = FLAGS_dot ;
102+ if (cql2cpp.ToDot (parse_command. get <std::string>( " query " ) , &dot,
103+ & error_msg)) {
104+ if (parse_command. is_used ( " --output " )) {
105+ std::string dot_filename = parse_command. get <std::string>( " --output " ) ;
76106 if (dot_filename.find (" .dot" ) == std::string::npos)
77107 dot_filename += " .dot" ;
78108
79109 std::ofstream fout (dot_filename);
80110 if (fout.is_open ()) {
81111 fout << dot;
82112 fout.close ();
83- LOG (INFO) << " dump dot file into " << dot_filename;
113+ LOG (INFO) << " save dot file: " << dot_filename;
84114 } else {
85115 LOG (ERROR) << " Can not open file " << dot_filename;
86116 }
117+ } else {
118+ LOG (INFO) << dot;
87119 }
88120 } else {
89121 LOG (ERROR) << error_msg;
90- goto FAILED;
91122 }
92- } else {
93- // case 2:
94- // we have query and a feature collection
95- // filter matched features from the feature collection
123+ } else if (program.is_subcommand_used (" filter" )) {
124+ if (filter_command.get <bool >(" --verbose" ))
125+ cql2cpp::AstNode::set_ostream (&std::cout);
96126 std::string geojson_text;
97- std::ifstream fin (FLAGS_geojson);
98- if (fin.good ()) {
99- if (fin.is_open ()) {
100- geojson_text.assign (std::istreambuf_iterator<char >(fin),
101- std::istreambuf_iterator<char >());
102- fin.close ();
103- } else {
104- LOG (ERROR) << " can not open " << FLAGS_geojson;
105- goto FAILED;
106- }
107- } else {
108- LOG (ERROR) << FLAGS_geojson << " not exist" ;
127+ std::string features = filter_command.get <std::string>(" --features" );
128+ std::ifstream fin (features);
129+
130+ if (not fin.good ()) {
131+ LOG (ERROR) << features << " not exist" ;
132+ goto FAILED;
133+ }
134+ if (not fin.is_open ()) {
135+ LOG (ERROR) << " can not open " << features;
109136 goto FAILED;
110137 }
138+ geojson_text.assign (std::istreambuf_iterator<char >(fin),
139+ std::istreambuf_iterator<char >());
140+ fin.close ();
111141
112142 geos::io::GeoJSONFeatureCollection fc ({});
113143 // read geojson features
114144 geos::io::GeoJSONReader reader;
115145 fc = reader.readFeatures (geojson_text);
116146 LOG (INFO) << " load " << fc.getFeatures ().size () << " features from "
117- << FLAGS_geojson ;
147+ << features ;
118148
119149 std::map<cql2cpp::FeatureSourcePtr, const geos::io::GeoJSONFeature*>
120150 fs_feature;
@@ -124,31 +154,73 @@ int main(int argc, char** argv) {
124154 fs_feature[fp] = &feature;
125155 }
126156
157+ std::string query = filter_command.get <std::string>(" query" );
158+
127159 cql2cpp::Cql2Cpp<const geos::io::GeoJSONFeature*> cql2cpp;
128160 cql2cpp.set_feature_source (fs_feature);
129161 std::vector<const geos::io::GeoJSONFeature*> result;
130- if (cql2cpp.filter (FLAGS_query, &result)) {
131- LOG (INFO) << " get feature count: " << result.size ();
132- for (const auto & feature : result) {
133- LOG (INFO) << " get feature geometry: "
134- << feature->getGeometry ()->toText ();
135- }
162+ if (cql2cpp.filter (query, &result)) {
163+ LOG (INFO) << result.size () << " features match the filter:" ;
164+ geos::io::GeoJSONWriter writer;
165+ for (const auto & feature : result) LOG (INFO) << writer.write (*feature);
136166 } else {
137167 LOG (ERROR) << " filter error: " << cql2cpp.error_msg ();
138168 }
169+ } else if (program.is_subcommand_used (" sql" )) {
170+ if (sql_command.get <bool >(" --verbose" ))
171+ cql2cpp::AstNode::set_ostream (&std::cout);
172+ std::string query = sql_command.get <std::string>(" query" );
173+ std::string sql_where;
174+ std::string error_msg;
175+ if (cql2cpp::Cql2Cpp<void *>::ConvertToSQL (query, &sql_where, &error_msg)) {
176+ LOG (INFO) << sql_where;
177+ } else {
178+ LOG (ERROR) << error_msg;
179+ goto FAILED;
180+ }
181+ } else if (program.is_subcommand_used (" evaluate" )) {
182+ if (eval_command.get <bool >(" --verbose" )) {
183+ cql2cpp::AstNode::set_ostream (&std::cout);
184+ }
185+ std::string geojson_text;
186+ std::string features = eval_command.get <std::string>(" --features" );
187+ std::ifstream fin (features);
188+ if (not fin.good ()) {
189+ LOG (ERROR) << features << " not exist" ;
190+ goto FAILED;
191+ }
192+ if (not fin.is_open ()) {
193+ LOG (ERROR) << " can not open " << features;
194+ goto FAILED;
195+ }
196+ geojson_text.assign (std::istreambuf_iterator<char >(fin),
197+ std::istreambuf_iterator<char >());
198+ fin.close ();
139199
140- if (FLAGS_index >= fc.getFeatures ().size ()) {
141- LOG (ERROR) << " index(" << FLAGS_index << " ) out of range [0.."
200+ geos::io::GeoJSONFeatureCollection fc ({});
201+ // read geojson features
202+ geos::io::GeoJSONReader reader;
203+ fc = reader.readFeatures (geojson_text);
204+ LOG (INFO) << " load " << fc.getFeatures ().size () << " features from "
205+ << features;
206+
207+ int index = eval_command.get <int >(" index" );
208+ if (index >= fc.getFeatures ().size ()) {
209+ LOG (ERROR) << " index(" << index << " ) out of range [0.."
142210 << fc.getFeatures ().size () - 1 << " ]" ;
143211 goto FAILED;
144212 }
145- cql2cpp::FeatureSourceGeoJson fs (fc.getFeatures ().at (FLAGS_index));
213+ cql2cpp::FeatureSourceGeoJson fs (fc.getFeatures ().at (index));
214+ std::string query = eval_command.get <std::string>(" query" );
215+
216+ cql2cpp::Cql2Cpp<const geos::io::GeoJSONFeature*> cql2cpp;
146217
147218 std::string dot;
148219 bool eval_result;
149- if (cql2cpp.Evaluate (FLAGS_query, fs, &eval_result, &error_msg, &dot)) {
150- if (not FLAGS_dot.empty ()) {
151- std::string dot_filename = FLAGS_dot;
220+ std::string error_msg;
221+ if (cql2cpp.Evaluate (query, fs, &eval_result, &error_msg, &dot)) {
222+ if (eval_command.is_used (" --output" )) {
223+ std::string dot_filename = eval_command.get <std::string>(" --output" );
152224 if (dot_filename.find (" .dot" ) == std::string::npos)
153225 dot_filename += " .dot" ;
154226
@@ -160,10 +232,15 @@ int main(int argc, char** argv) {
160232 } else {
161233 LOG (ERROR) << " Can not open file " << dot_filename;
162234 }
235+ } else {
236+ LOG (INFO) << dot;
163237 }
164238 } else {
165239 LOG (ERROR) << error_msg;
166240 }
241+
242+ } else {
243+ LOG (ERROR) << " unknown sub-command" ;
167244 }
168245
169246 gflags::ShutDownCommandLineFlags ();
0 commit comments