<commit_before>package com.github.rdf_jena;

import org.apache.jena.graph.Node;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.apache.jena.query.Dataset;
import org.apache.jena.query.ReadWrite;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFLanguages;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.tdb.TDBFactory;
import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import java.io.*;
import java.util.Iterator;
import java.util.Optional;

import static com.github.rdf_jena.JenaConverters.*;
import static com.github.rdf_jena.JenaRepositoryService.findClass;
import static com.github.rdf_jena.RubyRDFConverters.convertQuad;
import static com.github.rdf_jena.TransactionUtil.executeInTransaction;
import static org.jruby.RubyBoolean.newBoolean;
import static org.jruby.RubyFixnum.newFixnum;
import static org.jruby.RubyString.newString;
import static org.jruby.RubySymbol.newSymbol;

@JRubyClass(name = "Repository")
public class Repository extends RubyObject {

    public static ObjectAllocator Allocator = Repository::new;

    /**
     * Jena {@link Dataset} backed by a TDB database. This state is should be
     * used as final within this Ruby Object.
     */
    protected Dataset ds;

    public Repository(Ruby runtime, RubyClass metaclass) {
        super(runtime, metaclass);
    }

    @JRubyMethod(name = "initialize", required = 1, optional = 1)
    public IRubyObject initialize(
            ThreadContext ctx,
            IRubyObject[] args
    ) {
        String datasetDirectory = args[0].asJavaString();
        ds                      = TDBFactory.createDataset(datasetDirectory);

        //Ruby ruby                      = ctx.runtime;
        //RubyHash options               = (args.length <= 1) ? RubyHash.newHash(ruby) : args[1].convertToHash();
        //Boolean someOption             = (Boolean) options.get(newSymbol(ruby, "some_option"));

        return ctx.nil;
    }

    @JRubyMethod(name = "durable?")
    public RubyBoolean isDurable(ThreadContext ctx) {
        return newBoolean(ctx.runtime, true);
    }

