prefix, criteria, index and field taken into account
authorAdam Dickmeiss <adam@indexdata.dk>
Fri, 7 Nov 2014 14:18:39 +0000 (15:18 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Fri, 7 Nov 2014 14:18:39 +0000 (15:18 +0100)
missing is "criteria.optional"

src/sparql.c
test/test_sparql.c

index 768b692..fb6c302 100644 (file)
@@ -65,13 +65,148 @@ int yaz_sparql_from_rpn_wrbuf(yaz_sparql_t s, WRBUF addinfo, WRBUF w,
     return yaz_sparql_from_rpn_stream(s, addinfo, wrbuf_vp_puts, w, q);
 }
 
+static Odr_int lookup_attr_numeric(Z_AttributeList *attributes, int type)
+{
+    int j;
+    for (j = 0; j < attributes->num_attributes; j++)
+    {
+        Z_AttributeElement *ae = attributes->attributes[j];
+        if (*ae->attributeType == type)
+        {
+            if (ae->which == Z_AttributeValue_numeric)
+                return *ae->value.numeric;
+        }
+    }
+    return 0;
+}
+
+static const char *lookup_attr_string(Z_AttributeList *attributes, int type)
+{
+    int j;
+    for (j = 0; j < attributes->num_attributes; j++)
+    {
+        Z_AttributeElement *ae = attributes->attributes[j];
+        if (*ae->attributeType == type)
+        {
+            if (ae->which == Z_AttributeValue_complex)
+            {
+                Z_ComplexAttribute *ca = ae->value.complex;
+                int i;
+                for (i = 0; i < ca->num_list; i++)
+                {
+                    Z_StringOrNumeric *son = ca->list[i];
+                    if (son->which == Z_StringOrNumeric_string)
+                        return son->u.string;
+                }
+            }
+        }
+    }
+    return 0;
+}
 
 static int apt(yaz_sparql_t s,
                WRBUF addinfo,
                void (*pr)(const char *buf, void *client_data),
                void *client_data,
-               Z_AttributesPlusTerm *q)
+               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;
+    int i;
+
+    pr("  ", client_data);
+    for (i = 0; i < indent; i++)
+        pr(" ", client_data);
+
+    if (v)
+    {
+        for (e = s->conf; e; e = e->next)
+        {
+            if (!strncmp(e->pattern, "index.", 6))
+            {
+                char *end = 0;
+                Odr_int w = odr_strtol(e->pattern + 6, &end, 10);
+
+                if (end && *end == '\0' && v == w)
+                    break;
+            }
+        }
+        if (!e)
+        {
+            wrbuf_printf(addinfo, ODR_INT_PRINTF, v);
+            return YAZ_BIB1_UNSUPP_USE_ATTRIBUTE;
+        }
+    }
+    else
+    {
+        const char *index_name = lookup_attr_string(q->attributes, 1);
+        if (!index_name)
+            index_name = "any";
+        for (e = s->conf; e; e = e->next)
+        {
+            if (!strncmp(e->pattern, "index.", 6))
+            {
+                if (!strcmp(e->pattern + 6, index_name))
+                    break;
+            }
+        }
+        if (!e)
+        {
+            wrbuf_puts(addinfo, index_name);
+            return YAZ_BIB1_UNSUPP_USE_ATTRIBUTE;
+        }
+    }
+    assert(e);
+    wrbuf_rewind(addinfo);
+    for (cp = e->value; *cp; cp++)
+    {
+        if (*cp == '%')
+        {
+            switch (*++cp)
+            {
+            case 's':
+                wrbuf_puts(addinfo, "\"");
+                switch (term->which)
+                {
+                case Z_Term_general:
+                    wrbuf_json_write(addinfo,
+                                term->u.general->buf, term->u.general->len);
+                    break;
+                case Z_Term_numeric:
+                    wrbuf_printf(addinfo, ODR_INT_PRINTF, *term->u.numeric);
+                    break;
+                case Z_Term_characterString:
+                    wrbuf_json_puts(addinfo, term->u.characterString);
+                    break;
+                }
+                wrbuf_puts(addinfo, "\"");
+                break;
+            case 'd':
+                switch (term->which)
+                {
+                case Z_Term_general:
+                    wrbuf_write(addinfo,
+                                term->u.general->buf, term->u.general->len);
+                    break;
+                case Z_Term_numeric:
+                    wrbuf_printf(addinfo, ODR_INT_PRINTF, *term->u.numeric);
+                    break;
+                case Z_Term_characterString:
+                    wrbuf_puts(addinfo, term->u.characterString);
+                    break;
+                }
+                break;
+            case '%':
+                wrbuf_putc(addinfo, '%');
+                break;
+            }
+        }
+        else
+            wrbuf_putc(addinfo, *cp);
+    }
+    pr(wrbuf_cstr(addinfo), client_data);
     return 0;
 }
 
@@ -81,8 +216,9 @@ static int rpn_structure(yaz_sparql_t s,
                          void (*pr)(const char *buf,
                                     void *client_data),
                          void *client_data,
-                         Z_RPNStructure *q)
+                         Z_RPNStructure *q, int indent)
 {
+    int i;
     if (q->which == Z_RPNStructure_complex)
     {
         int r;
@@ -90,21 +226,33 @@ 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);
+            r = rpn_structure(s, addinfo, pr, client_data, c->s1,
+                              indent);
             if (r)
                 return r;
             pr(" .\n", client_data);
-            return rpn_structure(s, addinfo, pr, client_data, c->s2);
+            return rpn_structure(s, addinfo, pr, client_data, c->s2,
+                                 indent);
         }
         else if (op->which == Z_Operator_or)
         {
-            pr("{\n", client_data);
-            r = rpn_structure(s, addinfo, pr, client_data, c->s1);
+            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);
             if (r)
                 return r;
