SPARQL: Add support for local variables: %v yaz-799
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 12 Nov 2014 12:11:30 +0000 (13:11 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 12 Nov 2014 12:12:00 +0000 (13:12 +0100)
src/sparql.c
test/test_sparql.c

index b85ee76..a848a9d 100644 (file)
@@ -105,7 +105,7 @@ static const char *lookup_attr_string(Z_AttributeList *attributes, int type)
 }
 
 static int apt(yaz_sparql_t s, WRBUF addinfo, WRBUF res, WRBUF vars,
-               Z_AttributesPlusTerm *q, int indent)
+               Z_AttributesPlusTerm *q, int indent, int *var_no)
 {
     Z_Term *term = q->term;
     Odr_int v = lookup_attr_numeric(q->attributes, 1);
@@ -205,6 +205,9 @@ static int apt(yaz_sparql_t s, WRBUF addinfo, WRBUF res, WRBUF vars,
                     break;
                 }
                 break;
+            case 'v':
+                wrbuf_printf(addinfo, "?v%d", *var_no);
+                break;
             case '%':
                 wrbuf_putc(addinfo, '%');
                 break;
@@ -214,12 +217,14 @@ static int apt(yaz_sparql_t s, WRBUF addinfo, WRBUF res, WRBUF vars,
             wrbuf_putc(addinfo, *cp);
     }
     wrbuf_puts(res, wrbuf_cstr(addinfo));
+    (*var_no)++;
     return 0;
 }
 
 
 static int rpn_structure(yaz_sparql_t s, WRBUF addinfo,
-                         WRBUF res, WRBUF vars, Z_RPNStructure *q, int indent)
+                         WRBUF res, WRBUF vars, Z_RPNStructure *q, int indent,
+                         int *var_no)
 {
     int i;
     if (q->which == Z_RPNStructure_complex)
@@ -229,25 +234,25 @@ static int rpn_structure(yaz_sparql_t s, WRBUF addinfo,
         Z_Operator *op = c->roperator;
         if (op->which == Z_Operator_and)
         {
-            r = rpn_structure(s, addinfo, res, vars, c->s1, indent);
+            r = rpn_structure(s, addinfo, res, vars, c->s1, indent, var_no);
             if (r)
                 return r;
             wrbuf_puts(res, " .\n");
-            return rpn_structure(s, addinfo, res, vars, c->s2, indent);
+            return rpn_structure(s, addinfo, res, vars, c->s2, indent, var_no);
         }
         else if (op->which == Z_Operator_or)
         {
             for (i = 0; i < indent; i++)
                 wrbuf_puts(res, " ");
             wrbuf_puts(res, "  {\n");
-            r = rpn_structure(s, addinfo, res, vars, c->s1, indent + 1);
+            r = rpn_structure(s, addinfo, res, vars, c->s1, indent + 1, var_no);
             if (r)
                 return r;
             wrbuf_puts(res, "\n");
             for (i = 0; i < indent; i++)
                 wrbuf_puts(res, " ");
             wrbuf_puts(res, "  } UNION {\n");
-            r = rpn_structure(s, addinfo, res, vars, c->s2, indent + 1);
+            r = rpn_structure(s, addinfo, res, vars, c->s2, indent + 1, var_no);
             wrbuf_puts(res, "\n");
             for (i = 0; i < indent; i++)
                 wrbuf_puts(res, " ");
@@ -263,7 +268,8 @@ static int rpn_structure(yaz_sparql_t s, WRBUF addinfo,
     {
         Z_Operand *op = q->u.simple;
         if (op->which == Z_Operand_APT)
-            return apt(s, addinfo, res, vars, op->u.attributesPlusTerm, indent);
+            return apt(s, addinfo, res, vars, op->u.attributesPlusTerm, indent,
+                       var_no);
         else
             return YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM;
     }
@@ -357,7 +363,8 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
     {
         WRBUF res = wrbuf_alloc();
         WRBUF vars = wrbuf_alloc();
-        r = rpn_structure(s, addinfo, res, vars, q->RPNStructure, 0);
+        int var_no = 0;
+        r = rpn_structure(s, addinfo, res, vars, q->RPNStructure, 0, &var_no);
         if (r == 0)
         {
             WRBUF t_var = wrbuf_alloc();
index cee9550..f67dbcc 100644 (file)
@@ -319,11 +319,125 @@ static void tst1(void)
     yaz_sparql_destroy(s);
 }
 
+static void tst2(void)
+{
+    yaz_sparql_t s = yaz_sparql_create();
+
+    yaz_sparql_add_pattern(s, "prefix",
+                           "rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns");
+    yaz_sparql_add_pattern(s, "prefix",
+                           "bf: <http://bibframe.org/vocab/>");
+    yaz_sparql_add_pattern(s, "prefix",
+                           "gs: http://gs.com/panorama/domain-model");
+    yaz_sparql_add_pattern(s, "field.title", "?title");
+    yaz_sparql_add_pattern(s, "field.author", "?author");
+    yaz_sparql_add_pattern(s, "field.description", "?description");
+    yaz_sparql_add_pattern(s, "field.instanceTitle", "?ititle");
+    yaz_sparql_add_pattern(s, "criteria", "?work a bf:Work");
+    yaz_sparql_add_pattern(s, "criteria", "?work bf:workTitle/bf:titleValue ?title");
+    yaz_sparql_add_pattern(s, "criteria", "?work bf:creator/bf:label ?author");
+    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 %v "
+                           "FILTER(contains(%v, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.creator",
+                           "?work bf:creator/bf:label %v "
+                           "FILTER(contains(%v, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.authorityCreator",
+                           "?work bf:author %s");
+    yaz_sparql_add_pattern(s, "index.bf.type", "?inst rdf:type %s");
+    yaz_sparql_add_pattern(s, "index.bf.format",
+                           "?inst bf:format %v FILTER(contains(%v, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.nearby", "?lib gs:nearby (%d)");
+    yaz_sparql_add_pattern(s, "index.bf.baseTitle",
+                           "?work bf:derivativeOf/bf:workTitle/bf:titleValue "
+                           "%v FILTER(contains(%v, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.baseCreator",
+                           "?work bf:derivativeOf/bf:creator/bf:label "
+                           "%v FILTER(contains(%v, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.targetAudience",
+                           "?work bf:targetAudience %s");
+    yaz_sparql_add_pattern(s, "index.bf.isbn", "?inst bf:ISBN %s");
+
+    YAZ_CHECK(test_query(
+                  s, "@attr 1=bf.title computer",
+                  "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
+                  "PREFIX bf: <http://bibframe.org/vocab/>\n"
+                  "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
+                  "\n"
+                  "SELECT ?title ?author ?description ?ititle\n"
+                  "WHERE {\n"
+                  "  ?work a bf:Work .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?title .\n"
+                  "  ?work bf:creator/bf:label ?author .\n"
+                  "  ?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 ?v0 "
+                  "FILTER(contains(?v0, \"computer\"))\n"
+                  "}\n"
+                  ));
+
+    YAZ_CHECK(test_query(
+                  s, "@attr 1=bf.creator london",
+                  "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
+                  "PREFIX bf: <http://bibframe.org/vocab/>\n"
+                  "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
+                  "\n"
+                  "SELECT ?title ?author ?description ?ititle\n"
+                  "WHERE {\n"
+                  "  ?work a bf:Work .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?title .\n"
+                  "  ?work bf:creator/bf:label ?author .\n"
+                  "  ?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 ?v0 "
+                  "FILTER(contains(?v0, \"london\"))\n"
+                  "}\n"));
+
+    YAZ_CHECK(test_query(
+                  s, "@or @and @attr 1=bf.creator a @attr 1=bf.title b @attr 1=bf.title c",
+                  "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns>\n"
+                  "PREFIX bf: <http://bibframe.org/vocab/>\n"
+                  "PREFIX gs: <http://gs.com/panorama/domain-model>\n"
+                  "\n"
+                  "SELECT ?title ?author ?description ?ititle\n"
+                  "WHERE {\n"
+                  "  ?work a bf:Work .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?title .\n"
+                  "  ?work bf:creator/bf:label ?author .\n"
+                  "  ?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 ?v0 "
+                  "FILTER(contains(?v0, \"a\")) .\n"
+                  "   ?work bf:workTitle/bf:titleValue ?v1 "
+                  "FILTER(contains(?v1, \"b\"))\n"
+                  "  } UNION {\n"
+                  "   ?work bf:workTitle/bf:titleValue ?v2 "
+                  "FILTER(contains(?v2, \"c\"))\n"
+                  "  }\n"
+                  "}\n"
+                  ));
+
+    yaz_sparql_destroy(s);
+}
+
 int main(int argc, char **argv)
 {
     YAZ_CHECK_INIT(argc, argv);
     YAZ_CHECK_LOG();
     tst1();
+    tst2();
     YAZ_CHECK_TERM;
 }
 /*