Methods for conversion between solr and internal sort spec
[yaz-moved-to-github.git] / src / sortspec.c
1 /* This file is part of the YAZ toolkit.
2  * Copyright (C) 1995-2012 Index Data
3  * See the file LICENSE for details.
4  */
5 /**
6  * \file sortspec.c
7  * \brief Implements SortSpec parsing.
8  */
9 #if HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16
17 #include <yaz/z-core.h>
18 #include <yaz/sortspec.h>
19 #include <yaz/oid_db.h>
20 #include <yaz/wrbuf.h>
21
22 Z_SortKeySpecList *yaz_sort_spec(ODR out, const char *arg)
23 {
24     char sort_string_buf[64], sort_flags[64];
25     Z_SortKeySpecList *sksl = (Z_SortKeySpecList *)
26         odr_malloc(out, sizeof(*sksl));
27     int off;
28
29     sksl->num_specs = 0;
30     sksl->specs = (Z_SortKeySpec **)odr_malloc(out, sizeof(sksl->specs) * 20);
31
32     while ((sscanf(arg, "%63s %63s%n", sort_string_buf,
33                    sort_flags, &off)) == 2  && off > 1)
34     {
35         int i;
36         char *sort_string_sep;
37         char *sort_string = sort_string_buf;
38         Z_SortKeySpec *sks = (Z_SortKeySpec *) odr_malloc(out, sizeof(*sks));
39         Z_SortKey *sk = (Z_SortKey *) odr_malloc(out, sizeof(*sk));
40
41         arg += off;
42         sksl->specs[sksl->num_specs++] = sks;
43         sks->sortElement = (Z_SortElement *)
44             odr_malloc(out, sizeof(*sks->sortElement));
45         sks->sortElement->which = Z_SortElement_generic;
46         sks->sortElement->u.generic = sk;
47
48         if ((sort_string_sep = strchr(sort_string, '=')))
49         {
50             int i = 0;
51             sk->which = Z_SortKey_sortAttributes;
52             sk->u.sortAttributes = (Z_SortAttributes *)
53                 odr_malloc(out, sizeof(*sk->u.sortAttributes));
54             sk->u.sortAttributes->id = odr_oiddup(out, yaz_oid_attset_bib_1);
55             sk->u.sortAttributes->list = (Z_AttributeList *)
56                 odr_malloc(out, sizeof(*sk->u.sortAttributes->list));
57             sk->u.sortAttributes->list->attributes = (Z_AttributeElement **)
58                 odr_malloc(out, 10 *
59                             sizeof(*sk->u.sortAttributes->list->attributes));
60             while (i < 10 && sort_string && sort_string_sep)
61             {
62                 Z_AttributeElement *el = (Z_AttributeElement *)
63                     odr_malloc(out, sizeof(*el));
64                 sk->u.sortAttributes->list->attributes[i] = el;
65                 el->attributeSet = 0;
66                 el->attributeType = odr_intdup(out, atoi(sort_string));
67                 el->which = Z_AttributeValue_numeric;
68                 el->value.numeric =
69                     odr_intdup(out, odr_atoi(sort_string_sep + 1));
70                 i++;
71                 sort_string = strchr(sort_string, ',');
72                 if (sort_string)
73                 {
74                     sort_string++;
75                     sort_string_sep = strchr(sort_string, '=');
76                 }
77             }
78             sk->u.sortAttributes->list->num_attributes = i;
79         }
80         else
81         {
82             sk->which = Z_SortKey_sortField;
83             sk->u.sortField = odr_strdup (out, sort_string);
84         }
85         sks->sortRelation = odr_intdup(out, Z_SortKeySpec_ascending);
86         sks->caseSensitivity = odr_intdup(out, Z_SortKeySpec_caseInsensitive);
87
88         sks->which = Z_SortKeySpec_null;
89         sks->u.null = odr_nullval ();
90
91         for (i = 0; sort_flags[i]; i++)
92         {
93             switch (sort_flags[i])
94             {
95             case 'd':
96             case 'D':
97             case '>':
98                 *sks->sortRelation = Z_SortKeySpec_descending;
99                 break;
100             case 'a':
101             case 'A':
102             case '<':
103                 *sks->sortRelation = Z_SortKeySpec_ascending;
104                 break;
105             case 'i':
106             case 'I':
107                 *sks->caseSensitivity = Z_SortKeySpec_caseInsensitive;
108                 break;
109             case 'S':
110             case 's':
111                 *sks->caseSensitivity = Z_SortKeySpec_caseSensitive;
112                 break;
113             case '!':
114                 sks->which = Z_SortKeySpec_abort;
115                 sks->u.abort = odr_nullval();
116                 break;
117             case '=':
118                 sks->which = Z_SortKeySpec_missingValueData;
119                 sks->u.missingValueData = (Odr_oct*)
120                     odr_malloc(out, sizeof(Odr_oct));
121                 i++;
122                 sks->u.missingValueData->len = strlen(sort_flags+i);
123                 sks->u.missingValueData->size = sks->u.missingValueData->len;
124                 sks->u.missingValueData->buf = (unsigned char*)
125                                           odr_strdup(out, sort_flags+i);
126                 i += strlen(sort_flags+i) - 1;
127                 break;
128             }
129         }
130     }
131     if (!sksl->num_specs)
132         return 0;
133     return sksl;
134 }
135
136 int yaz_sort_spec_to_cql(Z_SortKeySpecList *sksl, WRBUF w)
137 {
138     int i;
139     for (i = 0; i < sksl->num_specs; i++)
140     {
141         Z_SortKeySpec *sks = sksl->specs[i];
142         Z_SortKey *sk;
143
144         if (sks->sortElement->which != Z_SortElement_generic)
145             return -1;
146
147         sk = sks->sortElement->u.generic;
148         if (i)
149             wrbuf_puts(w, " ");
150         else
151             wrbuf_puts(w, " SORTBY ");
152         if (sk->which == Z_SortKey_sortAttributes)
153             return -1;
154         else if (sk->which == Z_SortKey_sortField)
155             wrbuf_puts(w, sk->u.sortField);
156         switch (*sks->sortRelation)
157         {
158         case Z_SortKeySpec_ascending:
159             wrbuf_puts(w, "/ascending");
160             break;
161         case Z_SortKeySpec_descending:
162             wrbuf_puts(w, "/descending");
163             break;
164         }
165         switch (*sks->caseSensitivity)
166         {
167         case Z_SortKeySpec_caseSensitive:
168             wrbuf_puts(w, "/respectCase");
169             break;
170         case Z_SortKeySpec_caseInsensitive:
171             wrbuf_puts(w, "/ignoreCase");
172             break;
173         }
174         switch (sks->which)
175         {
176         case Z_SortKeySpec_null:
177             break;
178         case Z_SortKeySpec_abort:
179             wrbuf_puts(w, "/missingFail");
180             break;
181         case Z_SortKeySpec_missingValueData:
182             wrbuf_puts(w, "/missingValue=");
183             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
184                         sks->u.missingValueData->len);
185             break;
186         }
187     }
188     return 0;
189 }
190
191 int yaz_sort_spec_to_type7(Z_SortKeySpecList *sksl, WRBUF pqf)
192 {
193     int i;
194     for (i = 0; i < sksl->num_specs; i++)
195     {
196         Z_SortKeySpec *sks = sksl->specs[i];
197         Z_SortKey *sk;
198
199         if (sks->sortElement->which != Z_SortElement_generic)
200             return -1;
201
202         sk = sks->sortElement->u.generic;
203
204         wrbuf_insert(pqf, 0, "@or ", 4);
205
206         if (sk->which == Z_SortKey_sortAttributes)
207         {
208             int j;
209             for (j = 0; j < sk->u.sortAttributes->list->num_attributes; j++)
210             {
211                 Z_AttributeElement *el =
212                     sk->u.sortAttributes->list->attributes[j];
213                 if (el->which != Z_AttributeValue_numeric)
214                     return -1;
215                 wrbuf_printf(pqf, " @attr " ODR_INT_PRINTF "=" ODR_INT_PRINTF,
216                              *el->attributeType, *el->value.numeric);
217             }
218         }
219         else if (sk->which == Z_SortKey_sortField)
220         {
221             wrbuf_puts(pqf, " @attr 1=");
222             wrbuf_puts(pqf, sk->u.sortField);
223         }
224         switch (*sks->sortRelation)
225         {
226         case Z_SortKeySpec_ascending:
227             wrbuf_puts(pqf, " @attr 7=1 ");
228             break;
229         case Z_SortKeySpec_descending:
230             wrbuf_puts(pqf, " @attr 7=2 ");
231             break;
232         }
233         wrbuf_printf(pqf, "%d", i);
234     }
235     return 0;
236 }
237
238 int yaz_sort_spec_to_srw_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
239 {
240     int i;
241     for (i = 0; i < sksl->num_specs; i++)
242     {
243         Z_SortKeySpec *sks = sksl->specs[i];
244         Z_SortKey *sk;
245
246         if (sks->sortElement->which != Z_SortElement_generic)
247             return -1;
248
249         sk = sks->sortElement->u.generic;
250
251         if (i)
252             wrbuf_puts(w, " ");
253
254         if (sk->which == Z_SortKey_sortAttributes)
255             return -1;
256         else if (sk->which == Z_SortKey_sortField)
257         {
258             wrbuf_puts(w, sk->u.sortField);
259         }
260         wrbuf_puts(w, ",,"); /* path is absent */
261         switch (*sks->sortRelation)
262         {
263         case Z_SortKeySpec_ascending:
264             wrbuf_puts(w, "1");
265             break;
266         case Z_SortKeySpec_descending:
267             wrbuf_puts(w, "0");
268             break;
269         }
270         wrbuf_puts(w, ",");
271         switch (*sks->caseSensitivity)
272         {
273         case Z_SortKeySpec_caseSensitive:
274             wrbuf_puts(w, "1");
275             break;
276         case Z_SortKeySpec_caseInsensitive:
277             wrbuf_puts(w, "0");
278             break;
279         }
280         wrbuf_puts(w, ",");
281         switch (sks->which)
282         {
283         case Z_SortKeySpec_null:
284             wrbuf_puts(w, "highValue");
285             break;
286         case Z_SortKeySpec_abort:
287             wrbuf_puts(w, "abort");
288             break;
289         case Z_SortKeySpec_missingValueData:
290             wrbuf_write(w, (const char *) sks->u.missingValueData->buf,
291                         sks->u.missingValueData->len);
292             break;
293         }
294     }
295     return 0;
296 }
297
298 int yaz_sort_spec_to_solr_sortkeys(Z_SortKeySpecList *sksl, WRBUF w)
299 {
300     int i;
301     for (i = 0; i < sksl->num_specs; i++)
302     {
303         Z_SortKeySpec *sks = sksl->specs[i];
304         Z_SortKey *sk;
305
306         if (sks->sortElement->which != Z_SortElement_generic)
307             return -1;
308
309         sk = sks->sortElement->u.generic;
310
311         if (i)
312             wrbuf_puts(w, ",");
313
314         if (sk->which == Z_SortKey_sortAttributes)
315             return -1;
316         else if (sk->which == Z_SortKey_sortField)
317         {
318             wrbuf_puts(w, sk->u.sortField);
319         }
320         switch (*sks->sortRelation)
321         {
322         case Z_SortKeySpec_ascending:
323             wrbuf_puts(w, " asc");
324             break;
325         case Z_SortKeySpec_descending:
326             wrbuf_puts(w, " desc");
327             break;
328         }
329     }
330     return 0;
331 }
332
333
334 int yaz_srw_sortkeys_to_sort_spec(const char *srw_sortkeys, WRBUF w)
335 {
336     /* sru sortkey layout: path,schema,ascending,caseSensitive,missingValue */
337     /* see cql_sortby_to_sortkeys of YAZ. */
338     char **sortspec;
339     int num_sortspec = 0;
340     int i;
341     NMEM nmem = nmem_create();
342
343     if (srw_sortkeys)
344         nmem_strsplit_blank(nmem, srw_sortkeys, &sortspec, &num_sortspec);
345     if (num_sortspec > 0)
346     {
347         for (i = 0; i < num_sortspec; i++)
348         {
349             char **arg;
350             int num_arg;
351             int ascending = 1;
352             int case_sensitive = 0;
353             const char *missing = 0;
354             nmem_strsplitx(nmem, ",", sortspec[i], &arg, &num_arg, 0);
355
356             if (num_arg > 2 && arg[2][0])
357                 ascending = atoi(arg[2]);
358             if (num_arg > 3 && arg[3][0])
359                 case_sensitive = atoi(arg[3]);
360             if (num_arg > 4 && arg[4][0])
361                 missing = arg[4];
362
363             if (i)
364                 wrbuf_puts(w, " ");
365
366             wrbuf_puts(w, arg[0]); /* field */
367             wrbuf_puts(w, " ");
368
369             wrbuf_puts(w, ascending ? "a" : "d");
370             wrbuf_puts(w, case_sensitive ? "s" : "i");
371             if (missing)
372             {
373                 if (!strcmp(missing, "omit")) {
374                     ;
375                 }
376                 else if (!strcmp(missing, "abort"))
377                     wrbuf_puts(w, "!");
378                 else if (!strcmp(missing, "lowValue")) {
379                     ;
380                 }
381                 else if (!strcmp(missing, "highValue")) {
382                     ;
383                 }
384                 else
385                 {
386                     wrbuf_puts(w, "=");
387                     wrbuf_puts(w, missing);
388                 }
389             }
390         }
391     }
392     nmem_destroy(nmem);
393     return 0;
394 }
395
396 int yaz_solr_sortkeys_to_sort_spec(const char *solr_sortkeys, WRBUF w)
397 {
398     /* Solr sortkey layout: field order[, field order] */
399     /* see cql_sortby_to_sortkeys of YAZ. */
400     char **sortspec;
401     int num_sortspec = 0;
402     int i;
403     NMEM nmem = nmem_create();
404
405     if (solr_sortkeys)
406         nmem_strsplit(nmem, ",", solr_sortkeys, &sortspec, &num_sortspec);
407     if (num_sortspec > 0)
408     {
409         for (i = 0; i < num_sortspec; i++)
410         {
411             char **arg;
412             int num_arg;
413             char order = 'a';
414             int case_sensitive = 0;
415             nmem_strsplitx(nmem, " ", sortspec[i], &arg, &num_arg, 0);
416
417             if (num_arg != 2)
418                 return 0;
419
420             if (arg[1][0]) {
421                 order = tolower(arg[1][0]);
422             }
423             if (order != 'a' || order != 'd')
424                 return 0;
425
426             if (i)
427                 wrbuf_puts(w, " ");
428
429             wrbuf_puts(w, arg[0]); /* field */
430             wrbuf_puts(w, " ");
431
432             wrbuf_putc(w, order);
433             // Always in-sensitive
434             wrbuf_puts(w, case_sensitive ? "s" : "i");
435         }
436     }
437     nmem_destroy(nmem);
438     return 0;
439 }
440
441
442 /*
443  * Local variables:
444  * c-basic-offset: 4
445  * c-file-style: "Stroustrup"
446  * indent-tabs-mode: nil
447  * End:
448  * vim: shiftwidth=4 tabstop=8 expandtab
449  */
450