-            pr("} UNION {\n", client_data);
-            r = rpn_structure(s, addinfo, pr, client_data, c->s1);
-            pr("}\n", client_data);
+            pr("\n", client_data);
+            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);
+            for (i = 0; i < indent; i++)
+                pr(" ", client_data);
+            pr("  }", client_data);
             return r;
         }
         else
@@ -116,7 +264,8 @@ 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);
+            return apt(s, addinfo, pr, client_data, op->u.attributesPlusTerm,
+                indent);
         else
             return YAZ_BIB1_RESULT_SET_UNSUPP_AS_A_SEARCH_TERM;
     }
@@ -132,7 +281,7 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
 {
     struct sparql_entry *e;
     yaz_tok_cfg_t cfg = yaz_tok_cfg_create();
-    int errors = 0;
+    int r = 0, errors = 0;
 
     for (e = s->conf; e; e = e->next)
     {
@@ -168,7 +317,7 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
         {
             ;
         }
-        else if (!strncmp(e->pattern, "index", 5))
+        else if (!strncmp(e->pattern, "index.", 6))
         {
             ;
         }
@@ -202,12 +351,13 @@ int yaz_sparql_from_rpn_stream(yaz_sparql_t s,
             pr(" .\n", client_data);
         }
     }
-    rpn_structure(s, addinfo, pr, client_data, q->RPNStructure);
+    if (!errors)
+        r = rpn_structure(s, addinfo, pr, client_data, q->RPNStructure, 0);
 
-    pr("}\n", client_data);
+    pr("\n}\n", client_data);
     yaz_tok_cfg_destroy(cfg);
 
-    return errors ? -1 : 0;
+    return errors ? -1 : r;
 }
 
 /*
index b25792a..6ead793 100644 (file)
@@ -71,6 +71,8 @@ static void tst1(void)
                            "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");
@@ -81,10 +83,33 @@ 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, "index.bf.title",
+                           "?work bf:workTitle/bf:titleValue ?o1 "
+                           "FILTER(contains(?o1, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.creator",
+                           "?work bf:creator/bf:label ?o2 "
+                           "FILTER(contains(?o2, %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 ?o5 FILTER(contains(?o5, %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 "
+                           "?o6 FILTER(contains(?o6, %s))");
+    yaz_sparql_add_pattern(s, "index.bf.baseCreator",
+                           "?work bf:derivativeOf/bf:creator/bf:label "
+                           "?o7 FILTER(contains(?o7, %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, "computer",
+                  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"
@@ -94,8 +119,191 @@ static void tst1(void)
                   "  ?work bf:note ?description .\n"
                   "  ?inst bf:instanceOf ?work .\n"
                   "  ?inst bf:instanceTitle/bf:titleValue ?ititle .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"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"
+                  "  ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"london\"))\n"
+                  "}\n"));
+
+
+    YAZ_CHECK(test_query(
+                  s, "@and @attr 1=bf.creator london @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"
+                  "  ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"london\")) .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"computer\"))\n"
+                  "}\n"));
+
+    YAZ_CHECK(test_query(
+                  s, "@or @attr 1=bf.creator london @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"
+                  "  {\n"
+                  "   ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"london\"))\n"
+                  "  } UNION {\n"
+                  "   ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"computer\"))\n"
+                  "  }\n"
+                  "}\n"
+                  ));
+
+    YAZ_CHECK(test_query(
+                  s, "@or @or @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"
+                  "  {\n"
+                  "   {\n"
+                  "    ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"a\"))\n"
+                  "   } UNION {\n"
+                  "    ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"b\"))\n"
+                  "   }\n"
+                  "  } UNION {\n"
+                  "   ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"c\"))\n"
+                  "  }\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"
+                  "  {\n"
+                  "   ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"a\")) .\n"
+                  "   ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"b\"))\n"
+                  "  } UNION {\n"
+                  "   ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"c\"))\n"
+                  "  }\n"
+                  "}\n"
+                  ));
+
+    YAZ_CHECK(test_query(
+                  s, "@and @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"
+                  "  ?work bf:creator/bf:label ?o2 "
+                  "FILTER(contains(?o2, \"a\")) .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"b\")) .\n"
+                  "  ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"c\"))\n"
+                  "}\n"
+                  ));
+
+    YAZ_CHECK(test_query(
+                  s, "@and @attr 1=bf.title \"Phantom Tollbooth\" "
+                  "@attr 1=bf.nearby \"40.1583 83.0742 30\"",
+                  "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"
+                  "  ?work bf:workTitle/bf:titleValue ?o1 "
+                  "FILTER(contains(?o1, \"Phantom Tollbooth\")) .\n"
+                  "  ?lib gs:nearby (40.1583 83.0742 30)\n"
+                  "}\n"
+                  ));
+
+    YAZ_CHECK(test_query(
+                  s, "@attr 1=bf.isbn 9780316154697",
+                  "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"
+                  "  ?inst bf:ISBN \"9780316154697\"\n"
+                  "}\n"
+                 ));
+
 
     yaz_sparql_destroy(s);
 }