    @JRubyMethod(name = "empty?")
    public RubyBoolean isEmpty(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> newBoolean(ctx.runtime, ds.asDatasetGraph().isEmpty()));
    }

    @JRubyMethod(name = {"count", "size"})
    public RubyFixnum size(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> {
            Iterator<Quad> quads = ds.asDatasetGraph().find();
            long size = 0;
            while (quads.hasNext()) {
                quads.next(); size += 1;
            }
            return newFixnum(ctx.runtime, size);
        });
    }

    @JRubyMethod(name = {"graph_count", "graph_size"})
    public RubyFixnum graphSize(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> newFixnum(ctx.runtime, ds.asDatasetGraph().size()));
    }

    @JRubyMethod(name = {"each_statement", "each"})
    public IRubyObject iterateStatements(ThreadContext ctx, Block block) {
        if (block != Block.NULL_BLOCK) {
            executeInTransaction(ds, ReadWrite.READ, ds -> {
                Iterator<Quad> quads = ds.asDatasetGraph().find();
                while (quads.hasNext()) {
                    block.call(ctx, convertQuad(ctx, quads.next()));
                }
                return null;
            });
            return ctx.nil;
        } else {
            return callMethod(ctx, "enum_statement");
        }
    }

    @JRubyMethod(name = {"query_pattern"}, required = 1, optional = 1)
    public IRubyObject queryPattern(ThreadContext ctx, IRubyObject[] args, Block block) {
        if (block != Block.NULL_BLOCK) {
            IRubyObject statements = args[0];

            // argument 1; unused options

            executeInTransaction(ds, ReadWrite.READ, ds -> {
                Node[] nodePattern = convertRDFPattern(ctx, statements);
                DatasetGraph dg    = ds.asDatasetGraph();
                Iterator<Quad> quads;
                if (nodePattern == null) {
                    quads = dg.find();
                } else {
                    if (nodePattern[0] == null) {
                        nodePattern[0] = NodeFactory.createURI("urn:x-arq:DefaultGraph");
                    }
                    quads = dg.find(nodePattern[0], nodePattern[1], nodePattern[2], nodePattern[3]);
                }
                while (quads.hasNext()) {
                    block.call(ctx, convertQuad(ctx, quads.next()));
                }
                return null;
            });
            return ctx.nil;
        } else {
            IRubyObject[] enumArgs = new IRubyObject[args.length+1];
            enumArgs[0] = newSymbol(ctx.runtime, "query_pattern");
            System.arraycopy(args, 0, enumArgs, 1, args.length);
            return callMethod(ctx, "enum_for", enumArgs);
        }
    }

    @JRubyMethod(name = "has_statement?", required = 1)
    public RubyBoolean hasStatement(ThreadContext ctx, IRubyObject rdfStatement) {
        if (rdfStatement == null) {
            return newBoolean(ctx.runtime, false);
        }

        return executeInTransaction(ds, ReadWrite.READ, ds -> {
            Node[] nodePattern = convertRDFPattern(ctx, rdfStatement);
            if (nodePattern == null) {
                return newBoolean(ctx.runtime, false);
            }

            if (nodePattern[0] == null) {
                nodePattern[0] = NodeFactory.createURI("urn:x-arq:DefaultGraph");
            }
            return newBoolean(ctx.runtime, ds.asDatasetGraph().contains(
                    nodePattern[0], //graph
                    nodePattern[1], //subject
                    nodePattern[2], //predicate
                    nodePattern[3]  //object
            ));<commit_msg>added query_execute API; executes SPARQL strings<commit_after>package com.github.rdf_jena;

import org.apache.jena.graph.Node;
import org.apache.jena.graph.Graph;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.apache.jena.query.*;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.RDFNode;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RDFLanguages;
import org.apache.jena.sparql.core.DatasetGraph;
import org.apache.jena.sparql.core.Quad;
import org.apache.jena.sparql.graph.GraphFactory;
import org.apache.jena.tdb.TDBFactory;
import org.jruby.*;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.exceptions.RaiseException;
import org.jruby.runtime.Block;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;

import static com.github.rdf_jena.JenaConverters.*;
import static com.github.rdf_jena.JenaRepositoryService.findClass;
import static com.github.rdf_jena.RubyRDFConverters.convertNode;
import static com.github.rdf_jena.RubyRDFConverters.convertQuad;
import static com.github.rdf_jena.TransactionUtil.executeInTransaction;
import static org.jruby.RubyBoolean.newBoolean;
import static org.jruby.RubyFixnum.newFixnum;
import static org.jruby.RubyString.newString;
import static org.jruby.RubySymbol.newSymbol;

@JRubyClass(name = "Repository")
public class Repository extends RubyObject {

    public static ObjectAllocator Allocator = Repository::new;

    /**
     * Jena {@link Dataset} backed by a TDB database. This state is should be
     * used as final within this Ruby Object.
     */
    protected Dataset ds;

    public Repository(Ruby runtime, RubyClass metaclass) {
        super(runtime, metaclass);
    }

    @JRubyMethod(name = "initialize", required = 1, optional = 1)
    public IRubyObject initialize(
            ThreadContext ctx,
            IRubyObject[] args
    ) {
        String datasetDirectory = args[0].asJavaString();
        ds                      = TDBFactory.createDataset(datasetDirectory);

        //Ruby ruby                      = ctx.runtime;
        //RubyHash options               = (args.length <= 1) ? RubyHash.newHash(ruby) : args[1].convertToHash();
        //Boolean someOption             = (Boolean) options.get(newSymbol(ruby, "some_option"));

        return ctx.nil;
    }

    @JRubyMethod(name = "durable?")
    public RubyBoolean isDurable(ThreadContext ctx) {
        return newBoolean(ctx.runtime, true);
    }

    @JRubyMethod(name = "empty?")
    public RubyBoolean isEmpty(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> newBoolean(ctx.runtime, ds.asDatasetGraph().isEmpty()));
    }

    @JRubyMethod(name = {"count", "size"})
    public RubyFixnum size(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> {
            Iterator<Quad> quads = ds.asDatasetGraph().find();
            long size = 0;
            while (quads.hasNext()) {
                quads.next(); size += 1;
            }
            return newFixnum(ctx.runtime, size);
        });
    }

    @JRubyMethod(name = {"graph_count", "graph_size"})
    public RubyFixnum graphSize(ThreadContext ctx) {
        return executeInTransaction(ds, ReadWrite.READ, ds -> newFixnum(ctx.runtime, ds.asDatasetGraph().size()));
    }

    @JRubyMethod(name = {"each_statement", "each"})
    public IRubyObject iterateStatements(ThreadContext ctx, Block block) {
        if (block != Block.NULL_BLOCK) {
            executeInTransaction(ds, ReadWrite.READ, ds -> {
                Iterator<Quad> quads = ds.asDatasetGraph().find();
                while (quads.hasNext()) {
                    block.call(ctx, convertQuad(ctx, quads.next()));
                }
                return null;
            });
            return ctx.nil;
        } else {
            return callMethod(ctx, "enum_statement");
        }
    }

    @JRubyMethod(name = {"query_pattern"}, required = 1, optional = 1)
    public IRubyObject queryPattern(ThreadContext ctx, IRubyObject[] args, Block block) {
        if (block != Block.NULL_BLOCK) {
            IRubyObject statements = args[0];

            // argument 1; unused options

            executeInTransaction(ds, ReadWrite.READ, ds -> {
                Node[] nodePattern = convertRDFPattern(ctx, statements);
                DatasetGraph dg    = ds.asDatasetGraph();
                Iterator<Quad> quads;
                if (nodePattern == null) {
                    quads = dg.find();
                } else {
                    if (nodePattern[0] == null) {
                        nodePattern[0] = NodeFactory.createURI("urn:x-arq:DefaultGraph");
                    }
                    quads = dg.find(nodePattern[0], nodePattern[1], nodePattern[2], nodePattern[3]);
                }
                while (quads.hasNext()) {
                    block.call(ctx, convertQuad(ctx, quads.next()));
                }
                return null;
            });
            return ctx.nil;
        } else {
            IRubyObject[] enumArgs = new IRubyObject[args.length+1];
            enumArgs[0] = newSymbol(ctx.runtime, "query_pattern");
            System.arraycopy(args, 0, enumArgs, 1, args.length);
            return callMethod(ctx, "enum_for", enumArgs);
        }
    }

    @JRubyMethod(name = {"query_execute"}, required = 1, argTypes = {RubyString.class})
    public IRubyObject queryExecute(ThreadContext ctx, RubyString sparqlQuery, Block block) {
        if (block != Block.NULL_BLOCK) {
            executeInTransaction(ds, ReadWrite.READ, ds -> {
                Query query   = QueryFactory.create(sparqlQuery.asString().asJavaString());

                Model defaultModel = ds.getDefaultModel();
                try (QueryExecution qexec = QueryExecutionFactory.create(query, defaultModel)) {
                    ResultSet resultSet = qexec.execSelect();
                    while (resultSet.hasNext()) {
                        QuerySolution solution = resultSet.next();
                        Map<RubyString, IRubyObject> solutionVars = new HashMap<>();
                        Iterator<String> variableIterator = solution.varNames();
                        while (variableIterator.hasNext()) {
                            String variable = variableIterator.next();
                            solutionVars.put(ctx.runtime.newString(variable), convertNode(ctx, solution.get(variable)));
                        }
                        block.call(ctx, RubyHash.newHash(ctx.runtime, solutionVars, ctx.nil));
                    }
                }
                return null;
            });
            return ctx.nil;
        } else {
            IRubyObject[] enumArgs = new IRubyObject[2];
            enumArgs[0] = newSymbol(ctx.runtime, "query_execute");
            enumArgs[1] = sparqlQuery;
            return callMethod(ctx, "enum_for", enumArgs);
        }
    }

    @JRubyMethod(name = "has_statement?", required = 1)
    public RubyBoolean hasStatement(ThreadContext ctx, IRubyObject rdfStatement) {
        if (rdfStatement == null) {
            return newBoolean(ctx.runtime, false);
        }

        return executeInTransaction(ds, ReadWrite.READ, ds -> {
            Node[] nodePattern = convertRDFPattern(ctx, rdfStatement);
            if (nodePattern == null) {
                return newBoolean(ctx.runtime, false);
            }

            if (nodePattern[0] == null) {
                nodePattern[0] = NodeFactory.createURI("urn:x-arq:DefaultGraph");
            }
            return newBoolean(ctx.runtime, ds.asDatasetGraph().contains(
                    nodePattern[0], //graph
                    nodePattern[1], //subject
                    nodePattern[2], //predicate
                    nodePattern[3]  //object
            ));
{'fraction_non_alphanumeric': 0.11417268184342032, 'fraction_numerical': 0.00416435313714603, 'mean_word_length': 2.2897260273972604, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5101247', 'n_tokens_mistral': 4302, 'n_tokens_neox': 4061, 'n_words': 821}