@@ -128,15 +128,76 @@ ParseResult<search::SchemaField::TagParams> ParseTagParams(CmdArgParser* parser)
128
128
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
129
129
#endif
130
130
131
- ParseResult<search::Schema> ParseSchema (DocIndex::DataType type, CmdArgParser* parser) {
132
- search::Schema schema;
131
+ using ParsedSchemaField =
132
+ ParseResult<std::pair<search::SchemaField::FieldType, search::SchemaField::ParamsVariant>>;
133
+
134
+ // Tag fields include: [separator char] [casesensitive]
135
+ ParsedSchemaField ParseTag (CmdArgParser* parser) {
136
+ auto tag_params = ParseTagParams (parser);
137
+ if (!tag_params) {
138
+ return make_unexpected (tag_params.error ());
139
+ }
140
+ return std::make_pair (search::SchemaField::TAG, std::move (tag_params).value ());
141
+ }
142
+
143
+ ParsedSchemaField ParseText (CmdArgParser* parser) {
144
+ return std::make_pair (search::SchemaField::TEXT, std::monostate{});
145
+ }
146
+
147
+ ParsedSchemaField ParseNumeric (CmdArgParser* parser) {
148
+ return std::make_pair (search::SchemaField::NUMERIC, std::monostate{});
149
+ }
150
+
151
+ // Vector fields include: {algorithm} num_args args...
152
+ ParsedSchemaField ParseVector (CmdArgParser* parser) {
153
+ auto vector_params = ParseVectorParams (parser);
154
+
155
+ if (parser->HasError ()) {
156
+ auto err = *parser->Error ();
157
+ VLOG (1 ) << " Could not parse vector param " << err.index ;
158
+ return CreateSyntaxError (" Parse error of vector parameters" sv);
159
+ }
160
+
161
+ if (vector_params.dim == 0 ) {
162
+ return CreateSyntaxError (" Knn vector dimension cannot be zero" sv);
163
+ }
164
+ return std::make_pair (search::SchemaField::VECTOR, vector_params);
165
+ }
166
+
167
+ // ON HASH | JSON
168
+ ParseResult<bool > ParseOnOption (CmdArgParser* parser, DocIndex* index) {
169
+ index ->type = parser->MapNext (" HASH" sv, DocIndex::HASH, " JSON" sv, DocIndex::JSON);
170
+ return true ;
171
+ }
172
+
173
+ // PREFIX count prefix [prefix ...]
174
+ ParseResult<bool > ParsePrefix (CmdArgParser* parser, DocIndex* index) {
175
+ if (!parser->Check (" 1" )) {
176
+ return CreateSyntaxError (" Multiple prefixes are not supported" sv);
177
+ }
178
+ index ->prefix = parser->Next <std::string>();
179
+ return true ;
180
+ }
181
+
182
+ // STOPWORDS count [words...]
183
+ ParseResult<bool > ParseStopwords (CmdArgParser* parser, DocIndex* index) {
184
+ index ->options .stopwords .clear ();
185
+ for (size_t num = parser->Next <size_t >(); num > 0 ; num--) {
186
+ index ->options .stopwords .emplace (parser->Next ());
187
+ }
188
+ return true ;
189
+ }
190
+
191
+ // SCHEMA field [AS alias] type [flags...]
192
+ ParseResult<bool > ParseSchema (CmdArgParser* parser, DocIndex* index) {
193
+ auto & schema = index ->schema ;
133
194
134
195
while (parser->HasNext ()) {
135
196
string_view field = parser->Next ();
136
197
string_view field_alias = field;
137
198
138
199
// Verify json path is correct
139
- if (type == DocIndex::JSON && !IsValidJsonPath (field)) {
200
+ if (index -> type == DocIndex::JSON && !IsValidJsonPath (field)) {
140
201
return CreateSyntaxError (absl::StrCat (" Bad json path: " sv, field));
141
202
}
142
203
@@ -145,61 +206,38 @@ ParseResult<search::Schema> ParseSchema(DocIndex::DataType type, CmdArgParser* p
145
206
146
207
// Determine type
147
208
using search::SchemaField;
148
- auto type = parser->MapNext (" TAG" sv, SchemaField::TAG, " TEXT" sv, SchemaField::TEXT, " NUMERIC" sv,
149
- SchemaField::NUMERIC, " VECTOR" sv, SchemaField::VECTOR);
150
-
151
- // Tag fields include: [separator char] [casesensitive]
152
- // Vector fields include: {algorithm} num_args args...
153
- search::SchemaField::ParamsVariant params (monostate{});
154
- if (type == search::SchemaField::TAG) {
155
- auto tag_params = ParseTagParams (parser);
156
- if (!tag_params) {
157
- return make_unexpected (tag_params.error ());
158
- }
159
- params = tag_params.value ();
160
- } else if (type == search::SchemaField::VECTOR && !parser->HasError ()) {
161
- auto vector_params = ParseVectorParams (parser);
162
-
163
- if (parser->HasError ()) {
164
- auto err = *parser->Error ();
165
- VLOG (1 ) << " Could not parse vector param " << err.index ;
166
- return CreateSyntaxError (" Parse error of vector parameters" sv);
167
- }
168
-
169
- if (vector_params.dim == 0 ) {
170
- return CreateSyntaxError (" Knn vector dimension cannot be zero" sv);
171
- }
172
- params = vector_params;
209
+ auto parsed_params = parser->MapNext (" TAG" sv, &ParseTag, " TEXT" sv, &ParseText, " NUMERIC" sv,
210
+ &ParseNumeric, " VECTOR" sv, &ParseVector)(parser);
211
+ if (!parsed_params) {
212
+ return make_unexpected (parsed_params.error ());
173
213
}
174
214
215
+ auto [field_type, params] = std::move (parsed_params).value ();
216
+
175
217
// Flags: check for SORTABLE and NOINDEX
176
218
uint8_t flags = 0 ;
177
219
while (parser->HasNext ()) {
178
- if (parser->Check (" NOINDEX" )) {
179
- flags |= search::SchemaField::NOINDEX;
180
- continue ;
220
+ auto flag = parser->TryMapNext (" NOINDEX" , search::SchemaField::NOINDEX, " SORTABLE" ,
221
+ search::SchemaField::SORTABLE);
222
+ if (!flag) {
223
+ break ;
181
224
}
182
225
183
- if (parser->Check (" SORTABLE" )) {
184
- flags |= search::SchemaField::SORTABLE;
185
- continue ;
186
- }
187
-
188
- break ;
226
+ flags |= *flag;
189
227
}
190
228
191
229
// Skip all trailing ignored parameters
192
230
while (kIgnoredOptions .count (parser->Peek ()) > 0 )
193
231
parser->Skip (2 );
194
232
195
- schema.fields [field] = {type , flags, string{field_alias}, params};
233
+ schema.fields [field] = {field_type , flags, string{field_alias}, params};
196
234
}
197
235
198
236
// Build field name mapping table
199
237
for (const auto & [field_ident, field_info] : schema.fields )
200
238
schema.field_names [field_info.short_name ] = field_ident;
201
239
202
- return schema ;
240
+ return false ;
203
241
}
204
242
205
243
#ifndef __clang__
@@ -210,39 +248,23 @@ ParseResult<DocIndex> ParseCreateParams(CmdArgParser* parser) {
210
248
DocIndex index {};
211
249
212
250
while (parser->HasNext ()) {
213
- // ON HASH | JSON
214
- if (parser->Check (" ON" )) {
215
- index .type = parser->MapNext (" HASH" sv, DocIndex::HASH, " JSON" sv, DocIndex::JSON);
216
- continue ;
217
- }
251
+ auto option_parser =
252
+ parser->TryMapNext (" ON" sv, &ParseOnOption, " PREFIX" sv, &ParsePrefix, " STOPWORDS" sv,
253
+ &ParseStopwords, " SCHEMA" sv, &ParseSchema);
218
254
219
- // PREFIX count prefix [prefix ...]
220
- if (parser->Check (" PREFIX" )) {
221
- if (!parser->Check (" 1" ))
222
- return CreateSyntaxError (" Multiple prefixes are not supported" sv);
223
- index .prefix = string (parser->Next ());
255
+ if (!option_parser) {
256
+ // Unsupported parameters are ignored for now
257
+ parser->Skip (1 );
224
258
continue ;
225
259
}
226
260
227
- // STOWORDS count [words...]
228
- if (parser->Check (" STOPWORDS" )) {
229
- index .options .stopwords .clear ();
230
- for (size_t num = parser->Next <size_t >(); num > 0 ; num--)
231
- index .options .stopwords .emplace (parser->Next ());
232
- continue ;
261
+ auto parse_result = option_parser.value ()(parser, &index );
262
+ if (!parse_result) {
263
+ return make_unexpected (parse_result.error ());
233
264
}
234
-
235
- // SCHEMA
236
- if (parser->Check (" SCHEMA" )) {
237
- auto schema = ParseSchema (index .type , parser);
238
- if (!schema)
239
- return make_unexpected (schema.error ());
240
- index .schema = std::move (*schema);
241
- break ; // SCHEMA always comes last
265
+ if (!parse_result.value ()) {
266
+ break ;
242
267
}
243
-
244
- // Unsupported parameters are ignored for now
245
- parser->Skip (1 );
246
268
}
247
269
248
270
return index ;
@@ -661,22 +683,23 @@ void SearchFamily::FtAlter(CmdArgList args, const CommandContext& cmd_cntx) {
661
683
}
662
684
663
685
// Parse additional schema
664
- auto new_fields = ParseSchema (index_info->type , &parser);
665
- if (SendErrorIfOccurred (new_fields, &parser, builder)) {
686
+ DocIndex new_index{.type = index_info->type };
687
+ auto parse_result = ParseSchema (&parser, &new_index);
688
+ if (SendErrorIfOccurred (parse_result, &parser, builder)) {
666
689
cmd_cntx.tx ->Conclude ();
667
690
return ;
668
691
}
669
692
693
+ auto & new_fields = new_index.schema ;
694
+
670
695
// For logging we copy the whole schema
671
696
// TODO: Use a more efficient way for logging
672
- LOG (INFO)
673
- << " Adding "
674
- << DocIndexInfo{.base_index = DocIndex{.schema = new_fields.value ()}}.BuildRestoreCommand ();
697
+ LOG (INFO) << " Adding " << DocIndexInfo{.base_index = new_index}.BuildRestoreCommand ();
675
698
676
699
// Merge schemas
677
700
search::Schema& schema = index_info->schema ;
678
- schema.fields .insert (new_fields-> fields .begin (), new_fields-> fields .end ());
679
- schema.field_names .insert (new_fields-> field_names .begin (), new_fields-> field_names .end ());
701
+ schema.fields .insert (new_fields. fields .begin (), new_fields. fields .end ());
702
+ schema.field_names .insert (new_fields. field_names .begin (), new_fields. field_names .end ());
680
703
681
704
// Rebuild index
682
705
// TODO: Introduce partial rebuild
0 commit comments