Support of criteria.optional
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 10 Nov 2014 13:40:34 +0000 (14:40 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 10 Nov 2014 13:40:34 +0000 (14:40 +0100)
src/sparql.c
test/test_sparql.c

index fb6c302..b85ee76 100644 (file)
@@ -104,22 +104,19 @@ static const char *lookup_attr_string(Z_AttributeList *attributes, int type)
     return 0;
 }
 
-static int apt(yaz_sparql_t s,
-               WRBUF addinfo,
-               void (*pr)(const char *buf, void *client_data),
-               void *client_data,
+static int apt(yaz_sparql_t s, WRBUF addinfo, WRBUF res, WRBUF vars,
                Z_AttributesPlusTerm *q, int indent)
 {
     Z_Term *term = q->term;
     Odr_int v = lookup_attr_numeric(q->attributes, 1);
     struct sparql_entry *e = 0;
     const char *cp;
+    const char *use_var = 0;
     int i;
 
-    pr("  ", client_data);
+    wrbuf_puts(res, "  ");
     for (i = 0; i < indent; i++)
-        pr(" ", client_data);
-
+        wrbuf_puts(res, " ");
     if (v)
     {
         for (e = s->conf; e; e = e->next)
@@ -160,8 +157,18 @@ static int apt(yaz_sparql_t s,
     }
     assert(e);
     wrbuf_rewind(addinfo);
+
     for (cp = e->value; *cp; cp++)
     {
+        if (strchr(" \t\r\n\f", *cp) && !use_var)
+        {
+            use_var = e->value;
+            if (strchr("$?", e->value[0]))
+            {
+                wrbuf_write(vars, e->value + 1, cp - e->value - 1);
+                wrbuf_puts(vars, " ");
+            }
+        }
         if (*cp == '%')
         {
             switch (*++cp)
@@ -206,17 +213,13 @@ static int apt(yaz_sparql_t s,
         else
             wrbuf_putc(addinfo, *cp);
     }
-    pr(wrbuf_cstr(addinfo), client_data);
+    wrbuf_puts(res, wrbuf_cstr(addinfo));
     return 0;
 }
 
 
-static int rpn_structure(yaz_sparql_t s,
-                         WRBUF addinfo,
-                         void (*pr)(const char *buf,
-                                    void *client_data),
-                         void *client_data,
-                         Z_RPNStructure *q, int indent)
+static int rpn_structure(yaz_sparql_t s, WRBUF addinfo,
+                         WRBUF res, WRBUF vars, Z_RPNStructure *q, int indent)
 {
     int i;
     if (q->which == Z_RPNStructure_complex)
@@ -226,33 +229,29 @@ static int rpn_structure(yaz_sparql_t s,
         Z_Operator *op = c->roperator;
         if (op->which == Z_Operator_and)
         {
-            r = rpn_structure(s, addinfo, pr, client_data, c->s1,
-                              indent);
+            r = rpn_structure(s, addinfo, res, vars, c->s1, indent);
             if (r)
                 return r;
-            pr(" .\n", client_data);
-            return rpn_structure(s, addinfo, pr, client_data, c->s2,
-                                 indent);
+            wrbuf_puts(res, " .\n");
+            return rpn_structure(s, addinfo, res, vars, c->s2, indent);
         }
         else if (op->which == Z_Operator_or)
         {
             for (i = 0; i < indent; i++)
-                pr(" ", client_data);
-            pr("  {\n", client_data);
-            r = rpn_structure(s, addinfo, pr, client_data, c->s1,
-                              indent + 1);
+                wrbuf_puts(res, " ");
+            wrbuf_puts(res, "  {\n");
+            r = rpn_structure(s, addinfo, res, vars, c->s1, indent + 1);
             if (r)
                 return r;
-            pr("\n", client_data);
+            wrbuf_puts(res, "\n");
             for (i = 0; i < indent; i++)
-                pr(" ", client_data);
-            pr("  } UNION {\n", client_data);
-            r = rpn_structure(s, addinfo, pr, client_data, c->s2,
-                indent + 1);
-            pr("\n", client_data);
+                wrbuf_puts(res, " ");
+            wrbuf_puts(res, "  } UNION {\n");
+            r = rpn_structure(s, addinfo, res, vars, c->s2, indent + 1);
+            wrbuf_puts(res, "\n");
             for (i = 0; i < indent; i++)
-                pr(" ", client_data);
-            pr("  }", client_data);
+                wrbuf_puts(res, " ");
+            wrbuf_puts(res, "  }");
             return r;
         }
         else
@@ -264,8 +263,7 @@ static int rpn_structure(yaz_sparql_t s,
     {
         Z_Operand *op = q->u.simple;
         if (op->which == Z_Operand_APT)
-            return apt(s, addinfo, pr, client_data, op->u.attributesPlusTerm,
-                indent);
+            return apt(s, addinfo, res, vars, op->u.attributesPlusTerm, indent);
         else
             return YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM;
     }
@@ -317,6 +315,10 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
         {
             ;
         }
+        else if (!strcmp(e->pattern, "criteria.optional"))
+        {
+            ;
+        }
         else if (!strncmp(e->pattern, "index.", 6))
         {
             ;
@@ -352,8 +354,49 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
         }
     }
     if (!errors)
-        r = rpn_structure(s, addinfo, pr, client_data, q->RPNStructure, 0);
+    {
+        WRBUF res = wrbuf_alloc();
+        WRBUF vars = wrbuf_alloc();
+        r = rpn_structure(s, addinfo, res, vars, q->RPNStructure, 0);
+        if (r == 0)
+        {
+            WRBUF t_var = wrbuf_alloc();
+            for (e = s->conf; e; e = e->next)
+            {
+                if (!strcmp(e->pattern, "criteria.optional"))
+                {
+                    int optional = 1;
+                    size_t i = strlen(e->value), j;
+
+                    while (i > 0 && strchr(" \t\r\n\f", e->value[i-1]))
+                        --i;
+                    j = i;
+                    while (i > 0 && !strchr("$?", e->value[i-1]))
+                        --i;
+                    if (i > 0 && j > i)
+                    {
+                        wrbuf_rewind(t_var);
+                        wrbuf_write(t_var, e->value + i, j - i);
+                        wrbuf_puts(t_var, " ");
+                        if (strstr(wrbuf_cstr(vars), wrbuf_cstr(t_var)))
+                            optional = 0;
+                    }
 
+                    pr("  ", client_data);
+                    if (optional)
+                        pr("OPTIONAL { ", client_data);
+                    pr(e->value, client_data);
+                    if (optional)
+                        pr(" }", client_data);
+                    pr(" .\n", client_data);
+                }
+            }
+            pr(wrbuf_cstr(res), client_data);
+            wrbuf_destroy(t_var);
+        }
+        wrbuf_destroy(res);
+        wrbuf_destroy(vars);
+    }
     pr("\n}\n", client_data);
     yaz_tok_cfg_destroy(cfg);
 
index 6ead793..cee9550 100644 (file)
@@ -83,6 +83,8 @@ static void tst1(void)
     yaz_sparql_add_pattern(s, "criteria", "?work bf:note ?description");
     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceOf ?work");
     yaz_sparql_add_pattern(s, "criteria", "?inst bf:instanceTitle/bf:titleValue ?ititle");
+    yaz_sparql_add_pattern(s, "criteria.optional", "?inst bf:heldBy ?lib");
+
     yaz_sparql_add_pattern(s, "index.bf.title",
                            "?work bf:workTitle/bf:titleValue ?o1 "
                            "FILTER(contains(?o1, %s))");
@@ -119,6 +121,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  ?work bf:workTitle/bf:titleValue ?o1 "
                   "FILTER(contains(?o1, \"computer\"))\n"
                   "}\n"
@@ -138,6 +141,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  ?work bf:creator/bf:label ?o2 "
                   "FILTER(contains(?o2, \"london\"))\n"
                   "}\n"));
@@ -157,6 +161,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  ?work bf:creator/bf:label ?o2 "
                   "FILTER(contains(?o2, \"london\")) .\n"
                   "  ?work bf:workTitle/bf:titleValue ?o1 "
@@ -177,6 +182,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  {\n"
                   "   ?work bf:creator/bf:label ?o2 "
                   "FILTER(contains(?o2, \"london\"))\n"
@@ -201,6 +207,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  {\n"
                   "   {\n"
                   "    ?work bf:creator/bf:label ?o2 "
@@ -230,6 +237,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  {\n"
                   "   ?work bf:creator/bf:label ?o2 "
                   "FILTER(contains(?o2, \"a\")) .\n"
@@ -256,6 +264,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  ?work bf:creator/bf:label ?o2 "
                   "FILTER(contains(?o2, \"a\")) .\n"
                   "  ?work bf:workTitle/bf:titleValue ?o1 "
@@ -280,6 +289,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  ?inst bf:heldBy ?lib .\n"
                   "  ?work bf:workTitle/bf:titleValue ?o1 "
                   "FILTER(contains(?o1, \"Phantom Tollbooth\")) .\n"
                   "  ?lib gs:nearby (40.1583 83.0742 30)\n"
@@ -300,6 +310,7 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  OPTIONAL { ?inst bf:heldBy ?lib } .\n"
                   "  ?inst bf:ISBN \"9780316154697\"\n"
                   "}\n"
                  ));