19
19
#include < gflags/gflags.h>
20
20
#include < glog/logging.h>
21
21
22
+ #include < argparse/argparse.hpp>
22
23
#include < fstream>
23
24
24
25
#ifndef VERSION
25
26
#define VERSION " 0.0.0"
26
27
#endif
27
28
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
-
38
29
int 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
+ }
44
90
45
91
google::InitGoogleLogging (argv[0 ]);
46
92
FLAGS_colorlogtostderr = true ;
47
93
google::InstallFailureSignalHandler ();
48
94
google::LogToStderr ();
49
95
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);
70
99
std::string dot;
100
+ std::string error_msg;
71
101
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 " ) ;
76
106
if (dot_filename.find (" .dot" ) == std::string::npos)
77
107
dot_filename += " .dot" ;
78
108
79
109
std::ofstream fout (dot_filename);
80
110
if (fout.is_open ()) {
81
111
fout << dot;
82
112
fout.close ();
83
- LOG (INFO) << " dump dot file into " << dot_filename;
113
+ LOG (INFO) << " save dot file: " << dot_filename;
84
114
} else {
85
115
LOG (ERROR) << " Can not open file " << dot_filename;
86
116
}
117
+ } else {
118
+ LOG (INFO) << dot;
87
119
}
88
120
} else {
89
121
LOG (ERROR) << error_msg;
90
- goto FAILED;
91
122
}
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);
96
126
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;
109
136
goto FAILED;
110
137
}
138
+ geojson_text.assign (std::istreambuf_iterator<char >(fin),
139
+ std::istreambuf_iterator<char >());
140
+ fin.close ();
111
141
112
142
geos::io::GeoJSONFeatureCollection fc ({});
113
143
// read geojson features
114
144
geos::io::GeoJSONReader reader;
115
145
fc = reader.readFeatures (geojson_text);
116
146
LOG (INFO) << " load " << fc.getFeatures ().size () << " features from "
117
- << FLAGS_geojson ;
147
+ << features ;
118
148
119
149
std::map<cql2cpp::FeatureSourcePtr, const geos::io::GeoJSONFeature*>
120
150
fs_feature;
@@ -124,31 +154,73 @@ int main(int argc, char** argv) {
124
154
fs_feature[fp] = &feature;
125
155
}
126
156
157
+ std::string query = filter_command.get <std::string>(" query" );
158
+
127
159
cql2cpp::Cql2Cpp<const geos::io::GeoJSONFeature*> cql2cpp;
128
160
cql2cpp.set_feature_source (fs_feature);
129
161
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);
136
166
} else {
137
167
LOG (ERROR) << " filter error: " << cql2cpp.error_msg ();
138
168
}
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 ();
139
199
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.."
142
210
<< fc.getFeatures ().size () - 1 << " ]" ;
143
211
goto FAILED;
144
212
}
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;
146
217
147
218
std::string dot;
148
219
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" );
152
224
if (dot_filename.find (" .dot" ) == std::string::npos)
153
225
dot_filename += " .dot" ;
154
226
@@ -160,10 +232,15 @@ int main(int argc, char** argv) {
160
232
} else {
161
233
LOG (ERROR) << " Can not open file " << dot_filename;
162
234
}
235
+ } else {
236
+ LOG (INFO) << dot;
163
237
}
164
238
} else {
165
239
LOG (ERROR) << error_msg;
166
240
}
241
+
242
+ } else {
243
+ LOG (ERROR) << " unknown sub-command" ;
167
244
}
168
245
169
246
gflags::ShutDownCommandLineFlags ();
0 commit comments