RDF-Query-2.918/README.html 000644 000765 000024 00000274145 13033227545 015206 0 ustar 00greg staff 000000 000000
RDF::Query
RDF::Query - A SPARQL 1.1 Query implementation for use with RDF::Trine.
RDF::Query allows RDQL and SPARQL queries to be run against an RDF model, returning rows of matching results.
Requirements
To install RDF::Query you'll need the following perl modules installed:
- Data::UUID
- Digest::SHA
- DateTime
- DateTime::Format::W3CDTF
- Error
- File::Spec
- File::Temp
- I18N::LangTags
- JSON
- List::Util
- LWP
- Parse::RecDescent
- RDF::Trine
- Scalar::Util
- Set::Scalar
- Storable
- URI
The following additional modules are recommended for some functionality:
Installing RDF::Query
To install, run:
perl Makefile.PL
make
make test
make install
Version History
Version 2.918 (2017-01-04)
- Security Fix
- Do not search modules in relative paths (#141 from @ppisar).
Version 2.917 (2016-05-22)
- Enhancements
- Change hashbang to use env (#137 from KjetilK).
- Replaced Text::CSV by Text::CSV_XS (#127, #136; patch from jordivador).
- Bug Fixes
- Fixed bug that didn't properly anchor the regex match in serializing prefixnames (#135).
- Fixed SPARQL parsing bug causing filters to improperly appear inside of service blocks (github issue #134).
- Fix SPARQL serialization of functions that have a prefix that is also a valid function name (#133).
Version 2.916 (2015-10-16)
- Enhancements
- Updated RDF::Query::Node::Resource->as_sparql to allow SPARQL 1.0 PN_LOCAL prefix names (GitHub issue #132).
- Other
- Add default indentation to RDF::Query::Algebra::Limit->sse.
Version 2.915 (2015-08-18)
- New Features
- Add RDF::Query::Node->from_attean method (PR #128 from Kjetil Kjernsmo).
- Other
- Add default indentation to RDF::Query::Algebra::Limit->sse.
Version 2.914 (2015-05-17)
- Bug Fixes
- Fixed bug in evaluation of SPARQL CONCAT function.
Version 2.913 (2015-02-14)
- Bug Fixes
- Fix SPARQL 1.1 parsing bug that disallowed whitespace between an aggregate name and the following open-parenthesis.
- Fix bug in RDF::Query::Algebra::NamedGraph->definite_variables.
- Fix rqsh to use a pure memory model when requested (instead of a temporary model).
- Fixed whitespace handling bug during parsing of VALUES clauses (github issue #120).
- Enhancements
- Merge adjacent service blocks if their endpoints and silent flags match (github issue #124).
- Allow RDF::Query->new to accept an algebra object instead of a query string.
- Updated node classes to allow overloaded comparisions with RDF::Trine::Node::Nil objects.
- Improve coverage of as_hash function for variable bindings and expressions (github issue #121).
- Other
- Documentation fixes (from Kjetil Kjernsmo).
Version 2.912 (2014-10-24)
- Bug Fixes
- Fix bug in handling of SUM aggregates with non-literal data.
- Enhancements
- Improved performance of regular expression use in SPARQL parser (from Dorian Taylor; github pull request #111).
- Other
- Added IRC resource to Makefile.PL.
Version 2.911 (2014-07-24)
- Bug Fixes
- Fixed bug in RDF::Query::Plan::Join::PushDownNestedLoop that didn't allow 'aggregate' to appear in the RHS serialized text (github issue 101).
- Fixed SPARQL 1.1 GGP parsing bug (github issue 100).
- Fixed RDF::Query::Algebra->subpatterns_of_type to support descent into sub-queries.
- Disabled pushing full updates down into the store object (only meant to be full queries at this point).
- Fixed as_hash method in RDF::Query::Algebra::Aggregate, RDF::Query::Algebra::Sort, and RDF::Query::Expression::Alias.
- Updated RDF::Query::Compiler::SQL to respect node class encapsulation.
- Enhancements
- Modularized implementation of explain method in algebra and plan classes.
- Updated rqsh script to use env perl instead of hardcoded bin path.
- Added JSON output to bin/parse.pl script.
- Added RDF::Query::ExecutionContext->bind_variable method.
- Other
- Added :all export tag to RDF::Trine::Node.
- Remove Crypt::GPG and Bloom::Filter from list of recommended modules (no longer used in code).
Version 2.910 (2013-07-22)
- Bug Fixes
- Updated RDQL parser to work with recent RDF::Trine releases.
Version 2.909 (2012-11-24)
- Bug Fixes
- Fixed bad sparql serialization of filters with equality tests; was using '==' instead of '=' (github issue 53).
- Fixed bug in RDF::Query::Algebra::Service->referenced_variables.
- Fixed bug that wasn't passing the active graph to EXISTS filter evaluation.
- Fixed RDF::Query prepare and execute methods to properly localize the model object.
- Fixed bug in RDQL parser that mistakenly required a USING clause (github issue 70).
- Fixed handling of aggregates over empty groups.
- New Features
- Added support for VALUES graph pattern (in-place BINDINGS).
- Added support for UUID() and STRUUID() functions.
- Added is_update() and specifies_update_dataset() methods to RDF::Query.
- Accept common typo of SEPARATOR in SPARQL 1.1 parser ("SEPERATOR") with constructor arg 'allow_typos' in RDF::Query::Parser::SPARQL11.
- Enhancements
- Fixed SPARQL 1.1 parsing to enforce not using shared bnode labels between update data operations.
- Improved SPARQL 1.1 parser detection of invalid use of BIND() (when binding already in-scope variables).
- Fixed bug in SPARQL 1.1 parser to recognize legal Update operations.
- Updated SPARQL 1.1 parser to allow colon in local part of a prefixname.
- Updated STRBEFORE() and STRAFTER() implementations to track SPARQL 1.1 standard.
- Updated property path implementation to track W3C standard (changed counting semantics and dropped {m,n} form).
- Added support to passthrough query eval to the model if supported and the 'allow_passthrough' option is set on the query object.
- Added 'canonicalize' option to RDF::Query constructor to canonicalize literal values.
- Other
- Updated handling of BIND() in the SPARQL 1.1 parser to match the latest spec semantics.
- Added ability to run tests of type mf:CSVResultFormatTest.
- Fixed config handling in rqsh to allow the use of hexastore backends.
- Merged Log4perl initialization cleanup patches (from github/kba).
- Use $plan->explain instead of $plan->sse for "explain" rqsh command.
- Updated EARL IRIs in bin/failing_earl_tests.sh and bin/passing_earl_tests.sh.
- Removed RDF::Redland recommendation in Makefile.PL.
- Added doap:implements statements, and updated release data to doap.rdf.
- Updated RDF::Query::Util::cli_parse_args to allow no-argument setup.
- Updated xt/dawg/earl.pl to use new EARL IRIs earl:passed and earl:failed.
- Added POD to bin/rqsh.
- Updated DAWG test harnesses to support expected query bindings results in RDF/XML format.
- Fixed xt/dawg-eval11.t to emit TAP failures when query parsing fails.
- Require RDF::Endpoint 0.05 in xt/dawg-eval11.t.
- Removed values from test directory list in xt/dawg-eval11.t.
- Added values to list of test directories in xt/dawg-eval11.t.
- Added exists test directory to xt/dawg-eval11.t.
- Added test case confirming bad sparql serialization of equality testing filters (github issue 53).
- Removed tests for {m,n} property path forms.
- Fixed RDF::Query::Algebra::Project to throw exception on bad constructor arguments.
- Added bugtracker info to Makefile.PL.
- Added POD marking modules as unstable: RDF::Query::BGPOptimizer, RDF::Query::Compiler::SQL, RDF::Query::Federate, RDF::Query::Federate::Plan
- Improved expected/actual results output when encountering failing tests.
- Removed old bloom-filter federation code.
- Removed RDF::Query::ExecutionContext->base method.
- Fix POD in RDF::Query::Algebra::Table.
Version 2.908 (2012-01-31)
- Bug Fixes
- Fixed SPARQL serialization of expressions using && and ||.
- Fixed SPARQL 1.1 parser to support "GRAPH<iri>" without whitespace.
- Fixed bug resulting in false positive error when projecting expressions with aggregates.
- Fixed aggregate evaluation to result in unbound variables on error (instead of dropping the result).
- Fixed numeric divide operation to return xsd:decimal when operands are xsd:integers.
- Fixed RDF::Query::Expression::Binary->evaluate to properly throw on div-by-zero.
- Fixed RDF::Query::Expression::Function->evaluate to propogate type errors in IF().
- Fixed bin/rqsh to handle queries that use BASE.
- Fixed bug in RDF::Query::Plan::Join::PushDownNestedLoop that produced invalid results when the RHS was a subselect.
- Fixed RDF::Query::Algebra::Filter->as_sparql to handle variation of serialization of the child pattern.
- Fixed bug in SPARQL 1.1 parser that mistakenly introduced aggregate operations in non-aggregate queries.
- New Features
- Added support for Service as a binary op (allowing variable-endpoint SERVICE blocks).
- Added implementations for functions STRBEFORE, STRAFTER, and REPLACE.
- Added RDF::Query->prepare_with_named_graphs method.
- Added support for COPY and MOVE operations.
- Allow percent encoding and backslash escaping in prefix names.
- Enhancements
- Fixed RDF::Query::Expression::Binary to canonicalize numeric literal results.
- Added syntax support for SILENT form of LOAD.
- Added support for SILENT and variable endpoint handling for SERVICE patterns.
- Added syntax support for optional GRAPH keyword on SPARQL 1.1 update shortcuts.
- Updated RDF::Query::Plan::Extend to copy variable bindings instead of using the existing reference.
- Added RDF::Query::Plan::Extend->explain.
- Changed explain() syntax of plan quads.
- Updated plan classes to optionally register intermediate results with a execution delegate object.
- Made RDF::Query::Plan::Construct uniq the returned triples.
- Added custom RDF::Query::Plan::Construct->explain method.
- Normalize language tags used in SPARQL query syntax to lowercase.
- Modularize RDF::Query::Plan::Service to allow mock testing.
- Added exception handling in RDF::Query->set_error.
- Added subplans_of_type method to Plan classes.
- Fixed use of '__DEFAULT__' sentinel value in RDF::Query::Plan, RDF::Query::Plan::Service, RDF::Query::Node::Resource->as_sparql, and RDF::Query->as_sparql.
- Force the planner to avoid using a bind-join when the RHS contains a Service subplan (to avoid a DOS attack on the remote endpoint).
- Updated DATATYPE() to return rdf:langString on language-tagged literals (per RDF 1.1 change).
- Fixed sse serialization in RDF::Query::Algebra::Service to handle binary op (variable endpoint) form.
- Croak rather than die in some places, confess and use logdie in one place
- Allow aggregates in ORDER BY clause.
- Other
- Added examples/query_url.pl.
- Added RDF::Trine::Error::UnimplementedError exception class.
- Updated required version of RDF::Trine to 0.138.
Version 2.907 (2011-06-04)
- Bug Fixes
- Fixed bug in SPARQL 1.1 parser for DESCRIBE queries without a WHERE clause.
- Fixed join ordering bug for queries with a BINDINGS clause and several joins.
- Fixed RDF::Query->as_sparql for DESCRIBE queries which project URI terms, not variables.
- Other
- Fixed expected test results for DESCRIBE queries without a WHERE clause.
- examples/query.pl now emits a warning if the query object cannot be constructed.
Version 2.906 (2011-05-14)
- API Changes
- Globally changed 'base' to 'base_uri' in code and API.
- Bug Fixes
- Fixed SPARQL serialization in RDF::Query::Plan generation of SERVICE blocks to always include braces around the query body.
- Fixed SPARQL 1.1 parsing bug in property paths using alternatives ('|').
- Fixed SPARQL 1.1 bug in parsing prefixnames where a graph term is expected.
- Fixed bug in ZeroOrMore reverse path handling (patterns matching { var path* term }).
- Fixed bug in RDF::Query::Node::Literal::_cmp that was causing wrong node comparison results.
- Fixed bug in parsing solution modifiers in CONSTRUCT and DESCRIBE queries.
- Fixed bug in handling of unbound variables in delete templates in RDF::Query::Plan::Update.
- Fixed bug in calls to RDF::Query->var_or_expr_value that was preventing use of EXISTS filters in project expressions.
- New Features
- Updated RDF::Query::Plan::Iterator->new to allow passing in a callback that will return an iterator, instead of an iterator directly.
- Updated RDF::Query->query_plan to delegate entire queries to the RDF::Trine::Model when possible.
- Updated bin/deparse.pl to allow specifying an endpoint url for SPARQL-backed models (which can affect the query plan).
- Added support for empty SPARQL 1.1 Update sequence operations (allowing no-op updates).
- Added options to RDF::Query->new to allow forcing RDF::Query to disable query delegation to the underlying store.
- Added option to RDF::Query::Util::cli_parse_args to specify arbitrary options to be supplied to the RDF::Query->new constructor.
- Added new, cleaner line-based "explain" format for serializing query Plan and Algebra objects.
- Added bindings accessor and is_unit method to RDF::Query::Plan::Constant.
- Added ability to forcibly remove a particular join algorithm from consideration in plan generation.
- Added 'execute' command in rqsh to allow loading a query from a file or URL.
- Enhancements
- Updated SPARQL 1.1 parser to prevent bnode use in DELETE blocks.
- Updated rqsh to associate common filename extensions with media types (helps in loading local files).
- Updated RDF::Query::Plan::Path to align with new ALP algorithm from the spec text.
- Added some simple statistics generation code in RDF::Query::Plan::Join subclasses.
- Added missing implementation for property paths using {n,} modifier syntax.
- Added code to guard against mishandling unbound/blank/variable nodes in DELETE templates in RDF::Query::Plan::Update.
- Other
- Updated tests to use new RDF::Trine::Iterator->seen_count method instead of deprecated count method.
- Updated serialization text for zero-length paths in RDF::Query::Plan::Path->plan_node_data.
- Removed warning of unknown options passed to RDF::Query->new.
- Removed unused projection code in RDF::Query->execute_plan.
- Removed Digest::SHA1 from prereq modules, and updated code to use Digest::SHA instead.
- Remove the meaningless "All rights reserved" copyright text.
- Fixed test count in t/sparql11-propery_paths.t.
- Commented out noisy debugging output in RDF::Query::Plan::Path.
- Added trace debugging in RDF::Query::Plan::Sort.
- Added options instance variable to RDF::Query::ExecutionContext.
- Added Module::Pluggable to list of required modules in Makefile.PL.
- Added mappings from file extensions to media types in dawg test scripts.
- Various updates to SPARQL 1.1 dawg test harness scripts.
Version 2.905 (2011-02-18)
- Bug Fixes
- Fixed mistaken case sensitivity of COALESCE, BNODE, CONCAT, and SUBSTR keywords in SPARQL 1.1 parser.
- Fixed parsing ambiguity between MIN aggregate and MINUTES function.
- Fixed Xpath fn:timezone-from-dateTime function return for UTC timezones.
- Fixed RDF::Query::Algebra::Project->as_sparql handling of binary select expressions.
- Fixed RDF::Query::Algebra::Construct->sse serialization to include construct triples.
- Updated handling of BIND() to not close group scope (which was applying filters in the wrong place).
- Fixed RDF::Query::Parser::SPARQL11 to handle whitespace between tokens in 'INSERT DATA' and 'DELETE DATA'.
- Fixed RDF::Query::Parser::SPARQL11 to handle empty ModifyTemplates.
- Fixed SPARQL 1.1 parser to properly set relevant datasets for update operations.
- Fixed plan code for zero-length paths to return RDF::Query::Node-based results (not Trine-based).
- Fixed bug in RDF::Query::Plan::Clear when attempting to clear the default graph.
- Fixed exception throwing on numeric binary expression eval without numeric literal arguments.
- Updated RDF::Query::Plan to handle update operations with different datasets for matching (USING clause).
- New Features
- Added SPARQL 1.1 numeric functions: ABS, CEIL, FLOOR, ROUND, RAND
- Added SPARQL 1.1 string functions: CONCAT, SUBSTR, STRLEN, UCASE, LCASE, ENCODE_FOR_URI, CONTAINS, STRSTARTS, STRENDS
- Added SPARQL 1.1 date functions: NOW, TIMEZONE, TZ, YEAR, MONTH, DAY, HOURS, MINUTES, SECONDS
- Added SPARQL 1.1 hashing functions: MD5, SHA1, SHA224, SHA256, SHA384, and SHA512
- Added RDF::Query::Functions->install_function method, and implementations for fn:compare, fn:concat, and fn:substring.
- Updated RDF::Query->execute_with_named_graphs to accept optional arguments to be passed to execute().
- Added support for CONSTRUCT WHERE syntax shortcut.
- Added support for SILENT modifier to SERVICE patterns.
- Added SILENT flag in RDF::Query::Algebra::Service.
- Added initial code to create SPIN serializations of queries.
- Added RDF::Query::Node::Literal->type_list method.
- Enhancements
- Updated xt/dawg-syntax11.t to find more syntax queries in the dawg test data.
- SPARQL 1.1 parser now throws errors for more classes of syntactically invalid queries (repeated expression aliases, wrong number of BINDINGS values, SELECT * with use of grouping).
- Added support for non-strict comparisons of xsd:strings in RDF::Query::Node::Literal (based on $LAZY_COMPARISONS variable).
- Other
- Major refactor of xt/dawg-eval11.t test harness.
- Updated required version of Test::More to 0.88 (0.86 doesn't have done_testing() used in t/store-config.t).
- Updated RDF::Query::Expression::Function->evaluate to throw an error if no function coderef is found.
Version 2.904 (2010-11-23)
- Added 'set prefix' and 'time' commands to rqsh.
- Added string concatenation overloading of binary +.
- Fixed bug in property path evaluation on encountering blank path nodes.
- Fixed use of binary '*' in FILTER without numeric data in t/resultforms.t.
- Fixed bin/dawg11-status.pl to only load SPARQL 1.1 earl result files.
- Fixed RDF::Query::Plan::Update to ignore non-ground triples (unbound variables don't act as wildcards).
- Fixed handling of named graph data in insert/delete patterns of update operations.
- Updated RDF::Query::Util to use RDF::Trine::Model->temporary_model and guess an appropriate parser based on filenames.
- Updated namespace URI in RDF::Query::Functions::Jena to <http://jena.hpl.hp.com/ARQ/function#>.
- Updated namespace URI in RDF::Query::Functions::Xpath to <http://www.w3.org/2005/xpath-functions#>.
- Updated xt/dawg-eval11.t to align with updated test case manifest schemas.
- Updated xt/dawg-eval11.t to prevent test cases with missing files from emitting failures (now skipped).
- Added xpath function implementations.
- Added SPARQL 1.1 Update shortcut syntax support for COPY, MOVE, and ADD graph operations.
- Fixed bug in RDF::Query::Plan::Construct that wasn't giving each result a new set of blank nodes (RT 63155).
- Updated SYNOPSIS and execute() and execute_plan() methods POD (RT 63153 comment from Ivan Shmakov).
- Updated documentation to explicitly discuss inherited methods due to subclassing.
- Fixed RDF::Query::Algebra::Sequence->sse to serialize operations in proper order.
- Added $silent argument to RDF::Query::Algebra::Clear constructor.
Version 2.903 (2010-11-03)
- SPARQL 1.1
- New features
- Added support for BIND(expr AS ?var) operator.
- Added isNumeric built-in function, checking for proper datatype and valid lexical forms for numerics.
- Updates
- Updated SPARQL 1.1 parser to handle WITH clauses with PrefixedNames.
- SPARQL 1.1 parser now sets error and returns if no query string is supplied.
- Added more exception handling in RDF::Query::Parser::SPARQL11.
- Updated CLEAR and DROP handling in SPARQL 1.1 parser and engine to handle 'NAMED' and 'ALL' variants.
- Renamed 'binding_variables' methods to 'potentially_bound' to align with current SPARQL 1.1 terminology.
- Results returned by property path plans are now RDF::Query::VariableBindings objects and are properly projected.
- The query planner now interprets simple paths as basic graph patterns.
- Removed Algebra and Plan classes for Not and Exists operations (now handled in other classes).
- Updated RDF::Query::Plan::Extend to drop the extended variable binding if evaluating the extension yields an error.
- Updated RDF::Query::Plan::Update to accept delete patterns with variables.
- Updated subquery plan objects to use a sub-plan, not a full query object.
- Bug fixes
- Fixed SPARQL 1.1 parser bug that was returning partial data from a failed parse call.
- Fixed SPARQL 1.1 parser bug for queries with multiple FILTERs in a GGP including an EXISTS filter.
- Fixed SPARQL 1.1 parser bug for DROP/CLEAR queries.
- Fixed SPARQL 1.1 parser typo of 'SEPARATOR' argument to GROUP_CONCAT aggregate.
- Fixed SPARQL 1.1 parser to handle FITLERS to the left of MINUS/OPTIONAL and allow projecting '*' with other vars/epressions.
- Fixed SPARQL 1.1 parser case sensitivity of project expression 'AS' token.
- Fixed SPARQL 1.1 parser handling of of subqueries within GRAPH blocks.
- Fixed miscellaneous bugs and improved performance of parsing SPARQL 1.1 queries.
- Made parsing of very large triple blocks non-recursive in SPARQL 1.1 parser.
- Fixed COALESCE function to handle errors properly.
- Fixed RDF::Query::Plan::Aggregate to extend results using AliasExpressions from HAVING clauses.
- Fixed bug that was ignoring GROUP BY clauses when no aggregate operations were present.
- Fixed bad looping on start node of unbounded property paths.
- Fixed bug in query planning of '^' property paths.
- Fixed zero-length property path evaluation within GRAPH blocks.
- Removed plan duplication of zero-length case in '*' property paths.
- Fixed handling of named graphs within subqueries (changes to active graph handling in the query planner).
- Fixed type-promotion and handling of numeric types in aggregate handling.
- Fixed RDF::Query::Algebra::Update->as_sparql to handle INSERT/DELETE updates properly.
- Fixed RDF::Query::Plan::Aggregate->sse to allow handling of (non-blessed, scalar) '*' columns.
- Query Engine
- Added ability to pass through arguments to the query planner in RDF::Query->prepare.
- Updated RDF::Query::Node::Literal::_cmp to handle literals that fail to parse as DateTime objects.
- Updated RDF::Query::Plan::Limit to use the limit accessor internally.
- RDF::Query::Plan::NamedGraph now uses lazy iterator for graph names.
- Updated RDF::Query::VariableBindings to subclass the new RDF::Trine::VariableBindings.
- RDF::Query::Algebra::Project now implements bind_variables().
- Updated RDF::Query->describe to use $model->bounded_description instead of simply outgoing arcs.
- Fixed bug in evaluation of function expressions in which the execution context object was lost (causing EXISTS filters to fail).
- Fixed optimization of COUNT(*) over 1-triple BGPs to keep the variable binding for the pseudo-variable ?COUNT(*).
- Fixed sse serialization in RDF::Query::Algebra::Distinct.
- Fixed RDF::Query::Plan::Join::PushDownNestedLoop to close sub-plans in close() method.
- rqsh - RDF::Query Shell
- Added ability to show the parsed algebra with 'parse' command.
- Added abiility to show the query execution plan with the 'explain' command.
- Added ability to change the RDF serializer with the 'serializer' command.
- Added ability to initialize new stores with the 'init' command.
- Added ability to change underlying store with the 'use' command.
- Added 'help' command.
- Updated packaging to install rqsh script (renamed from old bin/rqsh.pl).
- Updated to catch errors thrown while trying to create new storage backends (e.g. DBI->connect failing).
- rqsh now defaults to read-write models.
- rqsh now sets a base URI for the current working directory.
- Password input now doesn't echo to the terminal.
- Filename input now autocompletes via Term::ReadLine.
- Warning and Error Handling
- Replaced calls to die with throwing exceptions.
- RDF::Query->new now warns about unrecognized options.
- DATATYPE() now throws an exception unless passed a valid node object.
- RDF::Query::Expresion::Binary now throws exceptions on numeric comparisions with non-numeric operands.
- Fixed error message in RDF::Query::Plan::NamedGraph.
- Added trace debugging to RDF::Query::Plan::Union.
- Added trace debugging to RDF::Query::Plan::Project.
- Added trace debugging to RDF::Query::Plan::Path.
- Tests and Miscellany
- Added SPARQL 1.1 syntax and eval test harnesses.
- Fixed bug in xt/dawg-eval11.t parsing of srx files containing literal values that evaluate to false in perl (e.g. '0').
- Fixed turtle output for rdfs:comments in xt/dawg/earl.pl.
- Moved developer tests from t/ to xt/.
- Refactored RDF::Query::Functions into several auto-loaded sub-packages via Module::Pluggable (patch from tobyink).
- Removed references to the now-deprecated mac.com in network-based tests.
- Updated expected values in t/queryform-describe.t for results using bounded descriptions.
- Updated RDF::Query::Util to look for .prefix-cmd cache of common namespace names.
- Updated RDF::Query::Util::cli_parse_args to accept '-r' as a read-only flag.
- Updated required version of RDF::Trine to 0.126.
- Updated to use URI 1.52 to allow direct usage of IRIs without unicode workarounds.
- Made code updates to improve performance based on profiling.
Version 2.902 (2010-07-02)
- Fixed bug in requiring prerequisite modules.
Version 2.901 (2010-06-29)
- Fixed named graph handling.
- Fixed bug in handling of * aggregates.
- Simplified code to create new temporary models when FROM clauses dereference graph data.
- Added support for SPARQL 1.1 CREATE/DROP GRAPH update operations.
- Fixed infinite loop bug on parsing certain invalid SPARQL 1.1 update queries.
- Fixed handling of BGPs within named graphs in RDF::Query::Plan::BasicGraphPattern.
- Updated syntax error exception messages in SPARQL parsers.
- Fixed property path evaluation within named graphs.
- Converted Makefile.PL to properly use Module::Install.
Version 2.900 (2010-06-23)
- Major Changes
- SPARQL 1.1 is now the default query parser.
- RDF::Core is no longer supported as a backend triplestore.
- Redland is still supported as a backend store, but updated handling of default and named graphs means that existing triples stored in Redland without a context (named graph) will not be accessible from RDF::Query.
- SPARQL Language Updates
- Added support for SPARQL 1.1 Query features:
- Basic Query Federation with BINDINGS and UNDEF support.
- Functions: IF, STRDT, STRLANG, IRI, URI, BNODE.
- Infix operators IN and NOT IN.
- Aggregates COUNT, SUM, MIN, MAX, AVG, GROUP_CONCAT, and SAMPLE.
- Property paths.
- Negation with MINUS graph patterns and NOT EXISTS filters.
- Added support for SPARQL 1.1 Update features:
- INSERT/DELETE DATA, INSERT/DELETE WHERE, LOAD, and CLEAR
- Added support for multi-statement updates.
- API Updates
- Removed all bridge classes (RDF::Query::Model::*).
- Removed RDF::Query::Logger class.
- Removed net filter function code from RDF::Query.
- Added as_hash method to Query, Algebra, and Node classes.
- Removed SPARUL and SPARQLP parsers.
- RDF::Query no longer loads URIs in FROM and FROM NAMED clauses with SPARQL 1.1 by default.
- Added ability for RDF::Query::Plan::Iterator to fire a callback when execute() is called.
- Added new RDF::Query::Plan::ComputedStatement class.
- Added new RDF::Query::Plan::Iterator class.
- Bugfixes
- Fixed whitespace unescaping bug in SPARQL (1.0 and 1.1) parsers.
- Scripts
- Added bin/json.pl to print a JSON-formatted representation of the query algebra.
- Added bin/rqsh.pl CLI interface to executing updates and queries.
- Added ability to serialize algebra and plan in bin/deparse.pl.
- bin/deparse.pl now catches parsing errors and prints stacktrace.
- Optimizations
- Implemented optimization for COUNT(*) over a single triplepattern.
Version 2.202 (2010-05-22)
- Added initial SPARQL 1.1 syntax and eval support for select expressions, subqueries, negation, aggregates, subqueries, and basic federation.
- Added RDF::Query::VariableBindings.pm->set method.
- Added RDF::Query::_new constructor without any sanity or setup code (used for subquery construction).
- Added RDF::Query::Node::Blank::new constructor to avoid RDF::Trine's N-Triples syntax requirements.
- Added SAMPLE and GROUP_CONCAT aggregate support.
- Added shortcut functions for constructing RDF::Query::Node objects and Algebra Triples, BGPs and GGPs.
- Added warning to RDF::Query::Algebra::Project constructor for improper variable lists.
- Updated DAWG tests to use SPARQL 1.1 parser.
- Removed SPARQLP aggregate tests that don't align with new SPARQL 1.1 semantics.
- Updated DAWG eval tests to skip non-approved tests.
- Fixed handling of unicode decoding in DAWG eval tests.
- Bumped required version of RDF::Trine to 0.123.
- Updated t/models.pl to use RDF::Trine::Parser->parse_url_into_model method and redland's 'guess' parser.
- Fixed logging key name in RDF::Query::Plan::Exists.
- Fixed sse and as_sparql methods in RDF::Query::Algebra::Exists.
- Implemented RDF::Query::Algebra::Exists::binding_variables.
- Updated BGPOptimizer to estimate selectivity directly instead of using costmodel code.
- Removed costmodel code.
- Removed unused fixup and execute methods in Algebra classes.
- Updated RDF::Query to only instantiate DateTime parser and LWP::UserAgent if needed.
- Changed DBPedia network test to align with recent DBPedia update in t/dev-service-description.
- Updated SPARQLP parser tests to align with internal changes in RDF::Query::Algebra::Aggregate.
- Updated RDF::Query::Algebra::Aggregate and RDF::Query::Plan::Aggregate to syntactically handle HAVING clauses.
- Fixed bin/graph-bgp.pl (had bitrotted).
- Changed bnodes to named variables in examples/queries/sparql-bgp-people-knows.rq.
- RDF::Query::Util::cli_make_query now defaults the 'class' parameter to 'RDF::Query'.
- Removed dependency list and added perlrdf link to POD in RDF::Trine and RDF::Query.
Version 2.201 (2010-01-30)
- Added benchmark/lubm.pl.
- Added examples/queries/sparql-ask-people.rq.
- Added RDFa tests.
- Added Data::UUID prerequisite to META.yml and Makefile.PL.
- Updated ::Model::RDFTrine::add_uri and ::add_string to use new RDF::Trine::Parser methods.
- Updated as_sparql and sse code to work with more recent RDF::Trine versions.
- Removed as_sparql caching in RDF::Query::Algebra::Triple.
- Renamed RDF::Query test files to remove old-style numbering.
- Updated parser tests to track new RDF::Trine::Node::Literal internal structure.
- Updated prereq version of RDF::Trine to 0.114.
- Fixed NAME POD section in RDF::Query::ServiceDescription (RT52264 from KjetilK).
Version 2.200 (2009-08-06)
- Federation / Service Descriptions
- Rewrote the optimistic plan generator in RDF::Query::Federate::Plan.
- Added threshold timeout argument to RDF::Query::Plan::ThresholdUnion and support for it in RDF::Query::Federate::Plan.
- Simplified logging in RDF::Query::Federate::Plan (now only logs to category 'rdf.query.federate.plan').
- RDF::Query::ServiceDescription now adds an 'origin' label annotations to RDF::Query::Algebra::Triple objects.
- Removed check of the sd:definitive property in RDF::Query::ServiceDescription (was based on wrong assumptions).
- Updated RDF::Query::ServiceDescription::answers_triple_pattern() to recognize wildcard capabilities, constructor now adds wildcard by default.
- Added new RDF::Query::ServiceDescription::new_with_model constructor.
- RDF::Query::ServiceDescription::computed_statement_generator now returns empty iterators when passed triple patterns with bound blank nodes.
- Added test data in data/federation_data/.
- RDF::Query::Plan::Service now adds an 'origin' label annotation to the RDF::Query::VariableBindings object.
- Added 'optimistic_threshold_time' query flag to RDF::Query::ExecutionContext and RDF::Query constructor.
- RDF::Query::Federate::add_service() now adds the appropriate computed statement generators to the query object.
- Removed optimistic query rewriting test from t/34-servicedescription.t (now covered by t/federate.t).
- Added t/federate.t with tests for optimistic federated query optimization using ::Plan::ThresholdUnion and RDF::Endpoint::Server.
- Aggregates
- Fixed serialization quoting issue in RDF::Query::Algebra::Aggregate::sse().
- RDF::Query::Plan::Aggregate now attempts plain string comparisons for MIN,MAX when strict_errors is not set.
- Added support for average aggregates, and fixed datatype support in aggregates.
- Command Line Inferface
- Added bin/query.pl, a fork of examples/query.pl, to support simple query execution.
- Added RDF::Query::Util as home to helper functions (added CLI args parsing functions to create queries and models).
- Simplified CLI argument parsing in bin/ and examples/ programs.
- Refactoring, Code Cleanup, and Documentation
- Added and updated POD to RDF::Query::Util, RDF::Query::Node and RDF::Query::Plan and RDF::Query::Federate::Plan.
- Added check for RDFQUERY_THROW_ON_SERVICE environment variable in RDF::Query::Plan::Service.
- Cleaned up code in RDF::Query::Model::get_computed_statements().
- Updated SSE formatting and uninitialized warning in RDF::Query::Plan, RDF::Query::Algebra::Filter, RDF::Query::Algebra::Distinct and RDF::Query::Algebra::Sort.
- Moved shared RDF::Trine-related model methods into RDF::Query::Model from subclasses.
- Raised required RDF::Trine version to 0.111 which brings RDF::Trine::Graph support.
- RDF::Query::Model::RDFTrine::BasicGraphPattern::execute now returns $self.
- Removed dependency on Test::JSON, List::MoreUtils, and XML::Parser.
- Removed TODO on test in t/29-serialize.t.
- Removed unnecessary code in RDF::Query::Plan subclasses, bin/query.pl, bin/graph-bgp.pl and bin/graph-query.pl.
- Logging
- Added logging in RDF::Query::Plan::ThresholdUnion, and RDF::Query::Model.
- Changed logging level from debug to trace in RDF::Query::Plan::Triple, RDF::Query::Plan::Project, RDF::Query::Plan::Filter, RDF::Query::Plan::Join::NestedLoop, RDF::Query::Plan::PushDownNestedLoop, and RDF::Query::Model::RDFTrine.
- Added calls to Log::Log4perl::is_debug to eliminate unnecessary serialization of logging when not in use.
- Made error message more useful when SERVICE calls fail in RDF::Query::Plan::Service.
- Bugfixes
- Fixed bug in RDF::Query::Plan::Offset in cases where the offset was beyond the end of the result set.
- Fixed testing for Bloom::Filter in t/31-service.t.
- Fixed test expectations when making remote DBPedia query in t/34-servicedescription.t.
- Fixed check of $ENV{RDFQUERY_NETWORK_TESTS} to test boolean value, not just existence.
- Fixed (bad) expected serializations in t/29-serialize.t.
- Fixed bug in RDF::Query::Plan::ThresholdUnion attempting to close an iterator twice.
- Fixed sse serialization issues in RDF::Query::Algebra::BasicGraphPattern and RDF::Query::Algebra::Project.
- Fixed bug in RDF::Query::Node::from_trine() that up-cast blank nodes to variables.
- Fixed quoting issue in RDF::Query::Algebra::Service::sse().
- Fixed parameter handling in bin/graph-qeps.pl:prune_plans().
- Fixed handling of 'GRAPH ?g {}' (empty GraphGraphPatterns) to return all graph names.
- Added check for ref($node) in RDF::Query::VariableBindings::new (broke code after previous removal of blessed() check).
- Added use of defined() in code that had been testing boolean value of objects (and causing expensive string overloading).
- Miscellaneous Changes
- Added examples of queries and service descriptions in examples/.
- Updated dawg-eval.t to actually test graph equivalence.
- Clarified graph labels in RDF::Query::Model::RDFTrine::BasicGraphPattern::graph().
- Added the ability to add label annotations to RDF::Query::VariableBindings, RDF::Query::Algebra::Triple and RDF::Query::Algebra::Quad objects.
- RDF::Query::Plan::Quad and RDF::Query::Plan::Triple now add an 'origin' label annotation to the RDF::Query::VariableBindings object if the underlying statement has one.
- RDF::Query::Plan::prune_plans now uses a stable sort when comparing plan costs.
- RDF::Query::Algebra::Triple::new now up-casts to RDF::Query node objects, if necessary.
- RDF::Query::Model::RDFTrine::generate_plans now respects the force_no_optimization query flag.
- RDF::Query::Algebra::BasicGraphPattern::sse() now sorts triples for output.
- Added distinguish_bnode_variables method to RDF::Query::Algebra::Quad and RDF::Query::Algebra::Triple.
- Added RDF::Query::Node::Blank::make_distinguished_variable method.
- Added caching of sparql serializations to RDF::Query::Algebra::BasicGraphPattern and RDF::Query::Algebra::Triple.
- Added code to RDF::Query::VariableBindings::new to up-cast any RDF::Trine::Node objects to their RDF::Query equivalents.
- RDF::Query::new() now looks for $args{ defines }, and adds them to the internal %options HASH.
- Added hook in RDF::Query::execute_plan() to print the query plan to STDERR if $options{plan} is set (can be set if defines).
- Updated RDF::Query::Plan to only consider model-specific plans (if there are any).
Version 2.100 (2009-03-18)
- API
- Added ::Algebra::BasicGraphPattern::connected method.
- Added 'node_counts' as a recognized key to ::Model::RDFTrine::suports().
- Added ::Model::node_count method.
- Added ::Model::RDFTrine::count_statements() and ::Model::RDFTrine::node_count() methods.
- Added 'store' field to the data returned by the meta() method in the ::Model::* classes.
- Added a peek method to ::Iterator to support execution deferment like in ::Algebra::Service.
- Added ability to force SERVICE calls to abort using $ENV{RDFQUERY_THROW_ON_SERVICE} and RequestedInterruptError.
- Added bf methods to ::Triple and ::BasicGraphPattern to describe the BGP in terms of bound/free.
- Added bind_variables method to RDF::Query::Algebra.
- Added caching to ::Algebra::Service::_names_for_node.
- Added code to count (and warn) the rate of false positives from a bloomjoin.
- Added cost model hooks in RDF::Query and ::Algebra::BasicGraphPattern.
- Added FeDeRate BINDINGS to the list of supported extensions.
- Added get_basic_graph_pattern to ::Model::RDFTrine (not used yet).
- Added is_solution_modifier() methods to ::Algebra classes.
- Added labels and common patterns to service description template.
- Added more logic and debugging to aggregating triples into BGPs for SERVICE calls.
- Added optional restriction argument to ::Algebra::subpatterns_of_type.
- Added RDF::Query::Model::RDFTrine::BasicGraphPattner::graph() method.
- Added RDF::Query::Node::compare for sorting (either Trine or Query) node objects.
- Added RDF::Query::plan_class so that ::Federate can overload calls to ::Plan methods.
- Added support for computed statement generators (like ARQ's computed property support [e.g. list:member]).
- Added trial subsumes() methods to ::Algebra::BasicGraphPattern and ::Algebra::Triple.
- Algebra classes now call RDF::Query::algebra_fixup for optimization before falling back on normal fixup code.
- Allow equality test and disjunction filters in patterns that can be compiled to SQL.
- Fixed ::Algebra::GroupGraphPattern to use join_bnode_streams in cases where the bloom filter wasn't automatically created but instead provided by the user.
- Fixed ::Model::RDFTrine::as_string use with Quads.
- Fixed argument list for RDF::Query::Algebra::Service::_names_for_node called from bloom function.
- Fixed bug so ::Model::RDFTrine::meta may be called as a class method.
- Fixed RDF::Query::algebra_fixup to ignore service capabilities that would result in empty BGPs.
- Modified code for aggregate queries (though they are currently broken).
- Moved construction of bloom-filter-optimized patterns to RDF::Query::Algebra::GroupGraphPattern::_bloom_optimized_pattern().
- Moved initial federated service code into RDF::Query::fixup and ::algebra_fixup.
- Moved QEP generation code to RDF::Query::query_plan so it can be overloaded.
- Moved RDF::Query::add_service() to RDF::Query::Federate::add_service().
- Parsing service descriptions now more forgiving in the face of missing values.
- RDF::Query::Algebra::Triple::new now adds RDF::Query::Node::Variable objects for undefined nodes.
- RDF::Query::fixup() now only returns a construct pattern (the query pattern now being returned by RDF::Query::query_plan()).
- RDF::Query::Model::get_computed_statements now doesn't die if there's no query object present.
- RDF::Query::new() now accepts two-argument form with just $query and \%options.
- RDF::Query::Node::Literal objects now can compare as equal when they're of numeric type but the lexical values aren't numeric.
- RDF::Query::prune_plans now takes ExecutionContext as an argument, and in turn calls ::Plan::prune_plans.
- RDF::Query::query_plan() now returns all possible query plans when called in list context.
- RDF::Query::query_plans now calls RDF::Query::prune_plans to select from the list of possible QEPs.
- RDF::Trine::Node::Resource now escapes unicode in base URIs (now just relative URI part) before calling URI->new_abs.
- Removed now unused RDF::Query::construct() and RDF::Query::fixup().
- Removed old execute() code from ::Algebra classes.
- Removed unused redland fallback code from RDF::Query::Model::RDFTrine.
- Split RDF::Query::execute into prepare() and execute_plan() methods.
- Converted RDF::Query::execute() to use ::Plan classes.
- Updated ::Compiler::SQL to recognize ::Algebra::Project objects.
- Updates to RDF::Query::execute() to support explicit pre-binding lists (instead of just scalar values).
- ::Algebra::GroupGraphPattern now throws an exception if passed unblessed values as patterns.
- ::Federate now labels nodes in the QEP tree with applicable services.
- ::Model::debug() now shows data from the named graph model.
- ::Model::RDFTrine::add_uri now decodes resulting content as utf8 before proceeding.
- ::Model::RDFTrine::meta() probes the underlying store object to declare the proper 'store' class.
- ::Service::_names_for_node updated to use ::Plan classes for query execution (fixes use of the k:bloom filter).
- Classes
- Added algebra classes for solution modifiers and query forms (construct, project).
- Added code and tests for Query Execution Plan classes RDF::Query::Plan::*.
- Added RDF::Query::Federate::Plan for federation-specific code.
- Added RDF::Query::BGPOptimizer implementing a basic optimizer for basic selectivity-based join ordering.
- Added RDF::Query::CostModel classes for computing/estimating the cost of executing a specific pattern.
- Added RDF::Query::ExecutionContext to hold all necessary information for query execution (query, model, bound variables).
- Added RDF::Query::ServiceDescription for parsing DARQ-style service descriptions.
- Added RDF::Query::VariableBindings to wrap existing HASH-based variable binding structure.
- Added stub ::Plan::ThresholdUnion class for running optimistic queries.
- Added workaround to RDFCore bridge so that RDF::Core doesn't die if getStmts is called with a Literal in the subj or pred position.
- Added a RequestedInterruptError exception class.
- Added code for RDF-Trine specific BGP query plans.
- Changed debugging in RDF::Query modules to use Log::Log4perl.
- Made SERVICE work again by rolling back streaming socket work (now commented out).
- Moved federation code to new RDF::Query::Federate class.
- Plan generation now includes any plans the model object can provide.
- RDF::Query now always uses a cost model (defaulting to ::Naive).
- RDF::Query::Federate now defaults to SPARQLP parser.
- Removed logging/warn calls from forked process in ::Service (was screwing up the parent-child IO pipe).
- Removed use of "DISTINCT" queries in SERVICE calls (for pipelining).
- ServiceDescription now only runs sofilter if ?subject/?object are bound.
- Started work on a more holistic approach to supporting service descriptions (instead of using add_computed_statement_generator()).
- Updated ::Algebra::Service to fork and use LWP's callback mechanism for concurrency.
- ::Algebra::Service now defers loading of content until the first result is requested.
- ::Model::RDFTrine now only produces BGP plans if there is no get_computed_statement_generators in the query object.
- Code now materializes all node identities before creating the Bloom filter (so capacity arg is accurate).
- Bloom filter use is now only attempted on SERVICE blocks that don't immediately contain a FILTER.
- Re-ordered conditionals so that the service-bloom-filter try block is called less frequently.
- SERVICE execution now uses non-identity reasoning Bloom filter function.
- Syntax and Serialization
- Added from_sse method to ::Statement, ::Node.
- Added initial code for ARQ-style property paths.
- Added initial parser code for SPARQL Update (SPARUL) extension.
- Added new 'UNSAID' syntax for SPARQLP, implementing negation.
- Added parse_expr method to RDF::Query::Parser::SPARQL.
- Added RDF::Query::Algebra::Quad::bf() method.
- Fixed RDQL parser to qualify URIs before returning from parse().
- Fixed SSE serialization of Aggregates using '*' instead of a variable as the column.
- Removed (now unused) parser generator script.
- SPARQL parser now always adds a ::Algebra::Project (even when the query selects '*').
- SPARQL parser now creates ::Algebra::Construct objects for CONSTRUCT queries.
- SPARQL parser now puts ::Distinct above ::Sort algebras in the parse tree.
- SPARQLP parser now creates ::Project object as parent of any ::Aggregate.
- Turtle parser now doesn't modify the lexical value of numeric typed literals.
- Turtle parser now makes universal IDs for all blank node (even those with given IDs like _:xyz).
- Updated ::Algebra SSE serializations to conform to Jena's serialization syntax.
- Updated ::Algebra::Limit::sse to emit 'slice' serialization if its child is a ::Algebra::Offset.
- Updated as_sparql() methods to support the new ::Construct classes.
- Updated RDF::Query::sse to emit base and prefix serializations.
- Updated SPARQL parser and serializer tests to always assume an ::Algebra::Project on SELECT queries.
- Updated SSE serialization of ::Join::PushDownNestedLoop to use 'bind-join' terminology.
- Updates to SPARQLP parser to support FeDeRate BINDINGS keyword.
- ::Algebra::Distinct now does proper serialization in as_sparql().
- ::GroupGraphPattern::sse() updated to output the '(join ...)' only if the GGP has more than one pattern.
- Optimizer
- Added benchmark/plans.pl to show the runtimes of the available QEPs for a query.
- Added benchmark/costmodel.pl for testing the RDF::Query::CostModel.
- Added logging for execution time (time to construct iterator) of Triples, BGPs, GGPs and sorting.
- Added logging of cardinalities in ::Algebra::Triple, ::Algebra::BasicGraphPattern and ::Algebra::Service.
- Added logging to plan classes ::NestedLoop, ::Service, ::Triple.
- Naive plan is used in ::Federate::Plan::generate_plans only if no optimistic plans are available.
- Updated cost model code to work with ::Plan classes instead of ::Algebra classes.
- Logging code now uses sse serialization as log keys (because of expressions that can't be serialized as SPARQL).
- Logging object can now be passed to RDF::Query constructor.
- Updated logging of algebra execution to use SPARQL serialization as logging key.
- Miscellaneous
- SPARQL parser now constructs ::Algebra::Project objects (had been in RDF::Query::execute).
- Updated RDF::Query to require version 0.108 of RDF::Trine.
- Added new bloom:filter function variant that doesn't use identity reasoning.
- Added debugging information when RDFQUERY_THROW_ON_SERVICE is in effect.
- Fixed test plan for t/optimizer.t in cases where no appropriate model is available.
- Updated plan generation code to use ::BGPOptimizer when the model supports node_counts.
- Fixed SSE serialization bug in ::Algebra::Sort.
- Fixed bugs in RDF::Query and RDF::Query::Expression classes that insisted variables be RDF::Query objects (and not simply RDF::Trine objects).
- Fixed propogation of iterator binding_names when pre-bound values are used in ::Algebra execution.
- Fixed RDF::Query::Algebra::Triple to correctly set binding_names when pre-binding is used.
- Fixed use of pre-binding in execution of RDF::Trine optimized BasicGraphPatterns.
- Fixed bug in SQL compilation when restricting left-joins to specific node types (based on functions like isIRI).
- Fixed node identity computation based on owl:sameAs.
- Fixed bitrotted livejournal example script to work with new 2.000 API.
- Tests
- Added expected result count test in t/34-servicedescription.t.
- Added initial tests for algebra subsumes method.
- Added logging and costmodel tests.
- Added more example capabilities and patterns to the test service descriptions.
- Added RDF::Trine::Store::Hexastore to test model construction list in t/models.pl.
- Added sparql:pattern data to test service descriptions.
- Added sse re-serialization test to t/29-serialize.t.
- Added support for sparql:pattern in service description parsing.
- Added t/plan-rdftrine.t to test QEP generation optimized for RDF::Trine BGPs.
- Added test data for repeat patterns (e.g. { ?a ?a ?b}).
- Added tests to t/plan.t for QEP sse serialization.
- Cleaned up federation tests.
- Commented out in-progress service description tests.
- Fixed bug in t/23-model_bridge.t to allow two models from the same model class to be used in testing.
- Fixed error handling in t/plan.t.
- Fixed t/costmodel-naive.t to provide a serialized query to ::Plan::Service constructor.
- Fixed test count in algebra-bgp.t.
- Fixed test in t/31-service.t that relied on identity-reasoning support in bloom filters (which is now off by default).
- Fixed use of RDFQUERY_NETWORK_TESTS in 31-service.t.
- Improved use of temporary RDF::Trine stores in RDF::Query tests.
- Marked tests TODO for federated query serialization.
- Removed what looks like an accidentally pasted test in t/plan.t.
- SERVICE tests involving bloom filter handling marked as TODO.
- ServiceDescription parsing now gets entire sparql:patterns and not just arcs to depth one.
- Silenced unfinished test debugging in t/logging.t.
- Updated args to roqet call in failing_earl_tests.sh.
- Updated costmodel and logging test expected results that changed due to changes to ::Plan::Join code.
- Updated dawg-eval.t regex to recognize RDFTrine blank nodes.
- Updated DBPedia test query in t/34-servicedescription.t to reflect new source data.
- Updated expected cardinalities in t/logging.t for current plan choice.
- Updated logging tests to use the new sparql serialization keys.
- Updated SERVICE test in t/plan.t (still broken, but only runs when dev env var RDFQUERY_NETWORK_TESTS in effect).
- Updated t/plan.t to be less dependent on the specific state of the kasei.us service endpoint.
- Updated test service description RDF for new tests.
- Updates to improve logging and test coverage.
- Examples and Documentation
- Added examples/query.pl to show a simple example of loading data and executing a query.
- Added examples/create_query_api.pl for generating queries programatically (based on request from KjetilK).
- Added bin/graph-bgp.pl to produce a png of a query's BGP variable connectivity graph.
- Added bin/graph-query.pl to graph the (one chosen) QEP tree.
- Added bin/graph-qeps.pl to vizualize all QEPs of a query with GraphViz.
- Updated bin/parse.pl to emit the SSE serialization of the query algebra tree.
- Updated bin/rdf_parse_turtle.pl to warn on any parser error.
Version 2.002 (2008-04-25)
- Updated Bloom::Filter required version in RDF-Query's Makefile.PL.
- Fixed bug in get_function() when called as a class method.
- Updated sparql:logical-* functions to accept more than two operands.
- Added code to make loading of Bloom::Filter optional.
- Added Bloom::Filter to list of recommended modules.
Version 2.001 (2008-04-19)
- Fixed use of "DESCRIBE <resource>" (instead of "DESCRIBE ?var").
- Fixed SPARQL serialization of queries with DISTINCT.
- Added ::Algebra::subpatterns_of_type method for retrieving all subpatterns of a particular type.
- Moved sort_rows() into new ::Algebra classes Sort, Limit, Offset and Distinct.
- Updated SQL compiler to handle new ::Algebra classes.
- Bumped required RDF::Trine version to 0.106.
- Added methods to RDF::Query for retrieving lists of supported SPARQL extensions and extension functions.
- RDF::Trine pattern optimization now holds onto the original BGP object for forwarding of calls to as_sparql().
- Removed use of Storable module. Query execution no longer clones parse tree before running.
- Simplified project operation on query stream in RDF::Query::execute().
- fixup() method in ::Algebra and ::Expression now passed the query object as an argument.
- Replaced ::RDFTrine::unify_bgp with more general fixup() implementation.
- ::Algebra classes now defer to the bridge during fixup() to allow model-specific optimizations.
- RDF::Trine::Iterator::smap now allows overriding default construct_args (e.g. binding names).
- sparql:str now throws a TypeError if argument isn't bound.
- Fixed referenced_variables in RDF::Query::Expression.
- Fixed COUNT function to only count bound variables.
- Fixed aggregation to work with expressions.
- Added support for GROUP BY clauses to aggregation queries.
- Removed now unused ::Algebra::OldFilter class.
- Added serialization tests for aggregate and union patterns.
- Moved as_sparql methods from RDF::Trine:: to RDF::Query:: classes.
- Removed context- (quad-) specific code from RDF::Query::Algebra::Triple.
- Fixed serialization of BOUND filter functions.
- Fixed serialization of unary expressions.
- Fixed call to join_streams to use ::Iterator::Bindings instead of ::Iterator.
- var_or_expr_value now takes bridge object as an argument.
- var_or_expr_value will now accept any RDF::Query::Expression object as an argument.
- Added test for using AS syntax for variable renaming: "(?var AS ?newvar)".
- Added support for MIN, MAX, COUNT and COUNT-DISTINCT aggregate operators to the SPARQLP parser.
- Added COUNT DISTINCT variant aggregate operator.
- Aggregates (MIN, MAX, COUNT, COUNT-DISTINCT) now return xsd:decimal values (this shouldn't really happen for non-numeric operands to MIN and MAX...)
- Added as_sparql submethod to RDF::Query::Node::Literal to serialize numeric types unquoted.
- Added var_or_expr_value method in RDF::Query.
- Removed unused _true and _false methods in RDF::Query.
- Fixed existing aggregates code and tests.
- Removed unused (and bitrotted) t/05-stress.t test.
- Made all tests that access the network opt-in with the RDFQUERY_NETWORK_TESTS environment variable.
- Updated POD for ::Expression::Alias.
- Added tests for select expressions.
- Added initial support for selecting expression values.
Version 2.000 (2008-03-19)
- RDF::Query now uses RDF::Trine package for common classes (nodes, statements, iterators).
- Moved RDF::Query::Stream into RDF::Trine::Iterator namespace.
- Reshuffled SPARQL parsers tests.
- Added support for RDF::Trine::Model.
- RDF::Trine::Iterator can serialize to XML and JSON natively; Updated tests accordingly.
- rdf namespace is only added by default for RDQL.
- Fixed bug where the wrong bridge object would be returned for queries with FROM clauses.
- Moved query_more code to Algebra classes.
- Added RDF::Query::pattern method to return the GGP algebra pattern for the query.
- Added RDF::Query::as_sparql method to serialize query as SPARQL string.
- Removed unused RDF::Query::set_named_graph_query method.
- Fixed bug where triples from a FROM clause were loaded into the underlying persistent store.
- Added POD to RDF::Query::Node classes.
- Added equal method to RDF::Query::Node classes.
- RDF::Query::Node::Blank constructor now optionally produces identifiers.
- Merged tSPARQL parsing code into new SPARQLP parser.
- Added definite_variables method to RDF::Query::Algebra classes.
- Triple class now serializes rdf:type shortcut 'a' appropriately.
- Removed 'VAR' type from ::Node::Variable object structure.
- Updated code to always expect a HASH reference from ::Bindings iterator.
- Added more (sparql and see) serialization tests.
- Removed old fixup code, replaced by ::Algebra fixup methods.
- Moved FROM clause data loading to its own method.
- Started removing old code (RDF::Base, direct DBI use, AUTOLOAD, profiling).
- Moved general count_statements() method into bridge superclass.
- Fixed SQL compiler to work with ::Algebra and ::Node classes.
- Added as_native method to bridge superclass for converting ::Node objects to bridge-native objects.
- Updated document namespace declaration for SPARQL XML Results.
- Added support for SERVICE queries (ala ARQ) with Bloom filter semijoins.
- Moved Expression classes out of the Algebra hierarchy and into their own space (RDF::Query::Expression).
Version 1.501 (2007-11-15)
- Fixed CONSTRUCT+OPTIONAL bug.
- Added as_sparql methods to Algebra and Node classes to serialize patterns in SPARQL syntax.
- Added deparse script.
- Fixed jena:sha1sum tests when Digest::SHA1 isn't available.
Version 1.500 (2007-11-13)
- Query Engine
- URIs are now properly qualified with a BASE when present.
- Base URI passed to constructor is now used if no BASE clause exists in the query.
- Fixed BASE qualification when an IRI contains Unicode characters (Emulating IRI support with the URI module).
- NAMED graph data is now seperated from the default model into new (temporary) models.
- NAMED graphs now work with RDF::Core.
- Added new RDF::Query::Algebra:: classes that are used to represent query ASTs.
- Added new RDF::Query::Node:: classes that are used to represent RDF Nodes and Variables.
- Major refactoring to RDF::Query::query_more() to enhance extensibility.
- Added RDF::Query::query_more_triple() and RDF::Query::query_more_bgp() for triple and bgp matching.
- Improved support of GGP pattern matching.
- Added sgrep, smap, swatch and concat methods to RDF::Query::Stream class.
- Refactored query_more() variants and sort_rows() to use new stream methods sgrep, smap, and concat.
- Continued to fix bugs to more closely align with DAWG tests.
- Updated DAWG tests to run with the RDF::Core backend.
- Any DAWG tests with mf:requires are now automatically marked TODO.
- DAWG tests graph equality is now punted to user verification.
- Fixed bNode merging code in DAWG tests.
- query_more() variants and sort_rows() now all return RDF::Query::Stream objects.
- query_more() (and everything it calls) now expects bridge object as a method argument (to ensure NAMED graph querying works).
- Added join_streams() to perform netsted-loop natural joins on two Stream objects.
- Filters
- Added call_function() method to abstract the generation of ['FUNCTION',...] blocks.
- FILTER operator != is now negative for unknown datatypes.
- Fixed exception handling in check_constraints().
- Fixed type-promotion in arithmetic operations and added recognized xsd numeric types.
- API Chnage: extension functions now take a bridge object as their second argument (after the query object).
- Fixed equals() method in RDF::Core bridge to properly use the RDF::Core API.
- Javascript function makeTerm now accepts language and datatype parameters.
- toString() javascript funtion now returns just the literal value (not including language or datatype).
- sop:str now will stringify blank nodes properly.
- sparql:langmatches now properly differentiates between no language tag and an empty language tag.
- Parsers
- Parsers now generate ASTs using the Algebra and Node classes.
- Fixed bugs in SPARQL tokenizer for some Unicode strings (with combining accents).
- RDF::Query::Parser::new_literal() now canonicalizes language tags (to lowercase).
- Fixed GGP verification in RDF::Query::Parser::SPARQL::fixup().
- Merged GGPAtom changes from tSPARQL to SPARQL grammar.
- Backends
- Fixed bug in RDF::Query::Model::RDFCore::equals() when comparing two blank nodes.
- Changed RDF::Query::Model::RDFCore::as_string to return strings where node type is identifiable (like Redland, URIs as [...], literal \"...\", bnodes (...)).
- Model methods literal_value, literal_datatype and literal_value_langauge now return undef if argument isn't a literal.
- Model methods uri_value and blank_identifier now return undef unless argument is of correct type.
- Model add_string methods now normalize Unicode input.
- Blank node prefix is now scoped to bridge, not lexically in RDF::Query::Model::RDFCore.
- RDF::Query::Model::Redland::new_literal now forces argument to a string (XS code breaks on non-PVOK scalars).
- RDF::Query::Model::Redland::add_uri now uses LWP instead of relying on Redland to fetch content.
- Redland model class now recognizes DateTime objects as literals.
- Updated add_uri() method in RDF::Core bridge to support named graphs (only one name per model for now).
- Miscellaneous
- Added rudimentary profiling code (Devel::DProf seems to crash on RDF::Query)
- Added initial code for supporting property functions (using time:inside as an example).
- Removed multi_get code.
- Removed code for MULTI patterns. Will replace with algebra-based optimization in the future.
- RDF::Query::Stream constructor now accepts an ARRAY reference.
- Stopped using the peephole optimizers. Will replace with an algebra-based optimizer in the future.
Version 1.044 (2007-09-13)
- DAWG tests now emit EARL reports.
- Added test harness and temporal data importing scripts to new bin/ directory.
- Added support for temporal queries in RDF::Query and optimizers.
- Added support for CONSTRUCT queries in new YAPP-based SPARQL parsers.
- Added TIMED graph tests for new SPARQL temporal extensions.
- Added tests to SPARQL parser for bugs that were discovered with temporal extensions.
- Added POD to new SPARQL parsers.
- Added new Parse::Yapp-based SPARQL parser in preparation for temporal SPARQL extensions.
- Added stub functions for temporal extension support.
- Added model_as_stream() method to Redland bridge class.
- Addded debug() method to RDF::Query::Model.
- Added UNION tests.
- Added a javascript debugging flag to RDF::Query.
- Added RDF::Query::groupgraphpattern() for handling GGPs.
- Added xsd:integer casting function.
- Added <http://kasei.us/2007/09/functions/warn> as a FILTER tee that warns to STDERR.
- Added Eyapp SPARQL grammer file and replaced parser with auto-generated code from eyapp.
- Marked some SPARQL parser tests as TODO (due to incompatability with new YAPP-based parser).
- Network tests are now run against all available models.
- Stream tests are now run against all available models.
- Query parser initialization code cleaned up (and now supports beta tSPARQL parser).
- net_filter_function() now properly accesses nodes with bridge methods.
- RDF::Query::Parser::new_blank now assigns default names if none is supplied.
- Updated error messages in SPARQL parser to align with new YAPP-based parser.
- SPARQL parse_predicate_object() fixed to support tripleNodes.
- SPARQL parse_object() and parse_predicate() fixed for whitespace insensitivity.
- Moved old hand-written SPARQL parser to now unused SPARQL-RD.pm.
- Moved new YAPP-based SPARQL parser to SPARQL.pm.
- Copied YAPP-based SPARQL parser for new temporal extension tSPARQL.pm.
- Moved existing tests for hand-written SPARQL parser to 01-sparql_parser.t.rd-old.
- Moved new YAPP-based SPARQL tests to t/01-sparql_parser.t.
- Removed bad-syntax queries from optimizer and SQL compiler tests.
- Fixed bad-syntax queries in stream and hook tests.
- Made output of coverage tests easier to read by adding test names.
- Fixed SPARQL parsers to allow keywords as variable names.
- Fixed SPARQL parsers to allow dashes and underscores in variable names.
- Fixed bad parser constructor call in SQL compiler tests.
- Suppressed RDF::Base loading (again) during RDF::Query startup.
- RDF::Query::Model::Redland::debug now shows contexts during iterator debugging.
- Moved the old (hand written) SPARQL parser out of the way to make test harnesses happy.
- SPARQL parser now respects spec regarding the reuse of blank node labels across BGPs.
- SPARQL parser now does the right thing with NIL (the empty list).
- SPARQL parser now handles embedded GGPs correctly.
- Updated SPARQL parser and tests to pass (almost all) DAWG tests.
- Fixed bug where results couldn't be sorted by a non-selected variable.
- Removed the unused RDF::Query::timed_graph() method.
- RDF::Query::qualify_uri is now more liberal in what it accepts.
- Fixed xsd:boolean casting of integer values.
- RDF::Query::Parser::new_variable can now generate private variable names.
- Fixed test suite to work properly on systems without Redland.
- Disabled loading of tSPARQL parser for release.
- Removed function prototype definitions in Model base class (was causing loading problems when models are missing).
Version 1.043 (2007-06-14)
- Fixed broken MANIFEST causing MakeMaker code to break.
Version 1.042 (2007-06-13)
- Added support for Javascript URL-based extension functions.
- Added GPG signing support for Javascript functions.
- Added meta methods to model classes.
- Added count_statements methods to model classes.
- Added default format for stringifying query result streams.
- Added SPARQL syntax coverage tests.
- Added stream tests.
- ISIRI() now returns a sop:isIRI function IRI.
- Redland bridge add_uri strips off URI fragment from parser base URI.
- Underlying models aren't loaded if turned off by environment variables.
- Stopped using the (currently broken) multi-get code.
- Model classes aren't used if turned off by environment variable.
- Standardized node testing to is_node (replacing older isa_node).
- GPG verification failure now throws exceptions.
- GPG fingerprint handling is now whitespace insensitive.
- Removed (currently) unused multiget tests.
- Redland bridge uri_value returns undef if not called with a node.
Version 1.041 (2006-11-26)
- Removed unwanted '+' signs on stringified bigints when running under perl 5.6.x.
- Fixed unicode errors when running under perl 5.6.x.
- Added tests for model bridge classes.
- Fixed bugs in SQL bridge class.
- RDFCore and Redland bridge classes now throw error when passed a bad model object.
- Bridge class support() method now responds to feature requests for 'temp_model'.
- Fixed bug in RDF::Query::Model::RDFCore::isa_resource returning true for blank nodes.
- Fixed code in RDF::Query::Model::::SQL::equals().
- Added partial support for new RDF::Storage::DBI storage class.
- Added support for RDF::Query:::Model::SQL models in RDF::Query bridge code.
- Removed RDF::Query::Model::SQL::* code that's now in RDF::Storage::DBI.
- Added tests for backend bridge classes (RDF::Query::Model::*).
- Added checks for which backends support XML serialization.
- Fixed naive peephole tests in cases where model supports cost-based analysis.
- Fixed bugs in tests that were relying on as_string() to act like literal_value().
- Added RDF::Base support.
- Fixed bug in fixup() that prevented running queries against multiple models.
- Added SimpleQueryPatternError exception class for future work on multi-get optimizations.
- Removed forced dependence on Digest::SHA1.
- Makefile.PL now recommends Digest::SHA1 (for jena function) and Geo::Distance (for 07-filters.t).
Version 1.040 (2006-07-21)
- Added support for BOUND() fiters in SQL compilation.
- SQL compiler now produces valid SQL when query variable names are SQL reserved keywords.
- Moved SPARQL parser test data into YAML.
- Added YAML as a build-time prerequisite.
- Fixed SPARQL parsing bug for blank nodes as statement objects.
- Added peephole optimizer code with naive and cost-analysis strategies.
- Added add_string method to RDF::Query::Model::Redland.
- Added node_count method to RDF::Query::Model::Redland (only used for testing at this point).
- RDF::Query::execute() now uses the peephole optimizer.
- Removed punting code in RDF::Query::execute that tried to do JIT optimization.
- Removed calls to getLabel() on model objects in test files.
- Fixed dawg tests (was dying because of multiple plans being printed).
- Fixed cost-based peephole optimizer tests (by forcing Redland to do node counting).
Version 1.039 (2006-07-14)
- Removed dawg tests from distribution. Only used as developer tests now.
- Updated package to use Module::Install instead of ExtUtils::MakeMaker.
- Fixed a spurious uninitialized warning in RDF::Query::get_bridge.
Version 1.038 (2006-07-09)
- Fixed DBI case-sensitivity for PostgreSQL support.
- Cleaned up SQL syntax for easier debugging.
- Removed extra parens in SQL that were causing postgresql to break.
- Reference test foaf file using File::Spec->catfile() instead of directly.
- Fixed SPARQL parsing bug for anonymous nodes in FILTER expressions.
- Fixed major SQL compilation bugs for testing equality in FILTER expressions.
- Fixed bug in hashing code for blank nodes in SQL compiler.
Version 1.037 (2006-07-06)
- execute() method now takes optional 'bind' parameter for pre-binding query variables.
- Updated code to support basic FILTERs in SQL compilation.
- Fixed bug in SQL compilation where no WHERE clause was needed.
- Fixed bug in SQL compilation when using model-specific Statements tables.
- Added Storable to the list of required modules (was missing in the list).
- Fixed typos in metadata about past versions in DOAP Changes.ttl.
Version 1.036 (2006-06-26)
- Fixed memory leak in RDF::Query::Stream that resulted in too many database handles.
- Initial support for OPTIONALs in SQL compiler.
- Removed LWP requirement for systems without libwww.
- Added support for class variable to hold parsing errors. (Beware under threads.)
- RDF::Query now sets error variable upon parsing error. (Access with error().)
- Fixed POD errors, and added tests for POD coverage.
- Added model API methods to SQL model class.
- Added close() method to RDF::Query::Stream.
Version 1.035 (2006-06-04)
- Added DAWG tests and harness.
- Rewrote core logic in OPTIONAL handling code.
- Comparisons on literals now respect numeric datatypes.
- Fixed outdated calling conventions in casting functions.
- Added custom functions:
- jena:sha1sum
- jena:now
- jena:langeq
- jena:listMember
- ldodds:Distance
- Added new model methods: equals, subject, predicate, object.
- Relocated external http-based test data to .Mac URLs.
Version 1.034 (2006-05-01)
- Added JSON serialization for bindings and boolean queries.
- Initial support for compiling RDF queries to SQL queries using the Redland schema.
- Added to_string method to query results Stream class.
- Model objects now store the query parse tree for access to data needed in serialization.
- Unquoted number and boolean literals in SPARQL are now datatyped appropriately.
- Fixed crashing bug when RDF::Query::Model::Redland::as_string was called with an undefined value.
- Fixed bug parsing queries with predicate starting with 'a' (confused with { ?subj a ?type}).
- Fixed bug parsing queries whose triple pattern ended with the optional dot.
Version 1.033 (2006-03-08)
- Updated test suite to work if one of the model classes is missing.
- Data-typed literals are now cast appropriately when used in a FILTER.
- Added support for xsd:dateTime datatypes using the DateTime module.
- Added support for LANG(), LANGMATCHES() and DATATYPE() built-in functions.
- Updated TODO list.
- Added more exception types to RDF::Query::Error.
- Added POD coverage.
- Fixed SPARQL parsing bug for logical operators <= and >=.
Version 1.032 (2006-03-03)
- Replaced the Parse::RecDescent SPARQL parser with a much faster hand-written one.
- Updated SPARQL parsing rules to be better about URI and QName character sets.
- FILTER equality operator now '=', not '==' (to match SPARQL spec).
- Initial support for FILTER constraints as part of the triple pattern structure (Will allow for nested FILTERs).
- Implemented support for ordering query results by an expression.
- Fixed bug in expresion handling of unary minus.
- Fixed bug in Redland NAMED GRAPH parsing.
- Fixed bug in RDF::Core parsing code where blank nodes would be accidentally smushed.
Version 1.031 (2006-02-08)
- Added support for NAMED graphs.
Version 1.030 (2006-01-13)
- Added support for SELECT * in SPARQL queries.
- Added support for default namespaces in SPARQL queries.
- Added tests for querying RDF collections in SPARQL (1 ?x 3)
- Added tests for triple patterns of the form { ?a ?a ?b . }
- Added tests for default namespaces in SPARQL.
- Added tests for SELECT * SPARQL queries.
- Bugfix where one of two identical triple variables would be ignored ({ ?a ?a ?b }).
Version 1.028 (2005-11-18)
- Added SPARQL functions: BOUND, isURI, isBLANK, isLITERAL.
- Updated SPARQL REGEX syntax.
- Updated SPARQL FILTER syntax.
- Added SPARQL RDF Collections syntactic forms.
- Fixed FILTER support in OPTIONAL queries.
- Added binding_value_by_name method to Query results stream class.
- Added isa_blank methods to RDF::Redland and RDF::Core model classes.
- Fixed RDF literal datatyping when using Redland versions >= 1.00_02.
- Updated SPARQL grammar to make 'WHERE' token optional.
- Added <commit> directives to SPARQL grammar.
- Updated SPARQL 'ORDER BY' syntax to use parenthesis.
- Fixed SPARQL FILTER logical-and support for more than two operands.
- Fixed SPARQL FILTER equality operator syntax to use '=' instead of '=='.
- Now requires Test::More 0.52 because of changes to is_deeply().
Version 1.027 (2005-07-28)
- Updated to follow SPARQL Draft 2005.07.21:
- ORDER BY arguments now use parenthesis.
- SPARQL parser now supports ORDER BY operands: variable, expression, or function call.
- Added binding_value_by_name() method to query result streams.
Version 1.026 (2005-06-05)
- Added new DBI model bridge (accesses Redland's mysql storage directly).
- Added built-in SPARQL functions and operators (not connected to grammar yet).
- Added bridge methods for accessing typed literal information.
Version 1.024 (2005-06-02)
- Added missing SPARQL OFFSET grammar rules.
- Added XML Results support for graph and boolean queries (DESCRIBE, CONSTRUCT, ASK).
- Fixed major bugs in RDF::Core bridge:
- - Bridge wasn't using passed model.
- - Literal construction was broken.
- - Blank node construction was broken when no identifier was specified.
- Stream::bindings_count now returns the right number even if there is no data.
- XML Result format now works with RDF::Core models.
- The Model bridge object is now passed to the Stream constructor.
- Internal code now uses the variables method.
- Removed redundant code from ORDER BY/LIMIT/OFFSET handling.
- Removed unused count method.
- Removed unused delegating AUTOLOAD.
- Removed unused parse_files method.
- Removed usused add_file method.
- Removed duplicate net test file.
- Added test file for local file-based SPARQL 'FROM' queries.
- Added test file for SPARQL Result Forms (LIMIT, ORDER BY, OFFSET, DISTINCT).
- Added test file for SPARQL Protocol for RDF (XML Results).
- Added new tests based on Devel::Cover results.
- Some test files now run against both Redland and RDF::Core:
- - 00-simple.t
- - 03-coverage.t
- - 10-sparql_protocol.t
- All debugging is now centrally located in the _debug method.
- Moved Stream class to lib/RDF/Query/Stream.pm.
- Fixed tests that broke with previous fix to CONSTRUCT queries.
- Fixed tests that broke with previous change to ASK query results.
Version 1.021 (2005-06-01)
- Added SPARQL UNION support.
- Broke OPTIONAL handling code off into a seperate method.
- Added new debugging code to trace errors in the twisty web of closures.
Version 1.020 (2005-05-18)
- Added support for SPARQL OPTIONAL graph patterns.
- Calling bindings_count on a stream now returns 0 with no data.
- Added Stream methods:
- is_bindings
- binding_name
- binding_values
- binding_names
- Added as_xml method to Stream class for XML Binding Results format.
Version 1.016 (2005-05-08)
- Added initial support for SPARQL ASK, DESCRIBE and CONSTRUCT queries.
- Added new test files for new query types.
- Added methods to bridge classes for creating statements and blank nodes.
- Added as_string method to bridge classes for getting string versions of nodes.
- Broke out triple fixup code into fixup_triple_bridge_variables().
- Updated FILTER test to use new Geo::Distance API.
Version 1.015 (2005-05-03)
- Fixes to the arguments passed to FILTERs.
- Filter tests now show example of two custom filters:
- Transitive subClassOf testing.
- Logical comparison operators (range testing lat/lon values).
- Added literal_value, uri_value, and blank_identifier methods to bridges.
- Redland bridge now calls sources/arcs/targets when only one field is missing.
- Fixes to stream code. Iterators are now destroyed in a timely manner.
- Complex queries no longer max out mysql connections under Redland.
- Cleaned up node sorting code.
- Removed dependency on Sort::Naturally.
- Added new node sorting function ncmp().
- check_constraints now calls ncmp() for logical comparisons.
- Added get_value method to make bridge calls and return a scalar value.
- Fixed node creation in Redland bridge.
- Moved DISTINCT handling code to occur before LIMITing.
- Added variables method to retrieve bound variable names.
- Added binding_count and get_all methods to streams.
- get_statments bridge methods now return RDF::Query::Stream objects.
Version 1.014 (2005-04-26)
- Made FILTERs work in SPARQL.
- Added initial SPARQL support for custom function constraints.
- SPARQL variables may now begin with the '$' sigil.
- Added direction support for ORDER BY (ascending/descending).
- Added 'next', 'current', and 'end' to Stream API.
Version 1.012 (2005-04-24)
- Stream objects now handle being constructed with an undef coderef.
- Streams are now objects usinig the Redland QueryResult API.
- RDF namespace is now always available in queries.
- row() now uses a stream when calling execute().
- Added ORDER BY support to RDQL parser.
- SPARQL constraints now properly use the 'FILTER' keyword.
- SPARQL constraints can now use '&&' as an operator.
- SPARQL namespace declaration is now optional.
- Updated tests.
Version 1.010 (2005-04-21)
- execute now returns an iterator
- Added core support for DISTINCT, LIMIT, OFFSET
- Added initial core support for ORDER BY (only works on one column right now)
- Broke out the query parser into it's own RDQL class
- Added initial support for a SPARQL parser
- Added support for blank nodes
- Added lots of syntactic sugar (with blank nodes, multiple predicates and objects)
- Added SPARQL support for DISTINCT and ORDER BY
- Moved model-specific code into RDF::Query::Model::*
- Moving over to redland's query API (pass in the model when query is executed)
Copyright
Copyright © 2005–2015 Gregory Williams. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
RDF-Query-2.918/SIGNATURE 000644 000765 000024 00000037432 13033227746 014646 0 ustar 00greg staff 000000 000000 This file contains message digests of all files listed in MANIFEST,
signed via the Module::Signature module, version 0.79.
To verify the content in this distribution, first make sure you have
Module::Signature installed, then type:
% cpansign -v
It will check each file's integrity, as well as the signature's
validity. If "==> Signature verified OK! <==" is not displayed,
the distribution may already have been compromised, and you should
not run its Makefile.PL or Build.PL.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
SHA1 1c6d0b399aadbd19ca2a01e6b685f3307768764a Changes.ttl
SHA1 8963ea8452cff037bfc791e300c4df1bce9424af MANIFEST
SHA1 9e85fab616f55e591b784e0d437814c08023de7b META.yml
SHA1 a16995de339fdf353650c786bc5d1024ded8208c Makefile.PL
SHA1 13918e0f6614b9fabb6c0a5884dd3dc9bd26db8f README
SHA1 ca95d6001a20b8a11fbf59c8eee16ea0b87a8dad README.html
SHA1 1ab0877fcab9964b7fd4f66c75477d964f08555b bin/dawg11-status.pl
SHA1 824179e3ee296f55ea91cdaacc4ede0386de3e7d bin/deparse.pl
SHA1 3bd85b6d54fae8af8796763c3975e1247259dcec bin/failing_earl_tests.sh
SHA1 ece33e492f1e0a90c3cbc8b45d9cf53103b1033d bin/fedoptimize.pl
SHA1 a51f90dd692bdc78b01cf61ffe0da3ac46219823 bin/fedquery.pl
SHA1 9f3178e6eab61481b74f2a915529c261eb5a52c8 bin/graph-bgp.pl
SHA1 d83e35cff91306658ec28a5a194415d880603d96 bin/graph-qeps.pl
SHA1 5af3d6892f4fc57ccf18bef8e00aa662228be7c9 bin/graph-query.pl
SHA1 b832b80b0410e97f206c392a72d250c104b1b6d8 bin/hexastore_query.pl
SHA1 0bc9a73e3b75acb6788ae41aa2eb430098d40388 bin/json.pl
SHA1 bdb77c61f587c3da4e9f4daf26ba9918c88a4a2c bin/open-test-files.pl
SHA1 6af97114e44b89b9b2cb4e986776c8ad39c3d4f8 bin/parse.pl
SHA1 05fe4ab659121586bc26d8300e34f6499410d48d bin/parse_profile.pl
SHA1 1d08a6cfc90665744d5e6000584f1b5da796e46b bin/passing_earl_tests.sh
SHA1 249197691728c4d36fdf31a522759ee8e95ff4a5 bin/query.pl
SHA1 23ea129036b22fe92b6e66a1dbeb1f51e80d35a4 bin/rqsh
SHA1 40260c21fdf3a8684cbbddd39bb29dd6cdbb9dd3 bin/rqsh-server.pl
SHA1 14c583933ced0bdc27a81bb7d5cd9e7ef2d9a520 data/Flower-2.rdf
SHA1 80c7ba4b112d5173878b1ba6c8968275cc7873d1 data/about.xrdf
SHA1 8825e353c65215df9c96ac8ada3615d940d5f0ab data/bnode-person.rdf
SHA1 fdecdfedfafd8fdf32db81864d317c3a4c228063 data/federation_data/alice.rdf
SHA1 5b9d419a370f50a465bd91a4a80dcfc6a89780f3 data/federation_data/alice_bob.rdf
SHA1 73212ebbc3040623f25c5acc1ff21baeec5fbf17 data/federation_data/bob.rdf
SHA1 d9e2e3af6a9d74d58c966d1947cdf68161e4d639 data/foaf.xrdf
SHA1 c376e4aaa018f642c291aec9df27d7768038b8c1 data/greenwich.rdf
SHA1 636a3d5fb8e4a45a3de2aea4a986bacc2ab0b2cb data/named_graphs/alice.rdf
SHA1 59e840e1598987e991e527ec45d6576f5053dd21 data/named_graphs/alice.ttl
SHA1 b4e13d1fee09c406cdffd6e93d8f10f95d806cc0 data/named_graphs/bob.rdf
SHA1 e3a79398e61eed62efca7367dabfddf89c2338d6 data/named_graphs/bob.ttl
SHA1 f6499f4b7a5c39ebc1e30c301c2a47ab95be69bf data/named_graphs/meta.rdf
SHA1 39fbdd47c713d59167ed03301ad794963c8837f0 data/named_graphs/meta.ttl
SHA1 215f259428f7b2661517f33808f55b09d28e3b74 data/named_graphs/repeats1.rdf
SHA1 8216059aa8dc09d808bab127c16d41008fc69d92 data/named_graphs/repeats2.rdf
SHA1 39477849861b33e741e148f256c91557f416fc14 data/rdfa-test.xhtml
SHA1 02797e9814c7d00ff60397ee41a57e83a2344380 data/service-kasei.ttl
SHA1 18c24a093059f5f9f07e7218bc9f66b56421b5ec data/service.ttl
SHA1 0613e1c2acc90c14e2fe5a87cec209b7d92362e1 data/t-sparql11-aggregates-1.rdf
SHA1 8141df2762aba4205d2735e6bb7e7b247b3002c9 data/temporal.rdf
SHA1 fb69c7e4bc494e95f4d4d38c5b7c79b8cf6f26a7 doap.rdf
SHA1 ecd004817e6716a71fa342ab477d7594a9d4d084 examples/create_query_api.pl
SHA1 d6695d34b0bdfda58851649a0699b96ff1ff2e88 examples/livejournal.pl
SHA1 814ff9b3e6fc419d4110e5320ae6b148695fba23 examples/queries/sparql-ask-people.rq
SHA1 b14ddff044b912ad758db092f7044e1bebe912be examples/queries/sparql-bgp-people-knows.rq
SHA1 450005973a9e5afee2584aacd08368f090784eab examples/queries/sparql-bgp-people.rq
SHA1 f247c9312537ae848560ef4b6dc011a020ee5935 examples/queries/sparql-ggp-person-opt-knows.rq
SHA1 5b173f4dc339e3a27081a8808bfee84b01adc707 examples/queries/sparqlp-service-people-names.rq
SHA1 fae459718d2e86b42928c8baab31ada0c5a6873c examples/query.pl
SHA1 938c6260d6094023f47e1460bc0301bbed2cd969 examples/query_url.pl
SHA1 143ff69d0711f2c19b35cd80fcfc5c9d751e192a examples/service_descriptions/dbpedia_org.ttl
SHA1 84fbf8384d6764a7c0a94d1a23eaeb3f41685189 examples/service_descriptions/kasei_us.ttl
SHA1 bce3c51bb369419603298064b78e14077b93af66 inc/Module/Install.pm
SHA1 d001b4b9a48395a8c4134b234a0e1789138427c5 inc/Module/Install/AuthorTests.pm
SHA1 fe220f215f645500ce8f14ff5e19d9a28692af56 inc/Module/Install/Base.pm
SHA1 b56ed8e42c600e08007d152cf0b1438a7c3b7f6e inc/Module/Install/Can.pm
SHA1 99c531a17a67ce5250df2ae151cc48c80d914cde inc/Module/Install/Fetch.pm
SHA1 76efdca3603159e0ae0e18f19fe72a0211a69529 inc/Module/Install/Makefile.pm
SHA1 2e33e87882d60db3913da6284dd5295e5315e18a inc/Module/Install/Metadata.pm
SHA1 01978a56e76a58399af3bd4d022aa990b9669bee inc/Module/Install/Scripts.pm
SHA1 c830b819e61bda5eca077c6291293bba61b3b9f2 inc/Module/Install/Win32.pm
SHA1 cb52b9d6f88d512d448a6f35ed0af0d1201a134b inc/Module/Install/WriteAll.pm
SHA1 261c4028c36edd93f6d9866338d16164d598ee2f lib/RDF/Query.pm
SHA1 f564c673e681cab7d3756f93be84ad32b1b5dffd lib/RDF/Query/Algebra.pm
SHA1 298e478564d1e96557e25e545afd123f5ac6bc29 lib/RDF/Query/Algebra/Aggregate.pm
SHA1 9daca7d270273f48a57c1175cb4449551996a1e0 lib/RDF/Query/Algebra/BasicGraphPattern.pm
SHA1 02ed4d44564fe0db9863f0b624f39f8e05f315bf lib/RDF/Query/Algebra/Clear.pm
SHA1 d179d7964f0385ebc65ac541f8583659fc554e1b lib/RDF/Query/Algebra/Construct.pm
SHA1 8785a926694cb31feb9b98f29ff4aa4e79b0d349 lib/RDF/Query/Algebra/Copy.pm
SHA1 e9e12dd7f215fdd74611d5428feb5092c19a3e1b lib/RDF/Query/Algebra/Create.pm
SHA1 dffcead0fd35e4654a4dd904a278127161f42d91 lib/RDF/Query/Algebra/Distinct.pm
SHA1 f9aa54379232d8d52eb1cfb3b8143a773ed20a2e lib/RDF/Query/Algebra/Extend.pm
SHA1 83afa99024d05b9b396dd0fd609eb08085cc0dbc lib/RDF/Query/Algebra/Filter.pm
SHA1 0c2f8d1d3e814afbf525dff885477e79e301efa2 lib/RDF/Query/Algebra/GroupGraphPattern.pm
SHA1 8437645c91803b4c0e7aca8ac4293422a103435b lib/RDF/Query/Algebra/Limit.pm
SHA1 52b10e4b4b0ab3fe011f1e36918fbeb57c935fa4 lib/RDF/Query/Algebra/Load.pm
SHA1 519dc4ed8cc29578ddfa67c5ae2fafea87e7af2d lib/RDF/Query/Algebra/Minus.pm
SHA1 8b09da31b218e89a6b7aae2b9f61bcd92c7ff010 lib/RDF/Query/Algebra/Move.pm
SHA1 05491956269408ef06ba6c520b4eb84666357ad0 lib/RDF/Query/Algebra/NamedGraph.pm
SHA1 69cd3ecd6ba7a427c00bb807634001e2811654d0 lib/RDF/Query/Algebra/Offset.pm
SHA1 ef6acc95c238b0d3c1e8760b8fabe854e5adffea lib/RDF/Query/Algebra/Optional.pm
SHA1 f57cac4d488de2b11ecdbe16184893139a7290b7 lib/RDF/Query/Algebra/Path.pm
SHA1 6f8dffef3adf9e67f1da8fd408215f42dbdffec4 lib/RDF/Query/Algebra/Project.pm
SHA1 67f0cb9bf8923162f9ad59962d8ffaccda291112 lib/RDF/Query/Algebra/Quad.pm
SHA1 97e5dc53a4b9197c4473df8f905b31f3011e3e85 lib/RDF/Query/Algebra/Sequence.pm
SHA1 18c87bd0892b0b012e9b939a01e31bad49136153 lib/RDF/Query/Algebra/Service.pm
SHA1 e4298ad7a39a32f56ad7f508e6ca948fd2cde136 lib/RDF/Query/Algebra/Sort.pm
SHA1 2ca667fbf81e8f11a45d7522c70905013a9a7462 lib/RDF/Query/Algebra/SubSelect.pm
SHA1 7707a91f788b9ff27262e5ce04252adf3a37dabf lib/RDF/Query/Algebra/Table.pm
SHA1 0c90870a445162b884bd55932441ad26d87753cf lib/RDF/Query/Algebra/TimeGraph.pm
SHA1 b3a79f4155d780c7334d121af7512d86c227b363 lib/RDF/Query/Algebra/Triple.pm
SHA1 885278608965135b2a3b970bef271fe6b31b1d64 lib/RDF/Query/Algebra/Union.pm
SHA1 7a1d005f7eae0c50eb5a8d7e5f3c672d7691304b lib/RDF/Query/Algebra/Update.pm
SHA1 c62c5bb34868234f04eec7f9120ff18bc382c8a5 lib/RDF/Query/BGPOptimizer.pm
SHA1 a6be4528beb5145ba15b7ba0b3d7f269f18758ed lib/RDF/Query/Compiler/SQL.pm
SHA1 2b5c14be1b8ddae4515127bad650e817d53474b6 lib/RDF/Query/Error.pm
SHA1 2898cfe331cc5a486ce94d2874b5ed074c392748 lib/RDF/Query/ExecutionContext.pm
SHA1 45605aa2a948959f3596dd9b54a0ead0d686abfc lib/RDF/Query/Expression.pm
SHA1 eaa870618d0458f4be08a2b95015b19c3db06ccd lib/RDF/Query/Expression/Alias.pm
SHA1 f2ac2e4a800e4125c903ae7f41b6af9b274c9d87 lib/RDF/Query/Expression/Binary.pm
SHA1 0e4ee997c57fdab05732bc4b45c2ad86722f5d84 lib/RDF/Query/Expression/Function.pm
SHA1 6a814396c6125ed001d08213d6da500ebc440d75 lib/RDF/Query/Expression/Nary.pm
SHA1 1b9af322a0bce6960867e7c5a92beb4f7d44f259 lib/RDF/Query/Expression/Unary.pm
SHA1 6494031565d542a5f3fc842a13da95bf2e0e871b lib/RDF/Query/Federate.pm
SHA1 ff17e74233255bb883ae4e483046ac97b949959a lib/RDF/Query/Federate/Plan.pm
SHA1 65ed50e896a44f35b8d1d0f591f1d3d4a59a3084 lib/RDF/Query/Functions.pm
SHA1 fdfea3a0c3495c59f30bb8549a58bdb1459edff3 lib/RDF/Query/Functions/Geo.pm
SHA1 8ee3aa76b3ac99188d49d9eeeab989ae61bcbf46 lib/RDF/Query/Functions/Jena.pm
SHA1 86c7179bcc2ad90238c3eaa9091a52d6e1e9d4ef lib/RDF/Query/Functions/Kasei.pm
SHA1 b156c6eef26e68e650c54bb3070f30de1ae94281 lib/RDF/Query/Functions/SPARQL.pm
SHA1 bcd51aa870f26a4020c376c56053e8ccf611888f lib/RDF/Query/Functions/Xpath.pm
SHA1 fda38de5563f47ec4fd4be3c08649f00278ab302 lib/RDF/Query/Node.pm
SHA1 6fbf1758658968b5d3812911d740de2fbfa3c614 lib/RDF/Query/Node/Blank.pm
SHA1 ee4898b187f8166cb0cd55184979e49cbe685839 lib/RDF/Query/Node/Literal.pm
SHA1 402d746dadbc23e2a4296a5dded675d36b18480f lib/RDF/Query/Node/Resource.pm
SHA1 afe4178f08767b4b4e09b08e3b53e45b74423904 lib/RDF/Query/Node/Variable.pm
SHA1 489c5ac5e1d8b89e97662679d02c9da335611822 lib/RDF/Query/Parser.pm
SHA1 4b2c88d8f6ba5568737a9a8238cfdf04fb1b347b lib/RDF/Query/Parser/RDQL.pm
SHA1 a6a7c097c2f932534ef1897560c9abc43445295a lib/RDF/Query/Parser/SPARQL.pm
SHA1 7ce11458a99bd26896e5e113b544cd43a8c040fd lib/RDF/Query/Parser/SPARQL11.pm
SHA1 7d3a44007c50d389d8b80dcc53b45bb5f3709851 lib/RDF/Query/Plan.pm
SHA1 96dcbc3ca552d05425582e3a53149fe7d38467fb lib/RDF/Query/Plan/Aggregate.pm
SHA1 99825340df344b14f3af8471862845a0d48565db lib/RDF/Query/Plan/BasicGraphPattern.pm
SHA1 e802222c64c2fbdaccf8677b42cb93851ee5eb1c lib/RDF/Query/Plan/Clear.pm
SHA1 1a3c975bcdb095eb5822526bc134d39931197e79 lib/RDF/Query/Plan/ComputedStatement.pm
SHA1 a8bf63ee89e7070aa88d8111fffb6f0507472e55 lib/RDF/Query/Plan/Constant.pm
SHA1 5fc7645e4392baec772c67197a6e283500542ebf lib/RDF/Query/Plan/Construct.pm
SHA1 2555cf93fd06870f594bef2fc54eaa52a211fc93 lib/RDF/Query/Plan/Copy.pm
SHA1 3bcaa5e2eb715b8a3dc7f7d09dbf5a46ad1b6805 lib/RDF/Query/Plan/Distinct.pm
SHA1 78d8e6013a194dce035e84942da496c883980e0e lib/RDF/Query/Plan/Extend.pm
SHA1 b2c736d1e19a1bdc778ba2312feeb3382b31d1f2 lib/RDF/Query/Plan/Filter.pm
SHA1 c475fb3a52add6fa13732e544a4a6381fdc315e8 lib/RDF/Query/Plan/Iterator.pm
SHA1 28f2273829252d0593147d833335dd5b5be41d00 lib/RDF/Query/Plan/Join.pm
SHA1 a99e640d8e8228e21184cccbd674d79f8d576f9e lib/RDF/Query/Plan/Join/NestedLoop.pm
SHA1 38cde4126c139f4aad68bd04d01109b35b4a5ec7 lib/RDF/Query/Plan/Join/PushDownNestedLoop.pm
SHA1 175df6f62ba105d028f6196386cad4bba904e7b6 lib/RDF/Query/Plan/Limit.pm
SHA1 3489143b6be85771b63d6ff2ec73388392fef838 lib/RDF/Query/Plan/Load.pm
SHA1 6218f34f48c7c83a5001ad5cb23e8038166cf0b4 lib/RDF/Query/Plan/Minus.pm
SHA1 98c895b73d5d4229a4da4d88b72cd17c47143568 lib/RDF/Query/Plan/Move.pm
SHA1 cde9ece67ce433e83a22861c36788d73f5af0aa3 lib/RDF/Query/Plan/NamedGraph.pm
SHA1 258c0b5c286bdfd7b2dc774b9e3a6f74593adb17 lib/RDF/Query/Plan/Offset.pm
SHA1 3e9af68eda9b162d4e5edc2c0bca90d839f15ec9 lib/RDF/Query/Plan/Path.pm
SHA1 ec50633a371712950cf4699a9d0a341b0a066d1e lib/RDF/Query/Plan/Project.pm
SHA1 73635c02a338bc08b362c3ef266b12de648f2160 lib/RDF/Query/Plan/Quad.pm
SHA1 534e2f85e17def2cc1e4eed1f848ae1513eb14e8 lib/RDF/Query/Plan/Sequence.pm
SHA1 d345fc0b92c5df1b8dcc91441b0589ff363a9d43 lib/RDF/Query/Plan/Service.pm
SHA1 72245b8b0da63998c17772032b901c57e3dee864 lib/RDF/Query/Plan/Sort.pm
SHA1 cea448bd8b7b161378f4953d6fdbb565322794d3 lib/RDF/Query/Plan/SubSelect.pm
SHA1 e1e5d5398baf6f8615771d68590275d1a8974b29 lib/RDF/Query/Plan/ThresholdUnion.pm
SHA1 aa82498fa0aa57d65e858dc195e7b5bf4181dfe8 lib/RDF/Query/Plan/Triple.pm
SHA1 005de14469ceab73ed0ed91ab0effd9c45046c69 lib/RDF/Query/Plan/Union.pm
SHA1 36d3b091ed865f086a9a77cd60302f3ff48b144d lib/RDF/Query/Plan/Update.pm
SHA1 015305d81e02d90c2b006cdc39efc3961d14f24a lib/RDF/Query/ServiceDescription.pm
SHA1 baae47f867e1ed3902b73eeea1e2a65b8a5f6d7b lib/RDF/Query/Temporal.pm
SHA1 8f5057f2b657eb4d8cc85d5a671650e3cfd1faae lib/RDF/Query/Util.pm
SHA1 682cd0874519ef69ccf7cfbc3d77cef389045266 lib/RDF/Query/VariableBindings.pm
SHA1 65eebc7db7d9900210d8b1cce4be766220f0655c t/00-simple.t
SHA1 cb9cad8ce5c7aceebaf153300eeecabe72ba0258 t/01-coverage.t
SHA1 6a3eafe9357a8d1eba5356a44b093a0029f147e8 t/algebra-bgp.t
SHA1 8cd5fd8ae8cec625634367ac36f92c57c6647239 t/algebra-expr.t
SHA1 6f576b1a97db8fee5c7ad3b982e56a26c77fd09f t/algebra-func.t
SHA1 10ef1c50a64532966f23f2356b6bb64e41e424a2 t/algebra-subsumption.t
SHA1 8fbffe81b3f765e772eb69597a0a239479008848 t/algebra.t
SHA1 65a27402e451761cfea8feedc9de8d83b565473f t/constraints.t
SHA1 b7e891b6c80efd76308e51f3d192837b46a57759 t/dataset-from-file.t
SHA1 040afbec763307704e9eb4016f705a5c881c1b9a t/dataset-from-net.t
SHA1 b9ad94240446d26783996a83961fd33e406b1ebd t/dev-computed-statements.t
SHA1 bcca0b7492c687cc4876b098abf810d9f03cfc86 t/distance.js
SHA1 312660b4f1f631b1fbe4a9602c406b20d7d17ced t/ext-select-expr.t
SHA1 410da1d8056eccb53d4f08c6d0500d63b53a9077 t/filters.t
SHA1 e1fccc14061a0f6dfca9e6ac833abaf1d2fe03b6 t/functions.rdf
SHA1 66d9957f87625acd92b4d7e5655a786a44013741 t/functions.t
SHA1 95852b4de6891ceda995cad0c1fde9b806055556 t/hooks.t
SHA1 3940f77caa65b04e872023200ae3124a59e11c31 t/iterators.t
SHA1 f0a2d411920e5623a8607a619da7d2def58f8143 t/literals.t
SHA1 1164131e4531bf45c704472128481553d54984cf t/models.pl
SHA1 c3600a3af76145d3cab42dc7550585dd2e6fa672 t/named-graphs.t
SHA1 a62ed3dd4c5221f211aa1eae8e7ab8695bd74eea t/optional.t
SHA1 66ff2242cccb612fc40f9820fedaa70953ae4213 t/plan.t
SHA1 04f1c1bee08121851489782b6c176d6144944a8d t/protocol-serialization.t
SHA1 a1abcf0dffa455e066d76927bec2a24327561bb0 t/queryform-ask.t
SHA1 b681cd6e217d4f2c030785d5317b7119e83d134c t/queryform-construct.t
SHA1 50eedc10193be8cbdc96d803873488bd6f48f582 t/queryform-describe.t
SHA1 f2f31091fe775d52dc114ddacb2441e13be71e30 t/rdql.t
SHA1 6479abb15e17ace342c43b9148b36c6dcbb4f9e4 t/resultforms.t
SHA1 60fa324cc291e8fb61e41d75ec9a88f9f7057db3 t/serialize.t
SHA1 03182a941d101a6708aee8e9a9d98e12c265eb75 t/sha1.js
SHA1 0a85e863f2e60959cb0060e6ac45f36b191f6ff9 t/sha1.js.asc
SHA1 7b8b0601f4dfc117d824656e4bc4263dee5e9324 t/sparql11-aggregates.t
SHA1 65c5b2ad32dd8c478d406ada8c122c4422ed1197 t/sparql11-federation.t
SHA1 11788ae786b60eb7dfa1b4aba5f52c69a701e6a3 t/sparql11-negation.t
SHA1 b3560bbea8467d790a70a0850a5d05ce5898e2d7 t/sparql11-propery_paths.t
SHA1 564f67b96c442baf944da3b0b2ae0be84e5c54d9 t/sparql11-select_expressions.t
SHA1 da7835801518d79e2be0023e241ab99b792d8aea t/sparql11-subselect.t
SHA1 c81750cd3555e90da5dee62971aadea0e83209c0 t/sparql11-update.t
SHA1 788c5516471d2b22854c1dfd7e96d3681526ad75 t/streams.t.deprecated
SHA1 8ba2ac8311aa6278a86ba2de30c2bf105c52af1a t/syntactic_forms.t
SHA1 895d6dcdd3270c9372069c65c80bdff91efcf879 t/union.t
SHA1 028d63372b420f7c6ffe156e81943c47f7352c9d xt/dawg-eval10.t
SHA1 54f4ea90f326e33a2908fa0981f4e87c38b08d55 xt/dawg-eval11.t
SHA1 175cc2ffa66db8400f925098df55dc38b3414c33 xt/dawg-syntax11.t
SHA1 cfe31629a09d9b7ed71c90358ce82f66bc810e48 xt/dev-service-description.t
SHA1 ff2f67299987aebce699ebf5564d8fbc9a7c201d xt/dev-sql-compiler.t
SHA1 df389f9e1fcc1da24fc912eb80c412b4b961a70b xt/dev-time-intervals.t
SHA1 fbbc085d6460de229abde98f8c475fb8abce02bb xt/federate.t
SHA1 15279bfcd192ebc5c9d663bcfd7f87a4d9561e77 xt/parser-rdql.t
SHA1 31e9070b5117a7e17562836fe920e11ca1383c89 xt/parser-sparql.t
SHA1 6ff83a80c14cf6744115756c927d5bc406babafc xt/parser-sparql11.t
SHA1 6387af7a5fde0747be5bc9ad2ec15ca9759bd95a xt/pod.t
SHA1 9115f7ffe1933ad736dc292f3c89595b36ed6aa2 xt/pod_coverage.t
SHA1 166f5c3ed8090d6e81dec60c4887a85aabd38e27 xt/sparql11-federation.t
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: GPGTools - http://gpgtools.org
iEYEARECAAYFAlhtL+YACgkQhPK6VMqoyC1/rACcCcKS1s+Rs9pHruMDExoJVgoI
lh8AoISClmHw311Rinhbf3fx97/YErr5
=1Dx5
-----END PGP SIGNATURE-----
RDF-Query-2.918/t/ 000755 000765 000024 00000000000 13033227743 013611 5 ustar 00greg staff 000000 000000 RDF-Query-2.918/xt/ 000755 000765 000024 00000000000 13033227743 014001 5 ustar 00greg staff 000000 000000 RDF-Query-2.918/xt/dawg-eval10.t 000755 000765 000024 00000066007 13033227174 016210 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use Encode qw(encode);
use URI::file;
use Test::More;
use File::Temp qw(tempfile);
use Scalar::Util qw(blessed reftype);
use Storable qw(dclone);
use Algorithm::Combinatorics qw(permutations);
use LWP::MediaTypes qw(add_type);
use Text::CSV_XS;
use Regexp::Common qw /URI/;
add_type( 'application/rdf+xml' => qw(rdf xrdf rdfx) );
add_type( 'text/turtle' => qw(ttl) );
add_type( 'text/plain' => qw(nt) );
add_type( 'text/x-nquads' => qw(nq) );
add_type( 'text/json' => qw(json) );
add_type( 'text/html' => qw(html xhtml htm) );
use RDF::Query;
use RDF::Query::Node qw(iri blank literal variable);
use RDF::Trine qw(statement);
use RDF::Trine::Error qw(:try);
use RDF::Trine::Graph;
use RDF::Trine::Namespace qw(rdf rdfs xsd);
use RDF::Trine::Iterator qw(smap);
use RDF::Endpoint 0.05;
use Carp;
use HTTP::Request;
use HTTP::Response;
use HTTP::Message::PSGI;
$RDF::Query::Plan::PLAN_CLASSES{'service'} = 'Test::RDF::Query::Plan::Service';
################################################################################
# Log::Log4perl::init( \q[
# log4perl.category.rdf.query.plan.service = TRACE, Screen
# # log4perl.category.rdf.query.plan.join.pushdownnestedloop = TRACE, Screen
# log4perl.appender.Screen = Log::Log4perl::Appender::Screen
# log4perl.appender.Screen.stderr = 0
# log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
# ] );
################################################################################
our $debug = 0;
our $STRICT_APPROVAL = 0;
if ($] < 5.007003) {
plan skip_all => 'perl >= 5.7.3 required';
exit;
}
use Data::Dumper;
require XML::Simple;
plan qw(no_plan);
require "xt/dawg/earl.pl";
my $PATTERN = '';
my %args;
while (defined(my $opt = shift)) {
if ($opt eq '-v') {
$debug++;
} elsif ($opt =~ /^-(.*)$/) {
$args{ $1 } = 1;
} else {
$PATTERN = $opt;
}
}
$ENV{RDFQUERY_THROW_ON_SERVICE} = 1;
no warnings 'once';
if ($PATTERN) {
# $debug = 1;
}
warn "PATTERN: ${PATTERN}\n" if ($PATTERN and $debug);
my $model = RDF::Trine::Model->temporary_model;
my @manifests = map { $_->as_string } map { URI::file->new_abs( $_ ) } map { glob( "xt/dawg/data-r2/$_/manifest.ttl" ) }
qw(
algebra
ask
basic
bnode-coreference
bound
cast
construct
dataset
distinct
expr-builtin
expr-equals
expr-ops
graph
i18n
open-world
optional
optional-filter
reduced
regex
solution-seq
sort
triple-match
type-promotion
);
foreach my $file (@manifests) {
warn "Parsing manifest $file\n" if $debug;
RDF::Trine::Parser->parse_url_into_model( $file, $model, canonicalize => 1 );
}
warn "done parsing manifests" if $debug;
my $earl = init_earl( $model );
my $rs = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/result-set#');
my $mf = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#');
my $ut = RDF::Trine::Namespace->new('http://www.w3.org/2009/sparql/tests/test-update#');
my $rq = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-query#');
my $dawgt = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#');
{
my @manifests = $model->subjects( $rdf->type, $mf->Manifest );
foreach my $m (@manifests) {
warn "Manifest: " . $m->as_string . "\n" if ($debug);
my ($list) = $model->objects( $m, $mf->entries );
unless (blessed($list)) {
warn "No mf:entries found for manifest " . $m->as_string . "\n";
}
my @tests = $model->get_list( $list );
foreach my $test (@tests) {
my $et = $model->count_statements($test, $rdf->type, $mf->QueryEvaluationTest);
my $ct = $model->count_statements($test, $rdf->type, $mf->CSVResultFormatTest);
if ($et + $ct) {
my ($name) = $model->objects( $test, $mf->name );
unless ($test->uri_value =~ /$PATTERN/) {
next;
}
warn "### query eval test: " . $test->as_string . " >>> " . $name->literal_value . "\n" if ($debug);
query_eval_test( $model, $test, $earl );
}
if ($model->count_statements($test, $rdf->type, $ut->UpdateEvaluationTest) or $model->count_statements($test, $rdf->type, $mf->UpdateEvaluationTest)) {
my ($name) = $model->objects( $test, $mf->name );
unless ($test->uri_value =~ /$PATTERN/) {
next;
}
warn "### update eval test: " . $test->as_string . " >>> " . $name->literal_value . "\n" if ($debug);
update_eval_test( $model, $test, $earl );
}
}
}
}
open( my $fh, '>', 'earl-eval-10.ttl' ) or die $!;
print {$fh} earl_output( $earl );
close($fh);
################################################################################
sub update_eval_test {
my $model = shift;
my $test = shift;
my $earl = shift;
my ($action) = $model->objects( $test, $mf->action );
my ($result) = $model->objects( $test, $mf->result );
my ($req) = $model->objects( $test, $mf->requires );
my ($approved) = $model->objects( $test, $dawgt->approval );
my ($queryd) = $model->objects( $action, $ut->request );
my ($data) = $model->objects( $action, $ut->data );
my @gdata = $model->objects( $action, $ut->graphData );
if ($STRICT_APPROVAL) {
unless ($approved) {
warn "- skipping test because it isn't approved\n" if ($debug);
return;
}
if ($approved->equal( $dawgt->NotClassified)) {
warn "- skipping test because its approval is dawgt:NotClassified\n" if ($debug);
return;
}
}
my $uri = URI->new( $queryd->uri_value );
my $filename = $uri->file;
my (undef,$base,undef) = File::Spec->splitpath( $filename );
$base = "file://${base}";
warn "Loading SPARQL query from file $filename" if ($debug);
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename) or do { fail("$!: $filename; " . $test->as_string); return }; binmode($fh, ':utf8'); <$fh> };
my $q = $sparql;
$q =~ s/\s+/ /g;
if ($debug) {
warn "### test : " . $test->as_string . "\n";
warn "# sparql : $q\n";
warn "# data : " . $data->as_string . "\n" if (blessed($data));
warn "# graph data : " . $_->as_string . "\n" for (@gdata);
warn "# result : " . $result->as_string . "\n";
warn "# requires : " . $req->as_string . "\n" if (blessed($req));
}
print STDERR "constructing model... " if ($debug);
my ($test_model) = RDF::Trine::Model->temporary_model;
try {
if (blessed($data)) {
add_to_model( $test_model, $data->uri_value );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
} except {
my $e = shift;
die $e->text;
} otherwise {
warn '*** failed to construct model';
};
foreach my $gdata (@gdata) {
my ($data) = ($model->objects( $gdata, $ut->data ))[0] || ($model->objects( $gdata, $ut->graph ))[0];
my ($graph) = $model->objects( $gdata, $rdfs->label );
my $uri = $graph->literal_value;
try {
warn "test data file: " . $data->uri_value . "\n" if ($debug);
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $test_model, context => RDF::Trine::Node::Resource->new($uri), canonicalize => 1 );
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
};
}
my ($result_status) = $model->objects( $result, $ut->result );
my @resgdata = $model->objects( $result, $ut->graphData );
my $expected_model = RDF::Trine::Model->temporary_model;
my ($resdata) = $model->objects( $result, $ut->data );
try {
if (blessed($resdata)) {
RDF::Trine::Parser->parse_url_into_model( $resdata->uri_value, $expected_model, canonicalize => 1 );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
};
foreach my $gdata (@resgdata) {
my ($data) = ($model->objects( $gdata, $ut->data ))[0] || ($model->objects( $gdata, $ut->graph ))[0];
my ($graph) = $model->objects( $gdata, $rdfs->label );
my $uri = $graph->literal_value;
my $return = 0;
if ($data) {
try {
warn "expected result data file: " . $data->uri_value . "\n" if ($debug);
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $expected_model, context => RDF::Trine::Node::Resource->new($uri), canonicalize => 1 );
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
$return = 1;
};
return if ($return);
}
}
if ($debug) {
warn "Dataset before update operation:\n";
warn $test_model->as_string;
}
my $ok = 0;
eval {
my $query = RDF::Query->new( $sparql, { lang => 'sparql11', update => 1, canonicalize => 1 } );
unless ($query) {
warn 'Query error: ' . RDF::Query->error;
fail($test->as_string);
return;
}
my ($plan, $ctx) = $query->prepare( $test_model );
$query->execute_plan( $plan, $ctx );
my $test_graph = RDF::Trine::Graph->new( $test_model );
my $expected_graph = RDF::Trine::Graph->new( $expected_model );
my $eq = $test_graph->equals( $expected_graph );
$ok = is( $eq, 1, $test->as_string );
unless ($ok) {
warn $test_graph->error;
warn "Got model:\n" . $test_model->as_string;
warn "Expected model:\n" . $expected_model->as_string;
}
};
if ($@ or not($ok)) {
if ($@) {
fail($test->as_string);
}
earl_fail_test( $earl, $test, $@ );
print "# failed: " . $test->as_string . "\n";
} else {
earl_pass_test( $earl, $test );
}
print STDERR "ok\n" if ($debug);
}
sub query_eval_test {
my $model = shift;
my $test = shift;
my $earl = shift;
my ($action) = $model->objects( $test, $mf->action );
my ($result) = $model->objects( $test, $mf->result );
my ($req) = $model->objects( $test, $mf->requires );
my ($approved) = $model->objects( $test, $dawgt->approval );
my ($queryd) = $model->objects( $action, $rq->query );
my ($data) = $model->objects( $action, $rq->data );
my @gdata = $model->objects( $action, $rq->graphData );
my @sdata = $model->objects( $action, $rq->serviceData );
if ($STRICT_APPROVAL) {
unless ($approved) {
warn "- skipping test because it isn't approved\n" if ($debug);
return;
}
if ($approved->equal($dawgt->NotClassified)) {
warn "- skipping test because its approval is dawgt:NotClassified\n" if ($debug);
return;
}
}
my $uri = URI->new( $queryd->uri_value );
my $filename = $uri->file;
my (undef,$base,undef) = File::Spec->splitpath( $filename );
$base = "file://${base}";
warn "Loading SPARQL query from file $filename" if ($debug);
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename) or do { warn("$!: $filename; " . $test->as_string); return }; binmode($fh, ':utf8'); <$fh> };
my $q = $sparql;
$q =~ s/\s+/ /g;
if ($debug) {
warn "### test : " . $test->as_string . "\n";
warn "# sparql : $q\n";
warn "# data : " . $data->as_string if (blessed($data));
warn "# graph data : " . $_->as_string for (@gdata);
warn "# result : " . $result->as_string;
warn "# requires : " . $req->as_string if (blessed($req));
}
# warn 'service data: ' . Dumper(\@sdata);
foreach my $sd (@sdata) {
my ($url) = $model->objects( $sd, $rq->endpoint );
print STDERR "setting up remote endpoint $url...\n" if ($debug);
my ($data) = $model->objects( $sd, $rq->data );
my @gdata = $model->objects( $sd, $rq->graphData );
if ($debug) {
warn "- data : " . $data->as_string if (blessed($data));
warn "- graph data : " . $_->as_string for (@gdata);
}
my $model = RDF::Trine::Model->new();
if ($data) {
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $model );
}
$Test::RDF::Query::Plan::Service::service_ctx{ $url->uri_value } = $model;
}
print STDERR "constructing model... " if ($debug);
my ($test_model) = RDF::Trine::Model->temporary_model;
try {
if (blessed($data)) {
add_to_model( $test_model, $data->uri_value );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
} except {
my $e = shift;
die $e->text;
} otherwise {
warn '*** failed to construct model';
};
print STDERR "ok\n" if ($debug);
my $resuri = URI->new( $result->uri_value );
my $resfilename = $resuri->file;
TODO: {
local($TODO) = (blessed($req)) ? "requires " . $req->as_string : '';
my $comment;
my $ok = eval {
if ($debug) {
my $q = $sparql;
$q =~ s/([\x{256}-\x{1000}])/'\x{' . sprintf('%x', ord($1)) . '}'/eg;
warn $q;
}
print STDERR "getting actual results... " if ($debug);
my ($actual, $type) = get_actual_results( $test_model, $sparql, $base, @gdata );
print STDERR "ok\n" if ($debug);
print STDERR "getting expected results... " if ($debug);
my $expected = get_expected_results( $resfilename, $type );
print STDERR "ok\n" if ($debug);
# warn "comparing results...";
compare_results( $expected, $actual, $earl, $test->as_string, \$comment );
};
warn $@ if ($@);
if ($ok) {
earl_pass_test( $earl, $test );
} else {
earl_fail_test( $earl, $test, $comment );
print "# failed: " . $test->as_string . "\n";
}
}
}
exit;
######################################################################
sub add_to_model {
my $model = shift;
my @files = @_;
foreach my $file (@files) {
try {
RDF::Trine::Parser->parse_url_into_model( $file, $model, canonicalize => 1 );
} catch Error with {
my $e = shift;
warn "Failed to load $file into model: " . $e->text;
};
}
}
sub get_actual_results {
my $model = shift;
my $sparql = shift;
my $base = shift;
my @gdata = @_;
my $query = RDF::Query->new( $sparql, { base => $base, lang => 'sparql10', load_data => 1, canonicalize => 1 } );
unless ($query) {
warn RDF::Query->error if ($debug or $PATTERN);
return;
}
my $testns = RDF::Trine::Namespace->new('http://example.com/test-results#');
my $rmodel = RDF::Trine::Model->temporary_model;
my ($plan, $ctx) = $query->prepare_with_named_graphs( $model, @gdata );
if ($args{plan}) {
warn $plan->explain(' ', 0);
}
my $results = $query->execute_plan( $plan, $ctx );
if ($args{ results }) {
$results = $results->materialize;
warn "Actual results:\n";
warn $results->as_string;
}
if ($results->is_bindings) {
return (binding_results_data( $results ), 'bindings');
} elsif ($results->is_boolean) {
$rmodel->add_statement( statement( $testns->result, $testns->boolean, literal(($results->get_boolean ? 'true' : 'false'), undef, $xsd->boolean) ) );
return ($rmodel->get_statements, 'boolean');
} elsif ($results->is_graph) {
return ($results, 'graph');
} else {
warn "unknown result type: " . Dumper($results);
}
}
sub get_expected_results {
my $file = shift;
my $type = shift;
my $testns = RDF::Trine::Namespace->new('http://example.com/test-results#');
if ($type eq 'graph') {
my $model = RDF::Trine::Model->temporary_model;
RDF::Trine::Parser->parse_url_into_model( "file://$file", $model, canonicalize => 1 );
my $results = $model->get_statements();
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return $results;
} elsif ($file =~ /[.](srj|json)/) {
my $model = RDF::Trine::Model->temporary_model;
my $data = do { local($/) = undef; open(my $fh, '<', $file) or die $!; binmode($fh, ':utf8'); <$fh> };
my $results = RDF::Trine::Iterator->from_json( $data, { canonicalize => 1 } );
if ($results->isa('RDF::Trine::Iterator::Boolean')) {
my $value = $results->next;
my $bool = ($value ? 'true' : 'false');
$model->add_statement( statement( $testns->result, $testns->boolean, literal($bool, undef, $xsd->boolean) ) );
if ($args{ results }) {
warn "Expected result: $bool\n";
}
return $model->get_statements;
} else {
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return binding_results_data( $results );
}
} elsif ($file =~ /[.]srx/) {
my $model = RDF::Trine::Model->temporary_model;
my $data = do { local($/) = undef; open(my $fh, '<', $file) or die $!; binmode($fh, ':utf8'); <$fh> };
my $results = RDF::Trine::Iterator->from_string( $data, { canonicalize => 1 } );
if ($results->isa('RDF::Trine::Iterator::Boolean')) {
$model->add_statement( statement( $testns->result, $testns->boolean, literal(($results->next ? 'true' : 'false'), undef, $xsd->boolean) ) );
return $model->get_statements;
} else {
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return binding_results_data( $results );
}
} elsif ($file =~ /[.]csv/) {
my $csv = Text::CSV_XS->new({binary => 1});
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $header = $csv->getline($fh);
my @vars = @$header;
my @data;
while (my $row = $csv->getline($fh)) {
my %result;
foreach my $i (0 .. $#vars) {
my $var = $vars[$i];
my $value = $row->[ $i ];
# XXX @@ heuristics that won't always work.
# XXX @@ expected to work on the test suite, though
if ($value =~ /^_:(\w+)$/) {
$value = blank($1);
} elsif ($value =~ /$RE{URI}/) {
$value = iri($value);
} elsif (defined($value) and length($value)) {
$value = literal($value);
}
$result{ $var } = $value;
}
push(@data, \%result);
}
if ($args{ results }) {
warn "Expected results:\n";
warn Dumper(\@data);
}
return \@data;
} elsif ($file =~ /[.]tsv/) {
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $header = <$fh>;
chomp($header);
my @vars = split("\t", $header);
foreach (@vars) { s/[?]// }
my @data;
my $parser = RDF::Trine::Parser::Turtle->new();
while (defined(my $line = <$fh>)) {
chomp($line);
my $row = [ split("\t", $line) ];
my %result;
foreach my $i (0 .. $#vars) {
my $var = $vars[$i];
my $value = $row->[ $i ];
my $node = length($value) ? $parser->parse_node( $value ) : undef;
$result{ $var } = $node;
}
push(@data, RDF::Query::VariableBindings->new( \%result ));
}
my $iter = RDF::Trine::Iterator::Bindings->new(\@data);
return binding_results_data($iter);
} elsif ($file =~ /[.](ttl|rdf)/) {
my $model = RDF::Trine::Model->new();
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $base = 'file://' . File::Spec->rel2abs($file);
my $parser = RDF::Trine::Parser->new(($file =~ /[.]ttl/) ? 'turtle' : 'rdfxml');
$parser->parse_file_into_model( $base, $file, $model );
my ($res) = $model->subjects( $rdf->type, $rs->ResultSet );
if (my($b) = $model->objects( $res, $rs->boolean )) {
my $bool = $b->literal_value;
my $rmodel = RDF::Trine::Model->new();
$rmodel->add_statement( statement( $testns->result, $testns->boolean, literal($bool, undef, $xsd->boolean) ) );
if ($args{ results }) {
warn "Expected result: $bool\n";
}
return $rmodel->get_statements;
} else {
my @vars = $model->objects( $res, $rs->resultVariable );
my @sols = $model->objects( $res, $rs->solution );
my @names = map { $_->literal_value } @vars;
my @bindings;
foreach my $r (@sols) {
my %data;
my @b = $model->objects( $r, $rs->binding );
foreach my $b (@b) {
my ($value) = $model->objects( $b, $rs->value );
my ($var) = $model->objects( $b, $rs->variable );
$data{ $var->literal_value } = $value;
}
push(@bindings, RDF::Trine::VariableBindings->new( \%data ));
}
my $iter = RDF::Trine::Iterator::Bindings->new( \@bindings, \@names );
if ($args{ results }) {
$iter = $iter->materialize;
warn "Got expected results:\n";
warn $iter->as_string;
}
return binding_results_data($iter);
}
} else {
die "Unrecognized type of expected results: $file";
}
}
sub compare_results {
my $expected = shift;
my $actual = shift;
my $earl = shift;
my $test = shift;
my $comment = shift || do { my $foo; \$foo };
my $TODO = shift;
my $lossy_cmp = 0;
if (reftype($expected) eq 'ARRAY') {
# comparison with expected results coming from a lossy format like csv/tsv
$lossy_cmp = 1;
my %data = (results => [], blank_identifiers => {});
foreach my $row (@$expected) {
push(@{ $data{ results } }, $row );
foreach my $key (keys %$row) {
my $node = $row->{$key};
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
$data{ blank_identifiers }{ $node->blank_identifier }++;
}
}
}
$data{ blanks } = scalar(@{ [ keys %{ $data{ blank_identifiers } } ] });
$expected = \%data;
}
if (not(ref($actual))) {
my $ok = is( $actual, $expected, $test );
return $ok;
} elsif (blessed($actual) and $actual->isa('RDF::Trine::Iterator::Graph')) {
die "Unexpected Graph result type (was expecting " . ref($expected) . ")" unless (blessed($expected) and $expected->isa('RDF::Trine::Iterator::Graph'));
my $act_graph = RDF::Trine::Graph->new( $actual );
my $exp_graph = RDF::Trine::Graph->new( $expected );
# local($debug) = 1 if ($PATTERN);
if ($debug) {
warn ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
my $actualxml = $act_graph->get_statements->as_string;
warn $actualxml;
warn "-------------------------------\n";
my $expectxml = $exp_graph->get_statements->as_string;
warn $expectxml;
warn "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n";
}
my $eq = $act_graph->equals( $exp_graph );
unless ($eq) {
warn $act_graph->error;
}
return is( $eq, 1, $test );
} elsif (reftype($actual) eq 'HASH' and reftype($expected) eq 'HASH') {
my @aresults = @{ $actual->{ results } };
my @eresults = @{ $expected->{ results } };
my $acount = scalar(@aresults);
my $ecount = scalar(@eresults);
if ($acount != $ecount) {
warn "Result count ($acount) didn't match expected ($ecount)" if ($debug);
return fail($test);
}
# warn Data::Dumper->Dump([\@aresults, \@eresults], [qw(actual expected)]);
my ($awith, $awithout) = split_results_with_blank_nodes( @aresults );
my ($ewith, $ewithout) = split_results_with_blank_nodes( @eresults );
# for the results without blanks, just serialize, sort, and compare
my @astrings = sort map { result_to_string($_, $lossy_cmp) } @$awithout;
my @estrings = sort map { result_to_string($_, $lossy_cmp) } @$ewithout;
if ($actual->{ blanks } == 0 and $expected->{ blanks } == 0) {
return is_deeply( \@astrings, \@estrings, $test );
} elsif (join("\xFF", @astrings) ne join("\xFF", @estrings)) {
warn "triples don't match: " . Dumper(\@astrings, \@estrings);
return fail($test);
}
# compare the results with bnodes
my @ka = keys %{ $actual->{blank_identifiers} };
my @kb = keys %{ $expected->{blank_identifiers} };
my $kbp = permutations( \@kb );
MAPPING: while (my $mapping = $kbp->next) {
my %mapping;
@mapping{ @ka } = @$mapping;
warn "trying mapping: " . Dumper(\%mapping) if ($debug);
my %ewith = map { result_to_string($_, $lossy_cmp) => 1 } @$ewith;
foreach my $row (@$awith) {
my %row;
foreach my $k (keys %$row) {
my $n = $row->{ $k };
next unless (blessed($n));
if ($n->isa('RDF::Trine::Node::Blank')) {
my $id = $mapping{ $n->blank_identifier };
warn "mapping " . $n->blank_identifier . " to $id\n" if ($debug);
$row{ $k } = RDF::Trine::Node::Blank->new( $id );
} else {
$row{ $k } = $n;
}
}
my $mapped_row = result_to_string( RDF::Query::VariableBindings->new( \%row ), $lossy_cmp );
warn "checking for '$mapped_row' in " . Dumper(\%ewith) if ($debug);
if ($ewith{ $mapped_row }) {
delete $ewith{ $mapped_row };
} else {
next MAPPING;
}
}
warn "found mapping: " . Dumper(\%mapping) if ($debug);
return pass($test);
}
warn "failed to find bnode mapping: " . Dumper($awith, $ewith);
return fail($test);
} else {
die "Failed to compare actual and expected results: " . Dumper($actual, $expected);
}
}
sub binding_results_data {
my $iter = shift;
my %data = (results => [], blank_identifiers => {});
while (my $row = $iter->next) {
push(@{ $data{ results } }, $row );
foreach my $key (keys %$row) {
my $node = $row->{$key};
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
$data{ blank_identifiers }{ $node->blank_identifier }++;
}
}
}
$data{ blanks } = scalar(@{ [ keys %{ $data{ blank_identifiers } } ] });
return \%data;
}
sub split_results_with_blank_nodes {
my (@with, @without);
ROW: foreach my $row (@_) {
my @keys = grep { ref($row->{ $_ }) } keys %$row;
foreach my $k (@keys) {
my $node = $row->{ $k };
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
push(@with, $row);
next ROW;
}
}
push(@without, $row);
}
return (\@with, \@without);
}
sub result_to_string {
my $row = shift;
my $lossy_cmp = shift;
my @keys = grep { ref($row->{ $_ }) } keys %$row;
my @results;
foreach my $k (@keys) {
my $node = $row->{ $k };
if ($node->isa('RDF::Trine::Node::Literal') and $node->has_datatype) {
my ($value, $dt);
if ($lossy_cmp) {
$value = $node->literal_value;
$dt = undef;
} else {
$value = RDF::Trine::Node::Literal->canonicalize_literal_value( $node->literal_value, $node->literal_datatype );
$dt = $node->literal_datatype;
}
$node = RDF::Query::Node::Literal->new( $value, undef, $dt );
}
push(@results, join('=', $k, $node->as_string));
}
return join(',', sort(@results));
}
package Test::RDF::Query::Plan::Service;
use strict;
use warnings;
use Data::Dumper;
use Scalar::Util qw(refaddr);
use base qw(RDF::Query::Plan::Service);
our %ENDPOINTS;
our %service_ctx;
sub new {
my $class = shift;
my $endpoint = shift;
my $plan = shift;
my $silent = shift;
my $sparql = shift;
if ($endpoint->isa('RDF::Query::Node::Resource')) {
my $uri = $endpoint->uri_value;
warn "setting up mock endpoint for $uri" if ($debug);
}
my $self = $class->SUPER::new( $endpoint, $plan, $silent, $sparql, @_ );
if ($endpoint->isa('RDF::Query::Node::Resource')) {
my $uri = $endpoint->uri_value;
my $e = URI->new($uri);
my $model = $service_ctx{ $uri };
# warn "model for $uri: $model";
if ($model) {
my $end = RDF::Endpoint->new( $model, { endpoint => { endpoint_path => $e->path } } );
$ENDPOINTS{ refaddr($self) } = $end;
}
}
return $self;
}
# sub mock {
# my $self = shift;
# return;
# my $endpoint = shift;
# my $data = shift;
# my $e = URI->new($endpoint);
#
# my $model = RDF::Trine::Model->new();
# my ($default, $named) = @$data;
# if ($default) {
# RDF::Trine::Parser->parse_url_into_model( $default->uri_value, $model );
# my $end = RDF::Endpoint->new( $model, { endpoint => { endpoint_path => $e->path } } );
# $ENDPOINTS{ refaddr($self) } = $end;
# }
# }
sub _request {
my $self = shift;
my $ua = shift;
my $req = shift;
my $env = $req->to_psgi;
my $end = $ENDPOINTS{ refaddr($self) };
if ($end) {
# warn "got mocked endpoint";
my $app = sub {
my $env = shift;
my $req = Plack::Request->new($env);
my $resp = $end->run( $req );
return $resp->finalize;
};
my $data = $app->( $env );
my $resp = HTTP::Response->from_psgi( $data );
return $resp;
} else {
# warn "no mocked endpoint available";
return HTTP::Response->new(403);
}
}
sub DESTROY {
my $self = shift;
delete $ENDPOINTS{ refaddr($self) };
$self->SUPER::DESTROY();
}
RDF-Query-2.918/xt/dawg-eval11.t 000755 000765 000024 00000065760 13033227174 016216 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use Encode qw(encode);
use URI::file;
use Test::More;
use File::Temp qw(tempfile);
use Scalar::Util qw(blessed reftype);
use Storable qw(dclone);
use Algorithm::Combinatorics qw(permutations);
use LWP::MediaTypes qw(add_type);
use Text::CSV_XS;
use Regexp::Common qw /URI/;
add_type( 'application/rdf+xml' => qw(rdf xrdf rdfx) );
add_type( 'text/turtle' => qw(ttl) );
add_type( 'text/plain' => qw(nt) );
add_type( 'text/x-nquads' => qw(nq) );
add_type( 'text/json' => qw(json) );
add_type( 'text/html' => qw(html xhtml htm) );
use RDF::Query;
use RDF::Query::Node qw(iri blank literal variable);
use RDF::Trine qw(statement);
use RDF::Trine::Error qw(:try);
use RDF::Trine::Graph;
use RDF::Trine::Namespace qw(rdf rdfs xsd);
use RDF::Trine::Iterator qw(smap);
use RDF::Endpoint 0.05;
use Carp;
use HTTP::Request;
use HTTP::Response;
use HTTP::Message::PSGI;
$RDF::Query::Plan::PLAN_CLASSES{'service'} = 'Test::RDF::Query::Plan::Service';
################################################################################
# Log::Log4perl::init( \q[
# log4perl.category.rdf.query.plan.service = TRACE, Screen
# # log4perl.category.rdf.query.plan.join.pushdownnestedloop = TRACE, Screen
# log4perl.appender.Screen = Log::Log4perl::Appender::Screen
# log4perl.appender.Screen.stderr = 0
# log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
# ] );
################################################################################
our $debug = 0;
our $STRICT_APPROVAL = 0;
if ($] < 5.007003) {
plan skip_all => 'perl >= 5.7.3 required';
exit;
}
use Data::Dumper;
require XML::Simple;
plan qw(no_plan);
require "xt/dawg/earl.pl";
my $PATTERN = '';
my %args;
while (defined(my $opt = shift)) {
if ($opt eq '-v') {
$debug++;
} elsif ($opt =~ /^-(.*)$/) {
$args{ $1 } = 1;
} else {
$PATTERN = $opt;
}
}
$ENV{RDFQUERY_THROW_ON_SERVICE} = 1;
no warnings 'once';
if ($PATTERN) {
# $debug = 1;
}
warn "PATTERN: ${PATTERN}\n" if ($PATTERN and $debug);
my $model = RDF::Trine::Model->temporary_model;
my @manifests = map { $_->as_string } map { URI::file->new_abs( $_ ) } map { glob( "xt/dawg11/$_/manifest.ttl" ) }
qw(
add
aggregates
basic-update
bind
bindings
clear
construct
copy
csv-tsv-res
delete
delete-data
delete-insert
delete-where
drop
exists
functions
grouping
json-res
move
negation
project-expression
property-path
service
subquery
update-silent
);
foreach my $file (@manifests) {
warn "Parsing manifest $file\n" if $debug;
RDF::Trine::Parser->parse_url_into_model( $file, $model, canonicalize => 1 );
}
warn "done parsing manifests" if $debug;
my $earl = init_earl( $model );
my $rs = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/result-set#');
my $mf = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#');
my $ut = RDF::Trine::Namespace->new('http://www.w3.org/2009/sparql/tests/test-update#');
my $rq = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-query#');
my $dawgt = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#');
{
my @manifests = $model->subjects( $rdf->type, $mf->Manifest );
foreach my $m (@manifests) {
warn "Manifest: " . $m->as_string . "\n" if ($debug);
my ($list) = $model->objects( $m, $mf->entries );
unless (blessed($list)) {
warn "No mf:entries found for manifest " . $m->as_string . "\n";
}
my @tests = $model->get_list( $list );
foreach my $test (@tests) {
my $et = $model->count_statements($test, $rdf->type, $mf->QueryEvaluationTest);
my $ct = $model->count_statements($test, $rdf->type, $mf->CSVResultFormatTest);
if ($et + $ct) {
my ($name) = $model->objects( $test, $mf->name );
unless ($test->uri_value =~ /$PATTERN/) {
next;
}
warn "### query eval test: " . $test->as_string . " >>> " . $name->literal_value . "\n" if ($debug);
query_eval_test( $model, $test, $earl );
}
if ($model->count_statements($test, $rdf->type, $ut->UpdateEvaluationTest) or $model->count_statements($test, $rdf->type, $mf->UpdateEvaluationTest)) {
my ($name) = $model->objects( $test, $mf->name );
unless ($test->uri_value =~ /$PATTERN/) {
next;
}
warn "### update eval test: " . $test->as_string . " >>> " . $name->literal_value . "\n" if ($debug);
update_eval_test( $model, $test, $earl );
}
}
}
}
open( my $fh, '>', 'earl-eval-11.ttl' ) or die $!;
print {$fh} earl_output( $earl );
close($fh);
################################################################################
sub update_eval_test {
my $model = shift;
my $test = shift;
my $earl = shift;
my ($action) = $model->objects( $test, $mf->action );
my ($result) = $model->objects( $test, $mf->result );
my ($req) = $model->objects( $test, $mf->requires );
my ($approved) = $model->objects( $test, $dawgt->approval );
my ($queryd) = $model->objects( $action, $ut->request );
my ($data) = $model->objects( $action, $ut->data );
my @gdata = $model->objects( $action, $ut->graphData );
if ($STRICT_APPROVAL) {
unless ($approved) {
warn "- skipping test because it isn't approved\n" if ($debug);
return;
}
if ($approved->equal( $dawgt->NotClassified)) {
warn "- skipping test because its approval is dawgt:NotClassified\n" if ($debug);
return;
}
}
my $uri = URI->new( $queryd->uri_value );
my $filename = $uri->file;
my (undef,$base,undef) = File::Spec->splitpath( $filename );
$base = "file://${base}";
warn "Loading SPARQL query from file $filename" if ($debug);
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename) or do { fail("$!: $filename; " . $test->as_string); return }; binmode($fh, ':utf8'); <$fh> };
my $q = $sparql;
$q =~ s/\s+/ /g;
if ($debug) {
warn "### test : " . $test->as_string . "\n";
warn "# sparql : $q\n";
warn "# data : " . $data->as_string . "\n" if (blessed($data));
warn "# graph data : " . $_->as_string . "\n" for (@gdata);
warn "# result : " . $result->as_string . "\n";
warn "# requires : " . $req->as_string . "\n" if (blessed($req));
}
print STDERR "constructing model... " if ($debug);
my ($test_model) = RDF::Trine::Model->temporary_model;
try {
if (blessed($data)) {
add_to_model( $test_model, $data->uri_value );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
} except {
my $e = shift;
die $e->text;
} otherwise {
warn '*** failed to construct model';
};
foreach my $gdata (@gdata) {
my ($data) = ($model->objects( $gdata, $ut->data ))[0] || ($model->objects( $gdata, $ut->graph ))[0];
my ($graph) = $model->objects( $gdata, $rdfs->label );
my $uri = $graph->literal_value;
try {
warn "test data file: " . $data->uri_value . "\n" if ($debug);
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $test_model, context => RDF::Trine::Node::Resource->new($uri), canonicalize => 1 );
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
};
}
my ($result_status) = $model->objects( $result, $ut->result );
my @resgdata = $model->objects( $result, $ut->graphData );
my $expected_model = RDF::Trine::Model->temporary_model;
my ($resdata) = $model->objects( $result, $ut->data );
try {
if (blessed($resdata)) {
RDF::Trine::Parser->parse_url_into_model( $resdata->uri_value, $expected_model, canonicalize => 1 );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
};
foreach my $gdata (@resgdata) {
my ($data) = ($model->objects( $gdata, $ut->data ))[0] || ($model->objects( $gdata, $ut->graph ))[0];
my ($graph) = $model->objects( $gdata, $rdfs->label );
my $uri = $graph->literal_value;
my $return = 0;
if ($data) {
try {
warn "expected result data file: " . $data->uri_value . "\n" if ($debug);
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $expected_model, context => RDF::Trine::Node::Resource->new($uri), canonicalize => 1 );
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
$return = 1;
};
return if ($return);
}
}
if ($debug) {
warn "Dataset before update operation:\n";
warn $test_model->as_string;
}
my $ok = 0;
eval {
my $query = RDF::Query->new( $sparql, { lang => 'sparql11', update => 1 } );
unless ($query) {
warn 'Query error: ' . RDF::Query->error;
fail($test->as_string);
return;
}
my ($plan, $ctx) = $query->prepare( $test_model );
$query->execute_plan( $plan, $ctx );
my $test_graph = RDF::Trine::Graph->new( $test_model );
my $expected_graph = RDF::Trine::Graph->new( $expected_model );
my $eq = $test_graph->equals( $expected_graph );
$ok = is( $eq, 1, $test->as_string );
unless ($ok) {
warn $test_graph->error;
warn "Got model:\n" . $test_model->as_string;
warn "Expected model:\n" . $expected_model->as_string;
}
};
if ($@ or not($ok)) {
if ($@) {
fail($test->as_string);
}
earl_fail_test( $earl, $test, $@ );
print "# failed: " . $test->as_string . "\n";
} else {
earl_pass_test( $earl, $test );
}
print STDERR "ok\n" if ($debug);
}
sub query_eval_test {
my $model = shift;
my $test = shift;
my $earl = shift;
my ($action) = $model->objects( $test, $mf->action );
my ($result) = $model->objects( $test, $mf->result );
my ($req) = $model->objects( $test, $mf->requires );
my ($approved) = $model->objects( $test, $dawgt->approval );
my ($queryd) = $model->objects( $action, $rq->query );
my ($data) = $model->objects( $action, $rq->data );
my @gdata = $model->objects( $action, $rq->graphData );
my @sdata = $model->objects( $action, $rq->serviceData );
if ($STRICT_APPROVAL) {
unless ($approved) {
warn "- skipping test because it isn't approved\n" if ($debug);
return;
}
if ($approved->equal($dawgt->NotClassified)) {
warn "- skipping test because its approval is dawgt:NotClassified\n" if ($debug);
return;
}
}
my $uri = URI->new( $queryd->uri_value );
my $filename = $uri->file;
my (undef,$base,undef) = File::Spec->splitpath( $filename );
$base = "file://${base}";
warn "Loading SPARQL query from file $filename" if ($debug);
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename) or do { warn("$!: $filename; " . $test->as_string); return }; binmode($fh, ':utf8'); <$fh> };
my $q = $sparql;
$q =~ s/\s+/ /g;
if ($debug) {
warn "### test : " . $test->as_string . "\n";
warn "# sparql : $q\n";
warn "# data : " . $data->as_string if (blessed($data));
warn "# graph data : " . $_->as_string for (@gdata);
warn "# result : " . $result->as_string;
warn "# requires : " . $req->as_string if (blessed($req));
}
# warn 'service data: ' . Dumper(\@sdata);
foreach my $sd (@sdata) {
my ($url) = $model->objects( $sd, $rq->endpoint );
print STDERR "setting up remote endpoint $url...\n" if ($debug);
my ($data) = $model->objects( $sd, $rq->data );
my @gdata = $model->objects( $sd, $rq->graphData );
if ($debug) {
warn "- data : " . $data->as_string if (blessed($data));
warn "- graph data : " . $_->as_string for (@gdata);
}
my $model = RDF::Trine::Model->new();
if ($data) {
RDF::Trine::Parser->parse_url_into_model( $data->uri_value, $model );
}
$Test::RDF::Query::Plan::Service::service_ctx{ $url->uri_value } = $model;
}
print STDERR "constructing model... " if ($debug);
my ($test_model) = RDF::Trine::Model->temporary_model;
try {
if (blessed($data)) {
add_to_model( $test_model, $data->uri_value );
}
} catch Error with {
my $e = shift;
fail($test->as_string);
earl_fail_test( $earl, $test, $e->text );
print "# died: " . $test->as_string . ": $e\n";
return;
} except {
my $e = shift;
die $e->text;
} otherwise {
warn '*** failed to construct model';
};
print STDERR "ok\n" if ($debug);
my $resuri = URI->new( $result->uri_value );
my $resfilename = $resuri->file;
TODO: {
local($TODO) = (blessed($req)) ? "requires " . $req->as_string : '';
my $comment;
my $ok = eval {
if ($debug) {
my $q = $sparql;
$q =~ s/([\x{256}-\x{1000}])/'\x{' . sprintf('%x', ord($1)) . '}'/eg;
warn $q;
}
print STDERR "getting actual results... " if ($debug);
my ($actual, $type) = get_actual_results( $test_model, $sparql, $base, @gdata );
print STDERR "ok\n" if ($debug);
print STDERR "getting expected results... " if ($debug);
my $expected = get_expected_results( $resfilename, $type );
print STDERR "ok\n" if ($debug);
# warn "comparing results...";
compare_results( $expected, $actual, $earl, $test->as_string, \$comment );
};
warn $@ if ($@);
if ($ok) {
earl_pass_test( $earl, $test );
} else {
earl_fail_test( $earl, $test, $comment );
print "# failed: " . $test->as_string . "\n";
}
}
}
exit;
######################################################################
sub add_to_model {
my $model = shift;
my @files = @_;
foreach my $file (@files) {
try {
RDF::Trine::Parser->parse_url_into_model( $file, $model, canonicalize => 1 );
} catch Error with {
my $e = shift;
warn "Failed to load $file into model: " . $e->text;
};
}
}
sub get_actual_results {
my $model = shift;
my $sparql = shift;
my $base = shift;
my @gdata = @_;
my $query = RDF::Query->new( $sparql, { base => $base, lang => 'sparql11', load_data => 1 } );
unless ($query) {
warn RDF::Query->error if ($debug or $PATTERN);
return;
}
my $testns = RDF::Trine::Namespace->new('http://example.com/test-results#');
my $rmodel = RDF::Trine::Model->temporary_model;
my ($plan, $ctx) = $query->prepare_with_named_graphs( $model, @gdata );
if ($args{plan}) {
warn $plan->explain(' ', 0);
}
my $results = $query->execute_plan( $plan, $ctx );
if ($args{ results }) {
$results = $results->materialize;
warn "Actual results:\n";
warn $results->as_string;
}
if ($results->is_bindings) {
return (binding_results_data( $results ), 'bindings');
} elsif ($results->is_boolean) {
$rmodel->add_statement( statement( $testns->result, $testns->boolean, literal(($results->get_boolean ? 'true' : 'false'), undef, $xsd->boolean) ) );
return ($rmodel->get_statements, 'boolean');
} elsif ($results->is_graph) {
return ($results, 'graph');
} else {
warn "unknown result type: " . Dumper($results);
}
}
sub get_expected_results {
my $file = shift;
my $type = shift;
my $testns = RDF::Trine::Namespace->new('http://example.com/test-results#');
if ($type eq 'graph') {
my $model = RDF::Trine::Model->temporary_model;
RDF::Trine::Parser->parse_url_into_model( "file://$file", $model, canonicalize => 1 );
my $results = $model->get_statements();
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return $results;
} elsif ($file =~ /[.](srj|json)/) {
my $model = RDF::Trine::Model->temporary_model;
my $data = do { local($/) = undef; open(my $fh, '<', $file) or die $!; binmode($fh, ':utf8'); <$fh> };
my $results = RDF::Trine::Iterator->from_json( $data, { canonicalize => 1 } );
if ($results->isa('RDF::Trine::Iterator::Boolean')) {
my $value = $results->next;
my $bool = ($value ? 'true' : 'false');
$model->add_statement( statement( $testns->result, $testns->boolean, literal($bool, undef, $xsd->boolean) ) );
if ($args{ results }) {
warn "Expected result: $bool\n";
}
return $model->get_statements;
} else {
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return binding_results_data( $results );
}
} elsif ($file =~ /[.]srx/) {
my $model = RDF::Trine::Model->temporary_model;
my $data = do { local($/) = undef; open(my $fh, '<:encoding(UTF-8)', $file) or die $!; <$fh> };
my $results = RDF::Trine::Iterator->from_string( $data, { canonicalize => 1 } );
if ($results->isa('RDF::Trine::Iterator::Boolean')) {
$model->add_statement( statement( $testns->result, $testns->boolean, literal(($results->next ? 'true' : 'false'), undef, $xsd->boolean) ) );
return $model->get_statements;
} else {
if ($args{ results }) {
$results = $results->materialize;
warn "Expected results:\n";
warn $results->as_string;
}
return binding_results_data( $results );
}
} elsif ($file =~ /[.]csv/) {
my $csv = Text::CSV_XS->new({binary => 1});
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $header = $csv->getline($fh);
my @vars = @$header;
my @data;
while (my $row = $csv->getline($fh)) {
my %result;
foreach my $i (0 .. $#vars) {
my $var = $vars[$i];
my $value = $row->[ $i ];
# XXX @@ heuristics that won't always work.
# XXX @@ expected to work on the test suite, though
if ($value =~ /^_:(\w+)$/) {
$value = blank($1);
} elsif ($value =~ /$RE{URI}/) {
$value = iri($value);
} elsif (defined($value) and length($value)) {
$value = literal($value);
}
$result{ $var } = $value;
}
push(@data, \%result);
}
if ($args{ results }) {
warn "Expected results:\n";
warn Dumper(\@data);
}
return \@data;
} elsif ($file =~ /[.]tsv/) {
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $header = <$fh>;
chomp($header);
my @vars = split("\t", $header);
foreach (@vars) { s/[?]// }
my @data;
my $parser = RDF::Trine::Parser::Turtle->new();
while (defined(my $line = <$fh>)) {
chomp($line);
my $row = [ split("\t", $line) ];
my %result;
foreach my $i (0 .. $#vars) {
my $var = $vars[$i];
my $value = $row->[ $i ];
my $node = length($value) ? $parser->parse_node( $value ) : undef;
$result{ $var } = $node;
}
push(@data, RDF::Query::VariableBindings->new( \%result ));
}
my $iter = RDF::Trine::Iterator::Bindings->new(\@data);
return binding_results_data($iter);
} elsif ($file =~ /[.](ttl|rdf)/) {
my $model = RDF::Trine::Model->new();
open( my $fh, "<:encoding(utf8)", $file ) or die $!;
my $base = 'file://' . File::Spec->rel2abs($file);
my $parser = RDF::Trine::Parser->new(($file =~ /[.]ttl/) ? 'turtle' : 'rdfxml');
$parser->parse_file_into_model( $base, $file, $model );
my ($res) = $model->subjects( $rdf->type, $rs->ResultSet );
if (my($b) = $model->objects( $res, $rs->boolean )) {
my $bool = $b->literal_value;
my $rmodel = RDF::Trine::Model->new();
$rmodel->add_statement( statement( $testns->result, $testns->boolean, literal($bool, undef, $xsd->boolean) ) );
if ($args{ results }) {
warn "Expected result: $bool\n";
}
return $rmodel->get_statements;
} else {
my @vars = $model->objects( $res, $rs->resultVariable );
my @sols = $model->objects( $res, $rs->solution );
my @names = map { $_->literal_value } @vars;
my @bindings;
foreach my $r (@sols) {
my %data;
my @b = $model->objects( $r, $rs->binding );
foreach my $b (@b) {
my ($value) = $model->objects( $b, $rs->value );
my ($var) = $model->objects( $b, $rs->variable );
$data{ $var->literal_value } = $value;
}
push(@bindings, RDF::Trine::VariableBindings->new( \%data ));
}
my $iter = RDF::Trine::Iterator::Bindings->new( \@bindings, \@names );
if ($args{ results }) {
$iter = $iter->materialize;
warn "Got expected results:\n";
warn $iter->as_string;
}
return binding_results_data($iter);
}
} else {
die "Unrecognized type of expected results: $file";
}
}
sub compare_results {
my $expected = shift;
my $actual = shift;
my $earl = shift;
my $test = shift;
my $comment = shift || do { my $foo; \$foo };
my $TODO = shift;
my $lossy_cmp = 0;
if (reftype($expected) eq 'ARRAY') {
# comparison with expected results coming from a lossy format like csv/tsv
$lossy_cmp = 1;
my %data = (results => [], blank_identifiers => {});
foreach my $row (@$expected) {
push(@{ $data{ results } }, $row );
foreach my $key (keys %$row) {
my $node = $row->{$key};
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
$data{ blank_identifiers }{ $node->blank_identifier }++;
}
}
}
$data{ blanks } = scalar(@{ [ keys %{ $data{ blank_identifiers } } ] });
$expected = \%data;
}
if (not(ref($actual))) {
my $ok = is( $actual, $expected, $test );
return $ok;
} elsif (blessed($actual) and $actual->isa('RDF::Trine::Iterator::Graph')) {
die "Unexpected Graph result type (was expecting " . ref($expected) . ")" unless (blessed($expected) and $expected->isa('RDF::Trine::Iterator::Graph'));
my $act_graph = RDF::Trine::Graph->new( $actual );
my $exp_graph = RDF::Trine::Graph->new( $expected );
# local($debug) = 1 if ($PATTERN);
if ($debug) {
warn ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
my $actualxml = $act_graph->get_statements->as_string;
warn $actualxml;
warn "-------------------------------\n";
my $expectxml = $exp_graph->get_statements->as_string;
warn $expectxml;
warn "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n";
}
my $eq = $act_graph->equals( $exp_graph );
unless ($eq) {
warn $act_graph->error;
}
return is( $eq, 1, $test );
} elsif (reftype($actual) eq 'HASH' and reftype($expected) eq 'HASH') {
my @aresults = @{ $actual->{ results } };
my @eresults = @{ $expected->{ results } };
my $acount = scalar(@aresults);
my $ecount = scalar(@eresults);
if ($acount != $ecount) {
warn "Result count ($acount) didn't match expected ($ecount)" if ($debug);
return fail($test);
}
# warn Data::Dumper->Dump([\@aresults, \@eresults], [qw(actual expected)]);
my ($awith, $awithout) = split_results_with_blank_nodes( @aresults );
my ($ewith, $ewithout) = split_results_with_blank_nodes( @eresults );
# for the results without blanks, just serialize, sort, and compare
my @astrings = sort map { result_to_string($_, $lossy_cmp) } @$awithout;
my @estrings = sort map { result_to_string($_, $lossy_cmp) } @$ewithout;
if ($actual->{ blanks } == 0 and $expected->{ blanks } == 0) {
return is_deeply( \@astrings, \@estrings, $test );
} elsif (join("\xFF", @astrings) ne join("\xFF", @estrings)) {
warn "triples don't match: " . Dumper(\@astrings, \@estrings);
return fail($test);
}
# compare the results with bnodes
my @ka = keys %{ $actual->{blank_identifiers} };
my @kb = keys %{ $expected->{blank_identifiers} };
my $kbp = permutations( \@kb );
MAPPING: while (my $mapping = $kbp->next) {
my %mapping;
@mapping{ @ka } = @$mapping;
warn "trying mapping: " . Dumper(\%mapping) if ($debug);
my %ewith = map { result_to_string($_, $lossy_cmp) => 1 } @$ewith;
foreach my $row (@$awith) {
my %row;
foreach my $k (keys %$row) {
my $n = $row->{ $k };
next unless (blessed($n));
if ($n->isa('RDF::Trine::Node::Blank')) {
my $id = $mapping{ $n->blank_identifier };
warn "mapping " . $n->blank_identifier . " to $id\n" if ($debug);
$row{ $k } = RDF::Trine::Node::Blank->new( $id );
} else {
$row{ $k } = $n;
}
}
my $mapped_row = result_to_string( RDF::Query::VariableBindings->new( \%row ), $lossy_cmp );
warn "checking for '$mapped_row' in " . Dumper(\%ewith) if ($debug);
if ($ewith{ $mapped_row }) {
delete $ewith{ $mapped_row };
} else {
next MAPPING;
}
}
warn "found mapping: " . Dumper(\%mapping) if ($debug);
return pass($test);
}
warn "failed to find bnode mapping: " . Dumper($awith, $ewith);
return fail($test);
} else {
die "Failed to compare actual and expected results: " . Dumper($actual, $expected);
}
}
sub binding_results_data {
my $iter = shift;
my %data = (results => [], blank_identifiers => {});
while (my $row = $iter->next) {
push(@{ $data{ results } }, $row );
foreach my $key (keys %$row) {
my $node = $row->{$key};
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
$data{ blank_identifiers }{ $node->blank_identifier }++;
}
}
}
$data{ blanks } = scalar(@{ [ keys %{ $data{ blank_identifiers } } ] });
return \%data;
}
sub split_results_with_blank_nodes {
my (@with, @without);
ROW: foreach my $row (@_) {
my @keys = grep { ref($row->{ $_ }) } keys %$row;
foreach my $k (@keys) {
my $node = $row->{ $k };
if (blessed($node) and $node->isa('RDF::Trine::Node::Blank')) {
push(@with, $row);
next ROW;
}
}
push(@without, $row);
}
return (\@with, \@without);
}
sub result_to_string {
my $row = shift;
my $lossy_cmp = shift;
my @keys = grep { ref($row->{ $_ }) } keys %$row;
my @results;
foreach my $k (@keys) {
my $node = $row->{ $k };
if ($node->isa('RDF::Trine::Node::Literal') and $node->has_datatype) {
my ($value, $dt);
if ($lossy_cmp) {
$value = $node->literal_value;
$dt = undef;
} else {
$value = RDF::Trine::Node::Literal->canonicalize_literal_value( $node->literal_value, $node->literal_datatype );
$dt = $node->literal_datatype;
}
$node = RDF::Query::Node::Literal->new( $value, undef, $dt );
}
push(@results, join('=', $k, $node->as_string));
}
return join(',', sort(@results));
}
package Test::RDF::Query::Plan::Service;
use strict;
use warnings;
use Data::Dumper;
use Scalar::Util qw(refaddr);
use base qw(RDF::Query::Plan::Service);
our %ENDPOINTS;
our %service_ctx;
sub new {
my $class = shift;
my $endpoint = shift;
my $plan = shift;
my $silent = shift;
my $sparql = shift;
if ($endpoint->isa('RDF::Query::Node::Resource')) {
my $uri = $endpoint->uri_value;
warn "setting up mock endpoint for $uri" if ($debug);
}
my $self = $class->SUPER::new( $endpoint, $plan, $silent, $sparql, @_ );
if ($endpoint->isa('RDF::Query::Node::Resource')) {
my $uri = $endpoint->uri_value;
my $e = URI->new($uri);
my $model = $service_ctx{ $uri };
# warn "model for $uri: $model";
if ($model) {
my $end = RDF::Endpoint->new( $model, { endpoint => { endpoint_path => $e->path } } );
$ENDPOINTS{ refaddr($self) } = $end;
}
}
return $self;
}
# sub mock {
# my $self = shift;
# return;
# my $endpoint = shift;
# my $data = shift;
# my $e = URI->new($endpoint);
#
# my $model = RDF::Trine::Model->new();
# my ($default, $named) = @$data;
# if ($default) {
# RDF::Trine::Parser->parse_url_into_model( $default->uri_value, $model );
# my $end = RDF::Endpoint->new( $model, { endpoint => { endpoint_path => $e->path } } );
# $ENDPOINTS{ refaddr($self) } = $end;
# }
# }
sub _request {
my $self = shift;
my $ua = shift;
my $req = shift;
my $env = $req->to_psgi;
my $end = $ENDPOINTS{ refaddr($self) };
if ($end) {
# warn "got mocked endpoint";
my $app = sub {
my $env = shift;
my $req = Plack::Request->new($env);
my $resp = $end->run( $req );
return $resp->finalize;
};
my $data = $app->( $env );
my $resp = HTTP::Response->from_psgi( $data );
return $resp;
} else {
# warn "no mocked endpoint available";
return HTTP::Response->new(403);
}
}
sub DESTROY {
my $self = shift;
delete $ENDPOINTS{ refaddr($self) };
$self->SUPER::DESTROY();
}
RDF-Query-2.918/xt/dawg-syntax11.t 000755 000765 000024 00000021611 13033227174 016600 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use URI::file;
use RDF::Query;
use Test::More;
use Scalar::Util qw(blessed);
use RDF::Trine::Iterator qw(smap);
use RDF::Query::Node qw(iri);
use LWP::Simple;
use LWP::MediaTypes qw(add_type);
add_type( 'application/rdf+xml' => qw(rdf xrdf rdfx) );
add_type( 'text/turtle' => qw(ttl) );
add_type( 'text/plain' => qw(nt) );
add_type( 'text/x-nquads' => qw(nq) );
add_type( 'text/json' => qw(json) );
add_type( 'text/html' => qw(html xhtml htm) );
our $debug = 0;
if ($] < 5.007003) {
plan skip_all => 'perl >= 5.7.3 required';
exit;
}
require Encode;
require Data::Dumper;
plan qw(no_plan);
require "xt/dawg/earl.pl";
my $PATTERN = shift(@ARGV) || '';
my @manifests;
my $model = new_model( map { glob( "xt/dawg11/$_/manifest.ttl" ) }
qw(
aggregates
construct
delete-insert
grouping
syntax-query
syntax-fed
syntax-update-1
syntax-update-2
) );
my $earl = init_earl( $model );
my $type = iri( "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" );
my $pos_query = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#PositiveSyntaxTest11" );
my $pos_update = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#PositiveUpdateSyntaxTest11" );
my $neg_query = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#NegativeSyntaxTest11" );
my $neg_update = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#NegativeUpdateSyntaxTest11" );
my $mfname = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#name" );
my $mfaction = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action" );
my $mf = RDF::Trine::Namespace->new('http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#');
{
# print "# Positive Syntax Tests\n";
my @manifests = $model->subjects( $type, $mf->Manifest );
foreach my $m (@manifests) {
warn "Manifest: " . $m->as_string . "\n" if ($debug);
my ($list) = $model->objects( $m, $mf->entries );
my @tests = $model->get_list( $list );
foreach my $test (@tests) {
unless ($test->uri_value =~ /$PATTERN/) {
next;
}
my $is_pos_query = $model->count_statements($test, $type, $pos_query);
my $is_pos_update = $model->count_statements($test, $type, $pos_update);
my $is_neg_query = $model->count_statements($test, $type, $mf->NegativeSyntaxTest) + $model->count_statements($test, $type, $mf->NegativeSyntaxTest11);
my $is_neg_update = $model->count_statements($test, $type, $mf->NegativeUpdateSyntaxTest) + $model->count_statements($test, $type, $mf->NegativeUpdateSyntaxTest11);
if ($is_pos_query or $is_pos_update) {
my $name = get_first_literal( $model, $test, $mfname );
my $ok = positive_syntax_test( $model, $test, $is_pos_update );
ok( $ok, $name );
if ($ok) {
earl_pass_test( $earl, globalize_uri_filename($test) );
} else {
earl_fail_test( $earl, globalize_uri_filename($test) );
warn RDF::Query->error;
}
} elsif ($is_neg_query or $is_neg_update) {
my $name = get_first_literal( $model, $test, $mfname );
my $ok = negative_syntax_test( $model, $test, $is_neg_update );
ok( $ok, $name );
if ($ok) {
earl_pass_test( $earl, globalize_uri_filename($test) );
} else {
earl_fail_test( $earl, globalize_uri_filename($test) );
}
}
}
}
}
# {
# print "# Negative Syntax Tests\n";
# my @manifests = $model->subjects( $type, $mf->Manifest );
# foreach my $m (@manifests) {
# warn "Manifest: " . $m->as_string . "\n" if ($debug);
# my ($list) = $model->objects( $m, $mf->entries );
# my @tests = $model->get_list( $list );
# foreach my $test (@tests) {
# my $is_neg_query = $model->count_statements($test, $type, $mf->NegativeSyntaxTest) + $model->count_statements($test, $type, $mf->NegativeSyntaxTest11);
# my $is_neg_update = $model->count_statements($test, $type, $mf->NegativeUpdateSyntaxTest) + $model->count_statements($test, $type, $mf->NegativeUpdateSyntaxTest11);
# if ($is_neg_query or $is_neg_update) {
# my $name = get_first_literal( $model, $test, $mfname );
# unless ($test->uri_value =~ /$PATTERN/) {
# next;
# }
# my $ok = negative_syntax_test( $model, $test );
# ok( $ok, $name );
# if ($ok) {
# earl_pass_test( $earl, globalize_uri_filename($test) );
# } else {
# earl_fail_test( $earl, globalize_uri_filename($test) );
# warn RDF::Query->error;
# }
# }
# }
# }
# }
open( my $fh, '>', 'earl-syntax-11.ttl' );
print {$fh} earl_output( $earl );
close($fh);
################################################################################
sub positive_syntax_test {
my $model = shift;
my $test = shift;
my $update = shift;
my $action = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action" );
my $file = get_first_obj( $model, $test, $action );
my $url = $file->uri_value;
my $uri = URI->new( relativeize_url( $url ) );
my $filename = localize_uri_filename( $uri->file );
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename); <$fh> };
my @uargs = $update ? (update => 1) : ();
my $query = eval { RDF::Query->new( $sparql, { lang => 'sparql11', @uargs } ) };
return 0 if ($@);
return blessed($query) ? 1 : 0;
}
sub negative_syntax_test {
my $model = shift;
my $test = shift;
my $update = shift;
my $action = iri( "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#action" );
my $file = get_first_obj( $model, $test, $action );
my $url = $file->uri_value;
my $uri = URI->new( relativeize_url( $url ) );
my $filename = $uri->file;
my $sparql = do { local($/) = undef; open(my $fh, '<', $filename); <$fh> };
my @uargs = $update ? (update => 1) : ();
my $query = eval { RDF::Query->new( $sparql, { lang => 'sparql11', @uargs } ) };
# warn RDF::Query->error;
return 1 if ($@);
warn 'Test expected failure but successfully parsed: ' . Data::Dumper::Dumper($query->{parsed}) if (blessed($query));
# warn $query->error if (blessed($query));
return blessed($query) ? 0 : 1;
}
exit;
######################################################################
sub new_model {
my @files = @_;
my $model = RDF::Trine::Model->temporary_model;
add_to_model( $model, file_uris(@files) );
return ($model);
}
sub add_to_model {
my $model = shift;
my @files = @_;
foreach my $file (@files) {
my $pclass = RDF::Trine::Parser->guess_parser_by_filename( $file );
my $parser = $pclass->new();
my $rdf = get($file);
$parser->parse_into_model( $file, $rdf, $model );
}
}
sub localize_uri_filename {
my $uri = shift;
$uri =~ s{^http://www.w3.org/2009/sparql/docs/tests/data-sparql11/}{xt/dawg11/};
return $uri;
}
sub globalize_uri_filename {
my $uri = shift;
$uri = $uri->uri_value;
$uri =~ s{^.*xt/dawg11/}{http://www.w3.org/2009/sparql/docs/tests/data-sparql11/};
return RDF::Trine::Node::Resource->new($uri);
}
sub file_uris {
my @files = @_;
my @uris = map { "$_" } map { URI::file->new_abs( $_ ) } @files;
return @uris;
}
######################################################################
sub get_first_as_string {
my $node = get_first_obj( @_ );
return unless $node;
return node_as_string( $node );
}
sub node_as_string {
my $node = shift;
if ($node) {
no warnings 'once';
if ($node->isa('RDF::Trine::Node::Resource')) {
return $node->uri_value;
} elsif ($node->isa_literal) {
return Encode::decode('utf8', $node->literal_value);
} else {
return $node->blank_identifier;
}
} else {
return;
}
}
sub get_first_literal {
my $node = get_first_obj( @_ );
return $node ? $node->literal_value : undef;
}
sub get_all_literal {
my @nodes = get_all_obj( @_ );
return map { $_->literal_value } grep { $_->isa('RDF::Trine::Node::Literal') } @nodes;
}
sub get_first_uri {
my $node = get_first_obj( @_ );
return $node ? $node->uri_value : undef;
}
sub get_all_uri {
my @nodes = get_all_obj( @_ );
return map { $_->uri_value } grep { defined($_) and $_->isa('RDF::Trine::Node::Resource') } @nodes;
}
sub get_first_obj {
my $model = shift;
my $node = shift;
my $uri = shift;
my @uris = UNIVERSAL::isa($uri, 'ARRAY') ? @{ $uri } : ($uri);
my @preds = map { ref($_) ? $_ : iri( $_ ) } @uris;
foreach my $pred (@preds) {
my $stream = $model->get_statements( $node, $pred, undef );
while (my $st = $stream->next) {
my $node = $st->object;
return $node if ($node);
}
}
}
sub get_all_obj {
my $model = shift;
my $node = shift;
my $uri = shift;
my @uris = UNIVERSAL::isa($uri, 'ARRAY') ? @{ $uri } : ($uri);
my @preds = map { ref($_) ? $_ : iri( $_ ) } @uris;
my @objs;
my @streams;
foreach my $pred (@preds) {
push(@streams, $model->get_statements( $node, $pred, undef ));
}
my $stream = shift(@streams);
while (@streams) {
$stream = $stream->concat( shift(@streams) );
}
return map { $_->object } $stream->get_all();
}
sub relativeize_url {
my $uri = shift;
if ($uri =~ /^http:/) {
$uri =~ s{^http://www.w3.org/2001/sw/DataAccess/tests/}{xt/dawg/data-r2/};
$uri = 'file://' . File::Spec->rel2abs( $uri );
}
return $uri;
}
__END__
RDF-Query-2.918/xt/dev-service-description.t 000644 000765 000024 00000012006 13033227174 020720 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use File::Spec;
use Test::More;
plan skip_all => "QUERY FEDERATION isn't implemented";
# use RDF::Trine::Namespace qw(rdf foaf);
# my $xsd = RDF::Trine::Namespace->new('http://www.w3.org/2001/XMLSchema#');
# my $dcterms = RDF::Trine::Namespace->new('http://purl.org/dc/terms/');
#
# use lib qw(. t);
# BEGIN { require "models.pl"; }
#
# use Test::More;
#
# my $tests = 22;
# my $network_tests = $ENV{RDFQUERY_NETWORK_TESTS} || 0;
# if (not exists $ENV{RDFQUERY_DEV_TESTS}) {
# plan skip_all => 'Developer tests. Set RDFQUERY_DEV_TESTS to run these tests.';
# return;
# } else {
# plan tests => $tests;
# }
#
# use_ok( 'RDF::Query::Federate' );
# use_ok( 'RDF::Query::ServiceDescription' );
#
# ################################################################################
# # Log::Log4perl::init( \q[
# # log4perl.category.rdf.query.servicedescription = DEBUG, Screen
# # log4perl.category.rdf.query.plan.service = DEBUG, Screen
# # log4perl.appender.Screen = Log::Log4perl::Appender::Screen
# # log4perl.appender.Screen.stderr = 0
# # log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
# # ] );
# ################################################################################
#
# my $uri = URI::file->new_abs( 'data/service.ttl' );
# my $sd = RDF::Query::ServiceDescription->new_from_uri( $uri );
# isa_ok( $sd, 'RDF::Query::ServiceDescription' );
#
# {
# is( $sd->label, 'DBpedia', 'expected endpoint label' );
# is( $sd->url, 'http://dbpedia.org/sparql', 'expected endpoint uri' );
# is( $sd->size, 58_787_090, 'expected triple size');
# is( $sd->definitive, 1, 'expected definitive flag');
#
# my $o = RDF::Query::Node::Variable->new('object');
# my $expect_p = {
# $rdf->type->uri_value => {
# pred => RDF::Query::Node::Resource->new( $rdf->type->uri_value ),
# sofilter => RDF::Query::Expression::Function->new('sparql:regex', RDF::Query::Expression::Function->new('sparql:str', $o), RDF::Query::Node::Literal->new('http://xmlns.com/foaf/0.1/Person')),
# size => RDF::Query::Node::Literal->new('3683409', undef, $xsd->integer->uri_value),
# },
# $foaf->name->uri_value => {
# pred => RDF::Query::Node::Resource->new( $foaf->name->uri_value ),
# sofilter => undef,
# size => RDF::Query::Node::Literal->new('18000', undef, $xsd->integer->uri_value),
# object_selectivity => RDF::Query::Node::Literal->new('0.02', undef, $xsd->double->uri_value),
# },
# $foaf->mbox->uri_value => {
# pred => RDF::Query::Node::Resource->new( $foaf->mbox->uri_value ),
# sofilter => undef,
# size => RDF::Query::Node::Literal->new('18000', undef, $xsd->integer->uri_value),
# object_selectivity => RDF::Query::Node::Literal->new('5.5E-5', undef, $xsd->double->uri_value),
# },
# $dcterms->spatial->uri_value => {
# pred => RDF::Query::Node::Resource->new( $dcterms->spatial->uri_value ),
# },
# };
# my $cap = $sd->capabilities;
# foreach my $data (grep {exists $_->{pred}} @$cap) {
# my $p = $data->{pred}->uri_value;
# my $e = delete $expect_p->{ $p };
# isa_ok( $e, 'HASH' );
# is_deeply( $data, $e, "capability for $p" );
# }
# is_deeply( $expect_p, {}, 'seen all expected predicate-based capabilities' );
#
# my $expect_t = {
# 'http://kasei.us/2008/04/sparql#any_triple' => 1,
# };
# foreach my $data (grep {exists $_->{type}} @$cap) {
# my $type = $data->{type}->uri_value;
# my $ok = delete( $expect_t->{ $type } );
# ok( $ok, "expected type-capability: $type" );
# }
# is_deeply( $expect_t, {}, 'seen all expected type-based capabilities' );
# }
#
# SKIP: {
# skip "set RDFQUERY_NETWORK_TESTS to run these tests", 3 unless ($network_tests);
# my $query = RDF::Query::Federate->new( <<"END" );
# PREFIX foaf:
# SELECT ?name
# WHERE { foaf:name ?name . FILTER( LANG(?name) = "en" ) }
# END
# $query->add_computed_statement_generator( $sd->computed_statement_generator );
# my $iter = $query->execute;
# my $count = 0;
# while (my $row = $iter->next) {
# isa_ok( $row, 'HASH' );
# my $name = $row->{name};
# like( $name->literal_value, qr"^Alan.*Turing$", 'execution: expected foaf:name in federation description' );
# $count++;
# last;
# }
# is( $count, 1, 'got results from dbpedia' );
# }
#
# SKIP: {
# skip "set RDFQUERY_NETWORK_TESTS to run these tests", 1 unless ($network_tests);
# my $query = RDF::Query::Federate->new( <<"END" );
# PREFIX foaf:
# PREFIX dbp:
# SELECT ?job
# WHERE { dbp:occupation ?job }
# END
# $query->add_computed_statement_generator( $sd->computed_statement_generator );
# my $iter = $query->execute;
# my $count = 0;
# while (my $row = $iter->next) {
# $count++;
# }
# is( $count, 0, 'execution: expected dbp:occupation not in federation description' );
# }
RDF-Query-2.918/xt/dev-sql-compiler.t 000644 000765 000024 00000103206 13033227174 017351 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use Test::More;
use Test::Exception;
use RDF::Query;
use RDF::Query::Parser::SPARQL;
if ($ENV{RDFQUERY_DEV_MYSQL}) {
plan 'no_plan';
} else {
plan tests => 34;
}
use_ok( 'RDF::Query::Compiler::SQL' );
my $parser = new RDF::Query::Parser::SPARQL ();
{
my $uri = 'http://xmlns.com/foaf/0.1/name';
my $node = RDF::Query::Node::Resource->new( $uri );
my $hash = RDF::Query::Compiler::SQL->_mysql_node_hash( $node );
is( $hash, '14911999128994829034', 'URI hash' );
}
{
my $node = RDF::Query::Node::Literal->new( 'kasei' );
my $hash = RDF::Query::Compiler::SQL->_mysql_node_hash( $node );
is( $hash, '12775641923308277283', 'literal hash' );
}
{
my $hash = RDF::Query::Compiler::SQL::_mysql_hash( 'LTom Croucher' );
is( $hash, '14336915341960534814', 'language-typed literal hash' );
}
{
my $node = RDF::Query::Node::Literal->new( 'Tom Croucher', 'en' );
my $hash = RDF::Query::Compiler::SQL->_mysql_node_hash( $node );
is( $hash, '14336915341960534814', 'language-typed literal node hash 1' );
}
{
my $node = RDF::Query::Node::Literal->new( 'RDF', 'en' );
my $hash = RDF::Query::Compiler::SQL->_mysql_node_hash( $node );
is( $hash, '16625494614570964497', 'language-typed literal node hash 2' );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name
WHERE { ?person foaf:name ?name }
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed, 'model' );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements15799945864759145248 s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID)\nWHERE\n\ts2.predicate = 14911999128994829034", "select people and names" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name
WHERE {
?person foaf:name ?name .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID)\nWHERE\n\ts2.predicate = 14911999128994829034", "select people and names" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name ?homepage
WHERE {
?person foaf:name ?name ; foaf:homepage ?homepage
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name,\n\ts3.object AS homepage_Node,\n\tljr2.URI AS homepage_URI,\n\tljl2.Value AS homepage_Value,\n\tljl2.Language AS homepage_Language,\n\tljl2.Datatype AS homepage_Datatype,\n\tljb2.Name AS homepage_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID),\n\tStatements s3 LEFT JOIN Resources ljr2 ON (s3.object = ljr2.ID) LEFT JOIN Literals ljl2 ON (s3.object = ljl2.ID) LEFT JOIN Bnodes ljb2 ON (s3.object = ljb2.ID)\nWHERE\n\ts2.predicate = 14911999128994829034 AND\n\ts3.subject = s2.subject AND\n\ts3.predicate = 9768710922987392204", "select people, names, and homepages" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?x ?name
FROM NAMED
FROM NAMED
WHERE {
GRAPH { ?x foaf:name ?name }
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts3.subject AS x_Node,\n\tljr0.URI AS x_URI,\n\tljl0.Value AS x_Value,\n\tljl0.Language AS x_Language,\n\tljl0.Datatype AS x_Datatype,\n\tljb0.Name AS x_Name,\n\ts3.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s3 LEFT JOIN Resources ljr0 ON (s3.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s3.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s3.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s3.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s3.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s3.object = ljb1.ID)\nWHERE\n\ts3.predicate = 14911999128994829034 AND\n\ts3.context = 2618056589919804847", "select people and names of context-specific graph" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?src ?name
FROM NAMED
FROM NAMED
WHERE {
GRAPH ?src { ?x foaf:name ?name }
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts3.context AS src_Node,\n\tljr0.URI AS src_URI,\n\tljl0.Value AS src_Value,\n\tljl0.Language AS src_Language,\n\tljl0.Datatype AS src_Datatype,\n\tljb0.Name AS src_Name,\n\ts3.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name,\n\tljr2.URI AS x_URI,\n\tljl2.Value AS x_Value,\n\tljl2.Language AS x_Language,\n\tljl2.Datatype AS x_Datatype,\n\tljb2.Name AS x_Name\nFROM\n\tStatements s3 LEFT JOIN Resources ljr0 ON (s3.context = ljr0.ID) LEFT JOIN Literals ljl0 ON (s3.context = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s3.context = ljb0.ID) LEFT JOIN Resources ljr1 ON (s3.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s3.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s3.object = ljb1.ID) LEFT JOIN Resources ljr2 ON (s3.subject = ljr2.ID) LEFT JOIN Literals ljl2 ON (s3.subject = ljl2.ID) LEFT JOIN Bnodes ljb2 ON (s3.subject = ljb2.ID)\nWHERE\n\ts3.predicate = 14911999128994829034", "select context of people and names" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX rss:
SELECT ?title
WHERE {
rss:title ?title .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.object AS title_Node,\n\tljr0.URI AS title_URI,\n\tljl0.Value AS title_Value,\n\tljl0.Language AS title_Language,\n\tljl0.Datatype AS title_Datatype,\n\tljb0.Name AS title_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.object = ljb0.ID)\nWHERE\n\ts2.subject = 1083049239652454081 AND\n\ts2.predicate = 17858988500659793691", "select rss:title of uri" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX rdf:
PREFIX foaf:
PREFIX dcterms:
PREFIX geo:
SELECT ?page
WHERE {
?person foaf:name "Gregory Todd Williams" .
?person foaf:homepage ?page .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts3.object AS page_Node,\n\tljr0.URI AS page_URI,\n\tljl0.Value AS page_Value,\n\tljl0.Language AS page_Language,\n\tljl0.Datatype AS page_Datatype,\n\tljb0.Name AS page_Name,\n\tljr1.URI AS person_URI,\n\tljl1.Value AS person_Value,\n\tljl1.Language AS person_Language,\n\tljl1.Datatype AS person_Datatype,\n\tljb1.Name AS person_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr1 ON (s2.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.subject = ljb1.ID),\n\tStatements s3 LEFT JOIN Resources ljr0 ON (s3.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s3.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s3.object = ljb0.ID)\nWHERE\n\ts2.predicate = 14911999128994829034 AND\n\ts2.object = 2782977400239829321 AND\n\ts3.subject = s2.subject AND\n\ts3.predicate = 9768710922987392204", "select homepage of person by name" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT ?s ?p
WHERE {
?s ?p "RDF"@en .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS s_Node,\n\tljr0.URI AS s_URI,\n\tljl0.Value AS s_Value,\n\tljl0.Language AS s_Language,\n\tljl0.Datatype AS s_Datatype,\n\tljb0.Name AS s_Name,\n\ts2.predicate AS p_Node,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.predicate = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.predicate = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.predicate = ljb1.ID)\nWHERE\n\ts2.object = 16625494614570964497", "select s,p by language-tagged literal" );
}
{
RDF::Query::Compiler::SQL->add_function( 'time:now', sub {
my $self = shift;
my $parsed_vars = shift;
my $expr = shift;
my $level = shift || \do{ my $a = 0 };
my %queryvars = map { $_->name => 1 } @$parsed_vars;
return ({}, [], ['NOW()']);
} );
my $parsed = $parser->parse(<<'END');
PREFIX rdf:
PREFIX foaf:
PREFIX dcterms:
PREFIX geo:
PREFIX mygeo:
PREFIX xsd:
PREFIX time:
SELECT ?point
WHERE {
?point a geo:Point .
FILTER( time:now() > "2006-01-01" )
}
END
my $sql;
lives_ok {
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
$sql = $compiler->compile();
} 'compile: select with function filter';
is( $sql, qq(SELECT\n\ts6.subject AS point_Node,\n\tljr0.URI AS point_URI,\n\tljl0.Value AS point_Value,\n\tljl0.Language AS point_Language,\n\tljl0.Datatype AS point_Datatype,\n\tljb0.Name AS point_Name\nFROM\n\tStatements s6 LEFT JOIN Resources ljr0 ON (s6.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s6.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s6.subject = ljb0.ID)\nWHERE\n\tNOW() > '2006-01-01' AND\n\ts6.predicate = 2982895206037061277 AND\n\ts6.object = 11045396790191387947), "sql: select with function filter" );
}
{
RDF::Query::Compiler::SQL->add_function( 'http://kasei.us/e/ns/geo#distance', sub {
my $self = shift;
my $parsed_vars = shift;
my $level = shift || \do{ my $a = 0 };
my @args = @_;
my $vars = $self->{vars};
my (@from, @where);
my %queryvars = map { $_->name => 1 } @$parsed_vars;
++$$level; my $sql_a = $self->expr2sql( $args[0], $level );
++$$level; my $sql_b = $self->expr2sql( $args[1], $level );
++$$level; my $sql_c = $self->expr2sql( $args[1], $level );
push(@where, "distance($sql_a, $sql_b, $sql_c)");
return ($vars, \@from, \@where);
} );
my $parsed = $parser->parse(<<'END');
PREFIX rdf:
PREFIX foaf:
PREFIX dcterms:
PREFIX geo:
PREFIX mygeo:
PREFIX xsd:
SELECT ?image ?point ?lat
WHERE {
?point geo:lat ?lat .
?image ?pred ?point .
FILTER( mygeo:distance(?point, +41.849331, -71.392) < "10"^^xsd:integer )
}
END
my $sql;
lives_ok {
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
$sql = $compiler->compile();
} 'compile: select images filterd by distance function comparison';
is( $sql, qq(SELECT\n\ts10.subject AS image_Node,\n\tljr0.URI AS image_URI,\n\tljl0.Value AS image_Value,\n\tljl0.Language AS image_Language,\n\tljl0.Datatype AS image_Datatype,\n\tljb0.Name AS image_Name,\n\ts9.subject AS point_Node,\n\tljr1.URI AS point_URI,\n\tljl1.Value AS point_Value,\n\tljl1.Language AS point_Language,\n\tljl1.Datatype AS point_Datatype,\n\tljb1.Name AS point_Name,\n\ts9.object AS lat_Node,\n\tljr2.URI AS lat_URI,\n\tljl2.Value AS lat_Value,\n\tljl2.Language AS lat_Language,\n\tljl2.Datatype AS lat_Datatype,\n\tljb2.Name AS lat_Name,\n\tljr3.URI AS pred_URI,\n\tljl3.Value AS pred_Value,\n\tljl3.Language AS pred_Language,\n\tljl3.Datatype AS pred_Datatype,\n\tljb3.Name AS pred_Name\nFROM\n\tStatements s9 LEFT JOIN Resources ljr1 ON (s9.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s9.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s9.subject = ljb1.ID) LEFT JOIN Resources ljr2 ON (s9.object = ljr2.ID) LEFT JOIN Literals ljl2 ON (s9.object = ljl2.ID) LEFT JOIN Bnodes ljb2 ON (s9.object = ljb2.ID),\n\tStatements s10 LEFT JOIN Resources ljr0 ON (s10.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s10.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s10.subject = ljb0.ID) LEFT JOIN Resources ljr3 ON (s10.predicate = ljr3.ID) LEFT JOIN Literals ljl3 ON (s10.predicate = ljl3.ID) LEFT JOIN Bnodes ljb3 ON (s10.predicate = ljb3.ID)\nWHERE\n\tdistance(, (0.0 + '+41.849331'), (0.0 + '+41.849331')) < (0 + '10') AND\n\ts9.predicate = 5391429383543785584 AND\n\ts10.object = s9.subject), "sql: select images filterd by distance function comparison" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT ?name
WHERE {
?p a foaf:Person ; foaf:name ?name .
FILTER REGEX(?name, "Greg") .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, qq(SELECT\n\ts5.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s4 LEFT JOIN Resources ljr1 ON (s4.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s4.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s4.subject = ljb1.ID),\n\tStatements s5 LEFT JOIN Resources ljr0 ON (s5.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s5.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s5.object = ljb0.ID)\nWHERE\n\t(ljl0.Value REGEXP 'Greg' OR ljr0.URI REGEXP 'Greg' OR ljb0.Name REGEXP 'Greg') AND\n\ts4.predicate = 2982895206037061277 AND\n\ts4.object = 3652866608875541952 AND\n\ts5.subject = s4.subject AND\n\ts5.predicate = 14911999128994829034), "select people by regex-filtered name" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT DISTINCT ?name
WHERE {
?p a foaf:Person ; foaf:name ?name .
FILTER REGEX(?name, "Greg") .
}
LIMIT 1
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, qq(SELECT DISTINCT\n\ts5.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s4 LEFT JOIN Resources ljr1 ON (s4.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s4.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s4.subject = ljb1.ID),\n\tStatements s5 LEFT JOIN Resources ljr0 ON (s5.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s5.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s5.object = ljb0.ID)\nWHERE\n\t(ljl0.Value REGEXP 'Greg' OR ljr0.URI REGEXP 'Greg' OR ljb0.Name REGEXP 'Greg') AND\n\ts4.predicate = 2982895206037061277 AND\n\ts4.object = 3652866608875541952 AND\n\ts5.subject = s4.subject AND\n\ts5.predicate = 14911999128994829034\nLIMIT 1), "select people by regex-filtered name with DISTINCT and LIMIT" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT DISTINCT ?name
WHERE {
?p a foaf:Person ; foaf:name ?name .
FILTER( ?name = "Gregory Todd Williams" )
}
LIMIT 1
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, qq(SELECT DISTINCT\n\ts7.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s6 LEFT JOIN Resources ljr1 ON (s6.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s6.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s6.subject = ljb1.ID),\n\tStatements s7 LEFT JOIN Resources ljr0 ON (s7.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s7.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s7.object = ljb0.ID)\nWHERE\n\t(SELECT value FROM Literals WHERE = ID LIMIT 1) = 'Gregory Todd Williams' AND\n\ts6.predicate = 2982895206037061277 AND\n\ts6.object = 3652866608875541952 AND\n\ts7.subject = s6.subject AND\n\ts7.predicate = 14911999128994829034\nLIMIT 1), "select people by Literal name with DISTINCT and LIMIT" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT DISTINCT ?name
WHERE {
?p a foaf:Person ; foaf:name ?name .
FILTER( ?p = )
}
LIMIT 1
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, qq(SELECT DISTINCT\n\ts5.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s4 LEFT JOIN Resources ljr1 ON (s4.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s4.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s4.subject = ljb1.ID),\n\tStatements s5 LEFT JOIN Resources ljr0 ON (s5.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s5.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s5.object = ljb0.ID)\nWHERE\n\t = 2954181085641959508 AND\n\ts4.predicate = 2982895206037061277 AND\n\ts4.object = 3652866608875541952 AND\n\ts5.subject = s4.subject AND\n\ts5.predicate = 14911999128994829034\nLIMIT 1), "select people by URI with DISTINCT and LIMIT" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name
WHERE {
?person foaf:name ?name .
FILTER BOUND(?name) .
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts4.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts4.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s4 LEFT JOIN Resources ljr0 ON (s4.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s4.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s4.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s4.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s4.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s4.object = ljb1.ID)\nWHERE\n\t IS NOT NULL AND\n\ts4.predicate = 14911999128994829034", "select people and names with filter BOUND()" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name
WHERE { ?person foaf:name ?name }
ORDER BY ?name
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID)\nWHERE\n\ts2.predicate = 14911999128994829034\nORDER BY\n\tname_Value ASC, name_URI ASC, name_Name ASC", "order by names" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
SELECT ?person ?name
WHERE { ?person foaf:name ?name }
ORDER BY ?name, ?person
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
throws_ok {
my $sql = $compiler->compile();
} 'RDF::Query::Error::CompilationError', 'order by multiple columns throws error';
}
{
my $parsed = $parser->parse(<<"END");
PREFIX foaf:
CONSTRUCT { ?person foaf:name ?name }
WHERE { ?person foaf:name ?name }
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed, 'model' );
throws_ok {
my $sql = $compiler->compile();
} 'RDF::Query::Error::CompilationError', 'non-select throws error';
}
{
my $parsed = $parser->parse(<<"END");
PREFIX time:
PREFIX foaf:
SELECT ?person ?name
WHERE { ?person foaf:name ?name }
ORDER BY time:now()
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
$compiler->add_function( 'time:now', sub {
my $self = shift;
my $parsed_vars = shift;
my $level = shift || \do{ my $a = 0 };
return ({}, [], ['NOW()']);
} );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID)\nWHERE\n\ts2.predicate = 14911999128994829034\nORDER BY\n\tNOW() ASC", "order by function (NOW())" );
}
{
my $parsed = $parser->parse(<<"END");
PREFIX func:
PREFIX foaf:
SELECT ?person ?name
WHERE { ?person foaf:name ?name }
ORDER BY func:ascii(?name)
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
$compiler->add_function( 'func:ascii', sub {
my $self = shift;
my $parsed_vars = shift;
my $level = shift || \do{ my $a = 0 };
my $expr = shift;
my $col = $self->expr2sql( $expr, $level );
return ({}, [], ["ASCII($col)"]);
} );
isa_ok( $compiler, 'RDF::Query::Compiler::SQL' );
my $sql = $compiler->compile();
is( $sql, "SELECT\n\ts2.subject AS person_Node,\n\tljr0.URI AS person_URI,\n\tljl0.Value AS person_Value,\n\tljl0.Language AS person_Language,\n\tljl0.Datatype AS person_Datatype,\n\tljb0.Name AS person_Name,\n\ts2.object AS name_Node,\n\tljr1.URI AS name_URI,\n\tljl1.Value AS name_Value,\n\tljl1.Language AS name_Language,\n\tljl1.Datatype AS name_Datatype,\n\tljb1.Name AS name_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.subject = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.subject = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.subject = ljb0.ID) LEFT JOIN Resources ljr1 ON (s2.object = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.object = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.object = ljb1.ID)\nWHERE\n\ts2.predicate = 14911999128994829034\nORDER BY\n\tASCII(ljr1.URI) ASC, ASCII(ljl1.Value) ASC, ASCII(ljl1.Language) ASC", "order by function (ASCII(name))" );
}
# if ($ENV{RDFQUERY_DEV_MYSQL}) {
# my $model_name = 'model';
# SKIP: {
# eval "require Kasei::RDF::Common;";
# if ($@) {
# warn $@;
# exit;
# # skip "Failed to load Kasei::RDF::Common", 1;
# }
#
# my $dsn = [ Kasei::Common::mysql_dbi_args() ];
#
# {
# my $model = DBI->connect( @$dsn );
# my $sparql = <<'END';
# SELECT ?s ?p ?o
# WHERE { ?s ?p ?o }
# LIMIT 1
# END
# lives_ok {
# my $query = new RDF::Query ( $sparql, undef, undef, 'sparql' );
# $query->execute( $model, model => $model_name, require_sql => 1 );
# } 's-p-o without pre-bound vars';
# }
#
# {
# Kasei::RDF::Common->import('mysql_model');
# my @myargs = Kasei::Common::mysql_upd();
# my $model = mysql_model( $model_name, @myargs[ 2, 0, 1 ] );
#
# {
# my $sparql = <<'END';
# SELECT ?s ?p ?o
# WHERE { ?s ?p ?o }
# LIMIT 1
# END
# lives_ok {
# my $query = new RDF::Query ( $sparql, undef, undef, 'sparql' );
# $query->execute( $model, dsn => $dsn, model => $model_name, require_sql => 1 );
# } 's-p-o without pre-bound vars';
#
# throws_ok {
# my $query = new RDF::Query ( $sparql, undef, undef, 'sparql' );
# $query->execute( $model, dsn => $dsn, model => $model_name, require_sql => 1, bind => { p => 1 } );
# } 'RDF::Query::Error::CompilationError', 's-p-o without pre-bound vars: forced sql compilation (expected) failure';
# }
#
# {
# my $query = new RDF::Query ( <<"END", undef, undef, 'sparql' );
# PREFIX geo:
# SELECT ?image ?point ?lat
# WHERE {
# ?point geo:lat ?lat .
# ?image ?pred ?point .
# FILTER( geo:distance(?point) ) .
# }
# END
# throws_ok {
# $query->execute( $model, dsn => $dsn, model => $model_name, require_sql => 1 );
# } 'RDF::Query::Error::CompilationError', 'forced sql compilation (expected) failure';
# }
#
# {
# print "# FILTER rage test\n";
# my $query = new RDF::Query ( <<"END", undef, undef, 'sparql' );
# PREFIX foaf:
# PREFIX geo:
# SELECT ?image ?point ?lat
# WHERE {
# ?image a foaf:Image ; ?pred ?point .
# ?point geo:lat ?lat .
# FILTER(
# (?pred = || ?pred = )
# && ?lat > 52
# && ?lat < 53
# ) .
# }
# END
# my $stream = $query->execute( $model, dsn => $dsn, model => $model_name );
#
# my $count;
# while (my $row = $stream->()) {
# my ($image, $point, $lat) = @{ $row };
# ok( $image->isa('RDF::Trine::Node::Resource'), 'image is resource');
# my $latv = ($lat) ? $lat->literal_value : undef;
# cmp_ok( $latv, '>', 52, 'lat: ' . $latv );
# cmp_ok( $latv, '<', 53, 'lat: ' . $latv );
# $count++;
# }
# }
#
# {
# print "# lots of points!\n";
# my $query = new RDF::Query ( <<"END", undef, undef, 'sparql' );
# PREFIX foaf:
# PREFIX geo:
# SELECT ?name
# WHERE {
# ?point a geo:Point; foaf:name ?name .
# }
# END
# my $stream = $query->execute( $model, dsn => $dsn, model => $model_name );
# isa_ok( $stream, 'CODE', 'stream' );
# my $count;
# while (my $row = $stream->()) {
# my ($node) = @{ $row };
# my $name = $node->as_string;
# ok( $name, $name );
# } continue { last if ++$count >= 100 };
# }
#
# {
# print "# foaf:Person ORDER BY name\n";
# my $query = new RDF::Query ( <<"END", undef, undef, 'sparql' );
# PREFIX foaf:
# PREFIX geo:
# SELECT DISTINCT ?p ?name
# WHERE {
# ?p a foaf:Person; foaf:name ?name
# }
# ORDER BY ?name
# END
# my $stream = $query->execute( $model, dsn => $dsn, model => $model_name );
# isa_ok( $stream, 'CODE', 'stream' );
# my ($count, $last);
# while (my $row = $stream->()) {
# my ($p, $node) = @{ $row };
# my $name = $node->as_string;
# if (defined($last)) {
# cmp_ok( $name, 'ge', $last, "In order: $name (" . $p->as_string . ")" );
# } else {
# ok( $name, "$name (" . $p->as_string . ")" );
# }
# $last = $name;
# } continue { last if ++$count >= 200 };
# }
#
# {
# print "# geo:Point ORDER BY longitude\n";
# my $query = new RDF::Query ( <<"END", undef, undef, 'sparql' );
# PREFIX foaf:
# PREFIX geo:
# PREFIX xsd:
# SELECT DISTINCT ?name ?lat ?lon
# WHERE {
# ?point a geo:Point; foaf:name ?name; geo:lat ?lat; geo:long ?lon
# }
# ORDER BY DESC( xsd:decimal(?lon) )
# END
# my $stream = $query->execute( $model, dsn => $dsn, model => $model_name );
# isa_ok( $stream, 'CODE', 'stream' );
# my ($count, $last);
# while (my $row = $stream->()) {
# my ($node, $lat, $long) = @{ $row };
# my $name = $node->as_string;
# if (defined($last)) {
# cmp_ok( $long->as_string, '<=', $last, "In order: $name (" . $long->as_string . ")" );
# } else {
# ok( $name, "$name (" . $long->as_string . ")" );
# }
# $last = $long->as_string;
# } continue { last if ++$count >= 200 };
# }
# }
# }
# }
# if ($ENV{RDFQUERY_DEV_POSTGRESQL}) {
# eval "require Kasei::RDF::Common;";
# $ENV{'POSTGRESQL_MODEL'} = 'model';
# $ENV{'POSTGRESQL_DATABASE'} = 'greg';
# $ENV{'POSTGRESQL_PASSWORD'} = 'password';
#
# Kasei::RDF::Common->import('postgresql_model');
# my $dbh = postgresql_model();
# warn $dbh;
#
# my @myargs = Kasei::Common::postgresql_upd();
# my $model = postgresql_model( 'db1', @myargs[ 2, 0, 1 ] );
# my $dsn = [ Kasei::Common::postgresql_dbi_args() ];
#
# warn $model;
# warn Dumper($dsn);
#
#
# }
__END__
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT ?name
WHERE {
?p a foaf:Person .
?p foaf:name ?name .
FILTER( ?p = _:r1101876070r10 )
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
is( $sql, qq(SELECT\n\ts2.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr1 ON (s2.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.subject = ljb1.ID),\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.object = ljb0.ID)\nWHERE\n\ts2.predicate = 2982895206037061277 AND\n\ts2.object = 3652866608875541952 AND\n\ts2.subject = s2.subject AND\n\ts2.predicate = 14911999128994829034 AND\n\ts2.subject = 4025741532186680712), "select people by BNode" );
}
{
my $parsed = $parser->parse(<<'END');
PREFIX foaf:
SELECT ?name
WHERE {
?p a foaf:Person ; foaf:name ?name .
FILTER( ?p = [] )
}
END
my $compiler = RDF::Query::Compiler::SQL->new( $parsed );
my $sql = $compiler->compile();
$sql =~ s/(s2.subject\s*=\s*)\d+/$1XXX/;
is( $sql, qq(SELECT\n\ts2.object AS name_Node,\n\tljr0.URI AS name_URI,\n\tljl0.Value AS name_Value,\n\tljl0.Language AS name_Language,\n\tljl0.Datatype AS name_Datatype,\n\tljb0.Name AS name_Name,\n\tljr1.URI AS p_URI,\n\tljl1.Value AS p_Value,\n\tljl1.Language AS p_Language,\n\tljl1.Datatype AS p_Datatype,\n\tljb1.Name AS p_Name\nFROM\n\tStatements s2 LEFT JOIN Resources ljr1 ON (s2.subject = ljr1.ID) LEFT JOIN Literals ljl1 ON (s2.subject = ljl1.ID) LEFT JOIN Bnodes ljb1 ON (s2.subject = ljb1.ID),\n\tStatements s2 LEFT JOIN Resources ljr0 ON (s2.object = ljr0.ID) LEFT JOIN Literals ljl0 ON (s2.object = ljl0.ID) LEFT JOIN Bnodes ljb0 ON (s2.object = ljb0.ID)\nWHERE\n\ts2.predicate = 2982895206037061277 AND\n\ts2.object = 3652866608875541952 AND\n\ts2.subject = s2.subject AND\n\ts2.predicate = 14911999128994829034 AND\n\ts2.subject = XXX), "select people by BNode" );
}
RDF-Query-2.918/xt/dev-time-intervals.t 000644 000765 000024 00000006527 13033227174 017715 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use Test::More;
use Test::Exception;
use Scalar::Util qw(refaddr);
use RDF::Query;
if ($ENV{RDFQUERY_TIMETEST}) {
plan qw(no_plan);
} else {
plan skip_all => 'Developer tests. Set RDFQUERY_TIMETEST to run these tests.';
return;
}
use lib qw(. t);
BEGIN { require "models.pl"; }
my $debug = 1;
my @files = map { "data/$_" } qw(temporal.rdf);
my @models = test_models( @files );
my $tests = 0;
my $find_interval = <<"END";
PREFIX xsd:
PREFIX t:
SELECT ?interval ?b ?e
WHERE {
{
?interval a t:Interval ;
t:begins ?b ; t:ends ?e .
FILTER( ?b <= "%s"^^xsd:dateTime && ?e > "%s"^^xsd:dateTime )
} UNION {
?interval a t:Interval ;
t:begins ?b .
OPTIONAL { ?interval t:ends ?e } .
FILTER( !BOUND(?e) ) .
FILTER( ?b <= "%s"^^xsd:dateTime )
} UNION {
?interval a t:Interval .
OPTIONAL { ?interval t:begins ?b } .
?interval t:ends ?e .
FILTER( !BOUND(?b) ) .
FILTER( ?e > "%s"^^xsd:dateTime )
} UNION {
?interval a t:Interval .
OPTIONAL { ?interval t:begins ?b } .
OPTIONAL { ?interval t:ends ?e } .
FILTER( !BOUND(?b) && !BOUND(?e) ) .
}
}
END
foreach my $model (@models) {
print "\n#################################\n";
print "### Using model: $model\n";
{
# find intervals that contain a specific date
my $dt = '1999-06-01';
my $sparql = sprintf( $find_interval, ($dt) x 4 );
my $query = RDF::Query->new( $sparql, undef, undef, 'sparql' );
my $stream = $query->execute( $model );
my $count = 0;
while (my $data = $stream->next) {
my $interval = $data->[0];
ok( $interval->isa('RDF::Trine::Node'), 'time-intervals' );
like( $interval->uri_value, qr/#yearTo2000/, 'time-intervals: 1999' );
$count++;
}
is( $count, 1, '1999: correct count of matching intervals' );
}
{
# find intervals that contain a specific date
my $dt = '2000-06-01';
my $sparql = sprintf( $find_interval, ($dt) x 4 );
my $query = RDF::Query->new( $sparql, undef, undef, 'sparql' );
my $stream = $query->execute( $model );
my $count = 0;
while (my $data = $stream->next) {
my $interval = $data->[0];
ok( $interval->isa('RDF::Trine::Node'), 'time-intervals' );
like( $interval->uri_value, qr/#year2000/, 'time-intervals: 2000' );
$count++;
}
is( $count, 1, '2000: correct count of matching intervals' );
}
{
# find intervals that contain a specific date
my $dt = '2002-06-01';
my $sparql = sprintf( $find_interval, ($dt) x 4 );
my $query = RDF::Query->new( $sparql, undef, undef, 'sparql' );
my $stream = $query->execute( $model );
my $count = 0;
while (my $data = $stream->next) {
my $interval = $data->[0];
$count++;
}
is( $count, 0, '2002: correct count of matching intervals' );
}
{
# find intervals that contain a specific date
my $dt = '2005-06-01';
my $sparql = sprintf( $find_interval, ($dt) x 4 );
my $query = RDF::Query->new( $sparql, undef, undef, 'sparql' );
my $stream = $query->execute( $model );
my $count = 0;
while (my $data = $stream->next) {
my $interval = $data->[0];
ok( $interval->isa('RDF::Trine::Node'), 'time-intervals' );
like( $interval->uri_value, qr/#yearFrom2003/, 'time-intervals: 2005' );
$count++;
}
is( $count, 1, '2005: correct count of matching intervals' );
}
}
RDF-Query-2.918/xt/federate.t 000644 000765 000024 00000033113 13033227174 015744 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
use Test::More;
plan skip_all => "QUERY FEDERATION isn't implemented";
# use Config;
# use URI::file;
# use Test::More;
# use Data::Dumper;
#
# use RDF::Query;
# use RDF::Query::Util;
# use RDF::Query::Algebra;
# use RDF::Query::Federate;
# use RDF::Query::Error qw(:try);
# use RDF::Query::ServiceDescription;
#
# use RDF::Trine::Parser;
# use RDF::Trine::Namespace qw(rdf foaf);
#
# use lib qw(. t);
# BEGIN { require "models.pl"; }
#
# my $eval_tests = 3;
# my $rewrite_tests = 4;
# my $run_eval_tests = 1;
#
# if (not $ENV{RDFQUERY_DEV_TESTS}) {
# plan skip_all => 'Developer tests. Set RDFQUERY_DEV_TESTS to run these tests.';
# return;
# }
#
# plan tests => ($eval_tests + $rewrite_tests);
#
# my $reason;
# eval { require LWP::Simple };
# if ($@) {
# $run_eval_tests = 0;
# $reason = "LWP::Simple is not available for loading URLs";
# }
#
# eval { require RDF::Endpoint::Server };
# if ($@) {
# $run_eval_tests = 0;
# $reason = "RDF::Endpoint::Server is not available";
# }
#
# ################################################################################
# # Log::Log4perl::init( \q[
# # # log4perl.category.rdf.query.federate.plan = TRACE, Screen
# # log4perl.category.rdf.query.plan.thresholdunion = TRACE, Screen
# # # log4perl.category.rdf.query.servicedescription = DEBUG, Screen
# #
# # log4perl.appender.Screen = Log::Log4perl::Appender::Screen
# # log4perl.appender.Screen.stderr = 0
# # log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout
# # ] );
# ################################################################################
#
# my $quit_sig = 1;
# my @sigs = split(' ', $Config{sig_name});
# foreach my $i (0 .. $#sigs) {
# if ($sigs[$i] eq 'QUIT') {
# $quit_sig = $i;
# last;
# }
# }
# my %named = map { $_ => File::Spec->rel2abs("data/federation_data/$_") } qw(alice.rdf bob.rdf);
# my %models = map { $_ => RDF::Query::Util::make_model( {}, $named{$_} ) } (keys %named);
#
#
# ################################################################################
#
# run_tests();
#
# ################################################################################
#
# sub run_tests {
# simple_optimistic_bgp_rewriting_test();
# simple_optimistic_bgp_rewriting_test_with_threshold_time();
# overlapping_optimistic_bgp_rewriting_test_1();
# overlapping_optimistic_bgp_rewriting_test_2();
#
# SKIP: {
# skip $reason, $eval_tests unless ($run_eval_tests);
# simple_optimistic_bgp_rewriting_execution_test();
# }
# }
#
# sub simple_optimistic_bgp_rewriting_test {
# ### in this test, two services are used, both of which support the two triple patterns.
# ### we're expecting the optimistic QEP to send the whole 2-triple BGP to each service
# ### as a whole, and then fall back on joining the two triple patterns locally.
#
# my $alice_sd = local_sd( 'alice.rdf', 8889, 'http://work.example/people/', 5, [qw(rdf:type foaf:knows)] );
# my $bob_sd = local_sd( 'bob.rdf', 8891, 'http://oldcorp.example.org/bob/', 4, [qw(rdf:type foaf:knows)] );
# my $query = RDF::Query::Federate->new( <<"END", { optimize => 1 } );
# PREFIX foaf:
# SELECT ?p ?knows WHERE {
# ?p foaf:knows ?knows .
# ?knows a foaf:Person .
# }
# END
# $query->add_service( $alice_sd );
# $query->add_service( $bob_sd );
# my ($plan, $ctx) = $query->prepare();
# my $sse = $plan->sse({}, ' ');
# is( _CLEAN_WS($sse), _CLEAN_WS(<<'END'), 'expected optimistic federation query plan' );
# (project (p knows) (threshold-union 0
# (service "PREFIX foaf: \nSELECT * WHERE {\n\t?p foaf:knows ?knows .\n\t?knows a foaf:Person .\n}")
# (service "PREFIX foaf: \nSELECT * WHERE {\n\t?p foaf:knows ?knows .\n\t?knows a foaf:Person .\n}")
# (bind-join
# (triple ?knows )
# (triple ?p ?knows))))
# END
# ### If we were to start an RDF::Endpoint server on the appropriate ports, this should work:
# # my $iter = $query->execute_plan( $plan, $ctx );
# # while (my $row = $iter->next) {
# # print "$row\n";
# # }
# }
#
# sub simple_optimistic_bgp_rewriting_test_with_threshold_time {
# ### this test is the same as simple_optimistic_bgp_rewriting_test() above,
# ### but we use a 'optimistic_threshold_time' flag in the constructor, which
# ### should come back out in the sse serialization of the thresholdtime QEP.
#
# my $alice_sd = local_sd( 'alice.rdf', 8889, 'http://work.example/people/', 5, [qw(rdf:type foaf:knows)] );
# my $bob_sd = local_sd( 'bob.rdf', 8891, 'http://oldcorp.example.org/bob/', 4, [qw(rdf:type foaf:knows)] );
# my $query = RDF::Query::Federate->new( <<"END", { optimize => 1, optimistic_threshold_time => 3 } );
# PREFIX foaf:
# SELECT ?p ?knows WHERE {
# ?p foaf:knows ?knows .
# ?knows a foaf:Person .
# }
# END
# $query->add_service( $alice_sd );
# $query->add_service( $bob_sd );
# my ($plan, $ctx) = $query->prepare();
# my $sse = $plan->sse({}, ' ');
# is( _CLEAN_WS($sse), _CLEAN_WS(<<'END'), 'expected optimistic federation query plan' );
# (project (p knows)
# (threshold-union 3
# (service "PREFIX foaf: \nSELECT * WHERE {\n\t?p foaf:knows ?knows .\n\t?knows a foaf:Person .\n}")
# (service "PREFIX foaf: \nSELECT * WHERE {\n\t?p foaf:knows ?knows .\n\t?knows a foaf:Person .\n}")
# (bind-join
# (triple ?knows )
# (triple ?p ?knows))
# )
# )
# END
# }
#
# sub overlapping_optimistic_bgp_rewriting_test_1 {
# ### this test uses four endpoint service descriptions, with overlapping
# ### coverage of five predicates:
# ### service \ predicate: P Q R S T
# ### a * * *
# ### b * * *
# ### c * * *
# ### d * *
# ### no single endpoint can answer the whole query, involving a BGP with
# ### 3 triple patterns, but endpoint 'a' can answer a two-triple-pattern
# ### subquery (predicates P and Q), then joining with results from endpoint
# ### 'd' (the single triple-pattern with predicate T).
# my @names = ('a' .. 'd');
# my %preds = (
# a => [qw(P Q R)],
# b => [qw(Q R S)],
# c => [qw(R S P)],
# d => [qw(S T)],
# );
# my %sd = map {
# my $port = 10000 + (ord($_) - ord('a'));
# $_ => local_sd( $_, $port, "http://${_}.example.com/", 5, [ map { "ex:$_" } @{ $preds{ $_ } } ] );
# } @names;
# my $query = RDF::Query::Federate->new( <<"END", { optimize => 1 } );
# PREFIX ex:
# SELECT * WHERE {
# ?v ex:P ?p ;
# ex:Q ?q ;
# ex:T ?t .
# }
# END
# while (my ($name,$sd) = each(%sd)) {
# $query->add_service( $sd );
# }
# my ($plan, $ctx) = $query->prepare();
# my $sse = $plan->sse({}, ' ');
# is( _CLEAN_WS($sse), _CLEAN_WS(<<'END'), 'expected optimistic federation query plan (1)' );
# (project (v p q t)
# (threshold-union 0
# (nestedloop-join
# (service "PREFIX ex: \nSELECT * WHERE {\n\t?v ex:P ?p .\n\t?v ex:Q ?q .\n}")
# (service "PREFIX ex: \nSELECT * WHERE {\n\t?v ex:T ?t .\n}"))
# (bind-join
# (bind-join
# (triple ?v ?t)
# (triple ?v ?q))
# (triple ?v ?p))
# )
# )
# END
# }
#
# sub overlapping_optimistic_bgp_rewriting_test_2 {
# ### this test uses two endpoint service descriptions, with overlapping
# ### coverage of four predicates:
# ### service \ predicate: P Q R S
# ### a * * *
# ### b * * *
# ### no single endpoint can answer the whole query, involving a BGP with
# ### 4 triple patterns, but each endpoint can answer a three-triple-pattern
# ### subquery, then joining with results with a single-triple-pattern query
# ### from the other endpoint.
# my @names = (qw(a b));
# my %preds = (
# a => [qw(P Q R)],
# b => [qw(Q R S)],
# );
# my %sd = map {
# my $port = 10000 + (ord($_) - ord('a'));
# $_ => local_sd( $_, $port, "http://${_}.example.com/", 5, [ map { "ex:$_" } @{ $preds{ $_ } } ] );
# } @names;
# my $query = RDF::Query::Federate->new( <<"END", { optimize => 1 } );
# PREFIX ex:
# SELECT * WHERE {
# ?v ex:P ?p ;
# ex:Q ?q ;
# ex:R ?t ;
# ex:S ?s .
# }
# END
# while (my ($name,$sd) = each(%sd)) {
# $query->add_service( $sd );
# }
# my $ctx = RDF::Query::ExecutionContext->new(
# query => $query,
# optimize => 1,
# model => RDF::Trine::Model->temporary_model,
# optimistic_threshold_time => 2,
# );
# my @plans = $query->query_plan( $ctx );
# my $plan = $plans[0];
# my $sse = $plan->sse({}, ' ');
# is( _CLEAN_WS($sse), _CLEAN_WS(<<'END'), 'expected optimistic federation query plan (2)' );
# (project (v p q t s)
# (threshold-union 2
# (nestedloop-join
# (service "SELECT * WHERE {\n\t?v ?p .\n\t?v ?q .\n\t?v ?t .\n}")
# (triple ?v ?s))
# (nestedloop-join
# (service "SELECT * WHERE {\n\t?v ?q .\n\t?v ?t .\n\t?v ?s .\n}")
# (triple ?v ?p))
# (bind-join
# (bind-join (bind-join (triple ?v ?s) (triple ?v ?t)) (triple ?v ?q))
# (triple ?v ?p))
# )
# )
# END
# }
#
# sub simple_optimistic_bgp_rewriting_execution_test {
# my %ports = qw(alice.rdf 8889 bob.rdf 8891);
# my $alice_sd = local_sd( 'alice.rdf', 8889, 'http://work.example/people/', 5, [qw(rdf:type foaf:knows foaf:name)] );
# my $bob_sd = local_sd( 'bob.rdf', 8891, 'http://oldcorp.example.org/bob/', 4, [qw(rdf:type foaf:knows foaf:name)] );
# my $query = RDF::Query::Federate->new( <<"END", { optimize => 1, optimistic_threshold_time => 0 } );
# PREFIX foaf:
# SELECT ?p ?name WHERE {
# ?p foaf:knows ?knows ; foaf:name ?name.
# }
# END
# $query->add_service( $alice_sd );
# $query->add_service( $bob_sd );
# my ($plan, $ctx) = $query->prepare();
#
# my %pids;
# while (my($name, $model) = each(%models)) {
# my $pid = start_endpoint_for_service( $ports{ $name }, $model );
# $pids{ $name } = $pid;
# }
#
# my $iter = $query->execute_plan( $plan, $ctx );
#
# my %names;
# my %origins;
# my $counter = 0;
# while (my $row = $iter->next) {
# my $orig = join(',', sort @{ $row->label('origin') });
# $origins{ $orig }++;
# $counter++;
# $names{ $row->{name}->literal_value }++;
# }
#
# # we expect to find:
# # - one result with name=Bob from the optimistic BGP sent to bob's server on port 8891
# # - one result with name=Alice from alice's server on port 8889
# # - two results from the local join that merges data from both servers, one with name=Alice, and one with name=Bob
# is( $counter, 4, 'expected result count with duplicates from optimistic execution' );
# is_deeply( \%names, { Bob => 2, Alice => 2 }, 'expected duplicate result counts per result' );
# is_deeply( \%origins, { 'http://127.0.0.1:8889/sparql' => 2, 'http://127.0.0.1:8891/sparql' => 2 }, 'expected originating endpoint distribution' );
#
# while (my($name, $pid) = each(%pids)) {
# kill_endpoint( $pid, $quit_sig );
# }
# sleep 1;
# }
#
# sub start_endpoint_for_service {
# my $req_port = shift;
# my $model = shift;
# my ($pid, $port) = RDF::Query::Util::start_endpoint( $model, $req_port++, '../RDF-Endpoint/include' );
# return $pid;
# }
#
# sub kill_endpoint {
# my $pid = shift;
# my $quit_sig = shift;
# my $sent = kill( $quit_sig, $pid );
# }
#
# sub local_sd {
# my $name = shift;
# my $port = shift;
# my $base = shift;
# my $size = shift;
# my $preds = shift || [];
# my $pred_rdf = join("\n\t", map { "sd:capability [ sd:predicate $_ ] ;" } @$preds);
# my $rdf = sprintf( <<'END', $name, $port, $size, $pred_rdf );
# @prefix rdfs: .
# @prefix rdf: .
# @prefix xsd: .
# @prefix sd: .
# @prefix foaf: .
# @prefix saddle: .
# @prefix sparql: .
# @prefix geo: .
# @prefix exif: .
# @prefix dc: .
# @prefix dcterms: .
# @prefix ex: .
#
# # definition of an endpoint
# [] a sd:Service ;
# rdfs:label "SPARQL Endpoint for data from %s" ;
# sd:url ;
# sd:totalTriples %d ;
# %s
# .
# END
# my $store = RDF::Trine::Store::DBI->temporary_store();
# my $model = RDF::Trine::Model->new( $store );
# my $parser = RDF::Trine::Parser->new('turtle');
# $parser->parse_into_model( $base, $rdf, $model );
# return RDF::Query::ServiceDescription->new_with_model( $model );
# }
#
# sub _CLEAN_WS {
# my $string = shift;
# $string =~ s/^\s+//;
# chomp($string);
# for ($string) {
# s/\s+/ /g;
# 1 while s/[)]\s+[)]/))/g;
# }
# return $string;
# }
RDF-Query-2.918/xt/parser-rdql.t 000644 000765 000024 00000021156 13033227174 016425 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use Test::More tests => 5;
use RDF::Query::Node qw(variable);
use_ok( 'RDF::Query::Parser::RDQL' );
my $parser = new RDF::Query::Parser::RDQL (undef);
isa_ok( $parser, 'RDF::Query::Parser::RDQL' );
{
my $rdql = <<"END";
SELECT
?page
WHERE
(?person foaf:name "Gregory Todd Williams")
(?person foaf:homepage ?page)
USING
rdf FOR ,
foaf FOR ,
dcterms FOR ,
geo FOR
END
my $correct = {
'triples' => [
bless( [
bless( [
bless( [
bless( [
'person'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://xmlns.com/foaf/0.1/name'
], 'RDF::Query::Node::Resource' ),
bless( [
'Gregory Todd Williams'
], 'RDF::Query::Node::Literal' )
], 'RDF::Query::Algebra::Triple' ),
bless( [
bless( [
'person'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://xmlns.com/foaf/0.1/homepage'
], 'RDF::Query::Node::Resource' ),
bless( [
'page'
], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::GroupGraphPattern' ),
[
bless( [
'page'
], 'RDF::Query::Node::Variable' )
]
], 'RDF::Query::Algebra::Project' )
],
'sources' => undef,
'variables' => [
bless( [
'page'
], 'RDF::Query::Node::Variable' )
],
'method' => 'SELECT',
'namespaces' => {
'geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#',
'foaf' => 'http://xmlns.com/foaf/0.1/',
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'dcterms' => 'http://purl.org/dc/terms/'
}
};
my $parsed = $parser->parse( $rdql );
is_deeply( $parsed, $correct, 'SELECT, WHERE, USING' );
}
{
my $rdql = <<"END";
SELECT
?image ?point ?lat
WHERE
(?point geo:lat ?lat)
(?image ?pred ?point)
AND
(?pred == || ?pred == )
AND
?lat > 52.988674,
?lat < 53.036526
USING
rdf FOR ,
foaf FOR ,
dcterms FOR ,
geo FOR
END
my $correct = {
method => 'SELECT',
'triples' => [
bless( [
bless( [
'FILTER',
bless( [
bless( [
'URI',
'sparql:logical-and'
], 'RDF::Query::Node::Resource' ),
bless( [
bless( [
'URI',
'sparql:logical-or'
], 'RDF::Query::Node::Resource' ),
bless( [
'==',
bless( [
'pred'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://purl.org/dc/terms/spatial'
], 'RDF::Query::Node::Resource' )
], 'RDF::Query::Expression::Binary' ),
bless( [
'==',
bless( [
'pred'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://xmlns.com/foaf/0.1/based_near'
], 'RDF::Query::Node::Resource' )
], 'RDF::Query::Expression::Binary' )
], 'RDF::Query::Expression::Function' ),
bless( [
'>',
bless( [
'lat'
], 'RDF::Query::Node::Variable' ),
bless( [
'52.988674',
undef,
'http://www.w3.org/2001/XMLSchema#float'
], 'RDF::Query::Node::Literal' )
], 'RDF::Query::Expression::Binary' )
], 'RDF::Query::Expression::Function' ),
bless( [
bless( [
bless( [
'point'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://www.w3.org/2003/01/geo/wgs84_pos#lat'
], 'RDF::Query::Node::Resource' ),
bless( [
'lat'
], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' ),
bless( [
bless( [
'image'
], 'RDF::Query::Node::Variable' ),
bless( [
'pred'
], 'RDF::Query::Node::Variable' ),
bless( [
'point'
], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::GroupGraphPattern' )
], 'RDF::Query::Algebra::Filter' ),
[
bless( [
'image'
], 'RDF::Query::Node::Variable' ),
bless( [
'point'
], 'RDF::Query::Node::Variable' ),
bless( [
'lat'
], 'RDF::Query::Node::Variable' )
]
], 'RDF::Query::Algebra::Project' )
],
'sources' => undef,
'namespaces' => {'foaf' => 'http://xmlns.com/foaf/0.1/','geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#','dcterms' => 'http://purl.org/dc/terms/','rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'},
'variables' => [variable('image'),variable('point'),variable('lat')]
};
my $parsed = $parser->parse( $rdql );
is_deeply( $parsed, $correct, 'VarUri EQ OR constraint, numeric comparison constraint' );
}
{
my $rdql = <<"END";
SELECT
?person ?homepage
WHERE
(?person foaf:name "Gregory Todd Williams")
(?person foaf:homepage ?homepage)
AND
?homepage ~~ /kasei/
USING
rdf FOR ,
foaf FOR ,
dcterms FOR ,
geo FOR
END
my $correct = {
method => 'SELECT',
'triples' => [
bless( [
bless( [
'FILTER',
bless( [
bless( [
'URI',
'sparql:regex'
], 'RDF::Query::Node::Resource' ),
bless( [
'homepage'
], 'RDF::Query::Node::Variable' ),
bless( [
'kasei'
], 'RDF::Query::Node::Literal' )
], 'RDF::Query::Expression::Function' ),
bless( [
bless( [
bless( [
'person'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://xmlns.com/foaf/0.1/name'
], 'RDF::Query::Node::Resource' ),
bless( [
'Gregory Todd Williams'
], 'RDF::Query::Node::Literal' )
], 'RDF::Query::Algebra::Triple' ),
bless( [
bless( [
'person'
], 'RDF::Query::Node::Variable' ),
bless( [
'URI',
'http://xmlns.com/foaf/0.1/homepage'
], 'RDF::Query::Node::Resource' ),
bless( [
'homepage'
], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::GroupGraphPattern' )
], 'RDF::Query::Algebra::Filter' ),
[
bless( [
'person'
], 'RDF::Query::Node::Variable' ),
bless( [
'homepage'
], 'RDF::Query::Node::Variable' )
]
], 'RDF::Query::Algebra::Project' )
],
'namespaces' => {'foaf' => 'http://xmlns.com/foaf/0.1/','rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#','geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#','dcterms' => 'http://purl.org/dc/terms/'},
'sources' => undef,
'variables' => [bless(['person'], 'RDF::Query::Node::Variable'),bless(['homepage'], 'RDF::Query::Node::Variable')]
};
my $parsed = $parser->parse( $rdql );
is_deeply( $parsed, $correct, 'regex constraint' );
}
RDF-Query-2.918/xt/parser-sparql.t 000644 000765 000024 00000531231 13033227174 016765 0 ustar 00greg staff 000000 000000 #!/usr/bin/env perl
use strict;
use warnings;
no warnings 'redefine';
use utf8;
use Test::More tests => 156;
use YAML;
use Data::Dumper;
use Scalar::Util qw(reftype);
use RDF::Query;
use_ok( 'RDF::Query::Parser::SPARQL' );
my $parser = new RDF::Query::Parser::SPARQL ();
isa_ok( $parser, 'RDF::Query::Parser::SPARQL' );
my (@data) = YAML::Load(do { local($/) = undef; });
foreach (@data) {
next unless (reftype($_) eq 'ARRAY');
my ($name, $sparql, $correct) = @$_;
my $parsed = $parser->parse( $sparql );
my $r = is_deeply( $parsed, $correct, $name );
unless ($r) {
warn 'PARSE ERROR: ' . $parser->error;
# my $triples = $parsed->{triples} || [];
# foreach my $t (@$triples) {
# warn $t->as_sparql . "\n";
# }
# warn Dumper($parsed);
my $dump = YAML::Dump($parsed);
$dump =~ s/\n/\n /g;
warn $dump;
exit;
}
}
sub _____PATTERNS______ {}
##### PATTERNS
{
my $pattern = $parser->parse_pattern( "{ ?s ?p ?o }" );
isa_ok( $pattern, 'RDF::Query::Algebra::GroupGraphPattern' );
my $expect = bless( [
bless( [
bless( [
bless( [ 's' ], 'RDF::Query::Node::Variable' ),
bless( [ 'p' ], 'RDF::Query::Node::Variable' ),
bless( [ 'o' ], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::BasicGraphPattern' )
], 'RDF::Query::Algebra::GroupGraphPattern' );
is_deeply( $pattern, $expect, 'GGP with variables' );
}
{
my $pattern = $parser->parse_pattern( "{ ?s a ?o }" );
isa_ok( $pattern, 'RDF::Query::Algebra::GroupGraphPattern' );
my $expect = bless( [
bless( [
bless( [
bless( [ 's' ], 'RDF::Query::Node::Variable' ),
bless( [ 'URI', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ], 'RDF::Query::Node::Resource' ),
bless( [ 'o' ], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::BasicGraphPattern' )
], 'RDF::Query::Algebra::GroupGraphPattern' );
is_deeply( $pattern, $expect, 'GGP with variables and Verb' );
}
{
my $pattern = $parser->parse_pattern( "{ ?s a foaf:Person ; foaf:name ?o }", undef, { foaf => 'http://xmlns.com/foaf/0.1/' } );
isa_ok( $pattern, 'RDF::Query::Algebra::GroupGraphPattern' );
my $expect = bless( [
bless( [
bless( [
bless( [ 's' ], 'RDF::Query::Node::Variable' ),
bless( [ 'URI', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ], 'RDF::Query::Node::Resource' ),
bless( [ 'URI', 'http://xmlns.com/foaf/0.1/Person' ], 'RDF::Query::Node::Resource' ),
], 'RDF::Query::Algebra::Triple' ),
bless( [
bless( [ 's' ], 'RDF::Query::Node::Variable' ),
bless( [ 'URI', 'http://xmlns.com/foaf/0.1/name' ], 'RDF::Query::Node::Resource' ),
bless( [ 'o' ], 'RDF::Query::Node::Variable' )
], 'RDF::Query::Algebra::Triple' )
], 'RDF::Query::Algebra::BasicGraphPattern' )
], 'RDF::Query::Algebra::GroupGraphPattern' );
is_deeply( $pattern, $expect, 'GGP with multiple triples and QName' );
}
sub _____ERRORS______ {}
##### ERRORS
{
my $sparql = <<"END";
# Multiple DOTs
SELECT * WHERE
{ ?s ?p ?o .. }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'syn-bad-09.rq: Extra dot after triple' );
like( $parser->error, qr/Syntax error/, 'got error: Extra dot after triple' );
}
{
my $sparql = <<"END";
# DOT, no triples
SELECT * WHERE
{ . }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'Extra dot in empty GGP' );
like( $parser->error, qr/Syntax error/, 'got error: Extra dot in empty GGP' );
}
{
my $sparql = <<"END";
# Missing DOT between triples
PREFIX :
SELECT *
{ :s1 :p1 :o1 :s2 :p2 :o2 . }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'Missing DOT between triples' );
like( $parser->error, qr/Syntax error/, 'got error: Missing DOT between triples' );
}
{
my $sparql = <<"END";
PREFIX rdf:
SELECT ?node
WHERE {
?node rdf:type .
}
extra stuff
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'extra input after query' );
like( $parser->error, qr/Remaining input/, 'got error: remaining input' );
}
{
my $sparql = <<"END";
PREFIX dc10:
PREFIX dc11:
SELECT ?title ?author
WHERE {
{ ?book dc10:title ?title . ?book dc10:creator ?author }
UNION
?foo
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing union part' );
like( $parser->error, qr/Expected GroupGraphPattern/, 'got error: Expected GroupGraphPattern' );
}
{
my $sparql = <<"END";
PREFIX dc10:
PREFIX dc11:
SELECT ?title ?author
WHERE {
?book dc10:title ?title .
?book dc10:creator ?author .
FILTER
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing filter' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/^Expected FILTER declaration/, 'got expected error' );
}
{
my $sparql = <<"END";
PREFIX dc10:
PREFIX dc11:
SELECT ?title ?author
WHERE {
?book dc10:title ?title .
FILTER( ?title = ) .
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'bad syntax in filter' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/^Expecting numeric expression/, 'got expected error' );
}
{
my $sparql = <<"END";
PREFIX dc10:
PREFIX dc11:
SELECT ?title ?author
WHERE {
?book dc10:title ?title .
FILTER( ?title = foo ) .
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'bad syntax in filter' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/^Expecting ":"/, 'got expected error' );
}
{
my $sparql = <<"END";
PREFIX dc:
SELECT ?title ?author
WHERE {
?book dc:title ?title ; dc:identifier ?id .
FILTER( ?id < 2 * ) .
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'bad syntax in filter' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/^Expecting unary expression after '*'/, 'got expected error' );
}
{
my $sparql = <<"END";
PREFIX foaf:
SELECT ?x
WHERE { (1 2) foaf:name }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing object' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/Expecting object after predicate/, 'parse error' );
}
{
my $sparql = <<"END";
PREFIX foaf:
SELECT ?x
WHERE { [] foaf:name }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing object' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/Expecting object after predicate/, 'parse error' );
}
{
my $sparql = <<"END";
PREFIX foaf:
SELECT ?x
WHERE { ?x foaf:name }
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing object' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/Expecting object after predicate/, 'parse error' );
}
{
my $sparql = <<"END";
PREFIX rdf:
PREFIX foaf:
PREFIX dcterms:
PREFIX geo:
PREFIX mygeo:
SELECT ?image ?point ?lat
WHERE {
?point geo:lat ?lat .
FILTER( 10 > ?lat + )
}
END
my $parsed = $parser->parse( $sparql );
is( $parsed, undef, 'missing multiplicative expression' );
like( $parser->error, qr/^Syntax error/, 'got expected syntax error' ); # XXX
# like( $parser->error, qr/Expecting multiplicative expression after '[+]'/, 'parse error' );
}
{
my $sparql = <<"END";
PREFIX rdf:
PREFIX foaf: