Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions engines/algebra-sparql-1-1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,31 @@ and the project operation always gets used (even in the case of `SELECT *`).

Every test consists of a sparql file and a corresponding json file containing the algebra result.
Tests ending with `(quads)` in their name are tested/generated with `quads: true` in the options.

## CLI

This package exposes the `traqula-algebra-sparql-1-1` binary.

Convert AST JSON to algebra JSON:

```bash
traqula-algebra-sparql-1-1 --input ast.json --output algebra.json --pretty
```

Convert algebra JSON back to AST JSON:

```bash
traqula-algebra-sparql-1-1 --from algebra --input algebra.json --output ast.json --pretty
```

Run as a long-lived JSONL service:

```bash
traqula-algebra-sparql-1-1 --service
```

Request example:

```json
{ "id": "1", "mode": "toAlgebra", "input": { "type": "query", "subType": "ask" }, "options": { "quads": false, "blankToVariable": false } }
```
113 changes: 113 additions & 0 deletions engines/algebra-sparql-1-1/bin/traqula-algebra-sparql-1-1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#!/usr/bin/env node
import type { Algebra, ContextConfigs } from '@traqula/algebra-transformations-1-1';
import {
parsePrefixMappings,
readJsonInput,
runJsonlService,
writeJsonOutput,
} from '@traqula/cli-utils';
import type { SparqlQuery } from '@traqula/rules-sparql-1-1';
import { Command } from 'commander';
import { createAlgebraCliRuntime, handleAlgebraCliRequest } from '../lib/cli.js';

function collectStrings(val: string, prev: string[]): string[] {
return [ ...prev, val ];
}

const program = new Command()
.name('traqula-algebra-sparql-1-1')
.description('Translate between Traqula SPARQL AST JSON and SPARQL algebra JSON.')
.option('-i, --input <path>', 'Read JSON input from file (defaults to stdin)')
.option('-o, --output <path>', 'Write JSON output to file (defaults to stdout)')
.option('--from <ast|algebra>', 'Input format (default: ast)', 'ast')
.option('--quads', 'toAlgebra: convert patterns to quads')
.option('--blank-to-variable', 'toAlgebra: rewrite blank nodes to variables')
.option('--base-iri <iri>', 'toAlgebra: base IRI for relative resolution')
.option('--prefix <pfx=iri>', 'toAlgebra: predefined prefixes (repeatable)', collectStrings, <string[]> [])
.option('--pretty', 'Pretty-print JSON output')
.option('--service', 'Run JSONL service mode over stdio')
.addHelpText('after', `
Service request format:
{"id":"1","mode":"toAlgebra","input":{...},"options":{"quads":false}}`);

interface Options {
input?: string;
output?: string;
from: string;
quads?: boolean;
blankToVariable?: boolean;
baseIri?: string;
prefix: string[];
pretty?: boolean;
service?: boolean;
}

function parseFromOption(value: string): 'toAlgebra' | 'toAst' {
if (value === 'ast') {
return 'toAlgebra';
}
if (value === 'algebra') {
return 'toAst';
}
throw new Error(`Invalid value for --from: ${value}. Expected 'ast' or 'algebra'`);
}

function createToAlgebraOptions(opts: Options): ContextConfigs {
return {
quads: opts.quads,
blankToVariable: opts.blankToVariable,
baseIRI: opts.baseIri,
prefixes: parsePrefixMappings(opts.prefix),
};
}

program.action(async(opts: Options) => {
const runtime = createAlgebraCliRuntime();

if (opts.service) {
await runJsonlService((request: unknown) => {
if (request === null || typeof request !== 'object') {
throw new Error('Service request must be a JSON object');
}
const data = <{ mode?: unknown; input?: unknown; options?: unknown }> request;
if (data.mode !== 'toAlgebra' && data.mode !== 'toAst') {
throw new Error('Service request must include mode: toAlgebra | toAst');
}
if (data.input === undefined) {
throw new Error('Service request must include property: input');
}
if (data.mode === 'toAlgebra') {
return handleAlgebraCliRequest(runtime, {
mode: 'toAlgebra',
input: <SparqlQuery> data.input,
options: <ContextConfigs | undefined> data.options,
});
}
return handleAlgebraCliRequest(runtime, {
mode: 'toAst',
input: <Algebra.Operation> data.input,
});
});
return;
}

const mode = parseFromOption(opts.from);
const input = await readJsonInput<SparqlQuery | Algebra.Operation>(opts.input);
const output = mode === 'toAlgebra' ?
handleAlgebraCliRequest(runtime, {
mode: 'toAlgebra',
input: <SparqlQuery> input,
options: createToAlgebraOptions(opts),
}) :
handleAlgebraCliRequest(runtime, {
mode: 'toAst',
input: <Algebra.Operation> input,
});

await writeJsonOutput(output, opts.pretty ?? false, opts.output);
});

program.parseAsync().catch((error: unknown) => {
process.stderr.write(`${error instanceof Error ? error.message : 'Unknown error'}\n`);
process.exitCode = 1;
});
46 changes: 46 additions & 0 deletions engines/algebra-sparql-1-1/lib/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { Algebra, ContextConfigs } from '@traqula/algebra-transformations-1-1';
import { algebraUtils, createAlgebraContext, createAstContext } from '@traqula/algebra-transformations-1-1';
import type { SparqlQuery } from '@traqula/rules-sparql-1-1';
import { toAlgebra11Builder } from './toAlgebra.js';
import { toAst11Builder } from './toAst.js';

export type AlgebraCliRequest =
| {
readonly mode: 'toAlgebra';
readonly input: SparqlQuery;
readonly options?: ContextConfigs;
}
| {
readonly mode: 'toAst';
readonly input: Algebra.Operation;
readonly options?: ContextConfigs;
};

export interface AlgebraCliRuntime {
readonly toAlgebraTransformer: ReturnType<typeof toAlgebra11Builder.build>;
readonly toAstTransformer: ReturnType<typeof toAst11Builder.build>;
}

export function createAlgebraCliRuntime(): AlgebraCliRuntime {
return {
toAlgebraTransformer: toAlgebra11Builder.build(),
toAstTransformer: toAst11Builder.build(),
};
}

export function handleAlgebraCliRequest(runtime: AlgebraCliRuntime, request: AlgebraCliRequest): unknown {
if (request.mode === 'toAlgebra') {
const options = request.options ?? {};
const context = createAlgebraContext(options);
const operation = runtime.toAlgebraTransformer.translateQuery(
context,
request.input,
options.quads,
options.blankToVariable,
);
return algebraUtils.objectify(operation);
}

const context = createAstContext();
return runtime.toAstTransformer.algToSparql(context, request.input);
}
1 change: 1 addition & 0 deletions engines/algebra-sparql-1-1/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './toAst.js';
export * from './toAlgebra.js';
export * from './cli.js';
14 changes: 13 additions & 1 deletion engines/algebra-sparql-1-1/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,41 @@
}
},
"main": "dist/esm/lib/index.js",
"bin": {
"traqula-algebra-sparql-1-1": "dist/esm/bin/traqula-algebra-sparql-1-1.js"
},
"publishConfig": {
"access": "public"
},
"files": [
"dist/*/bin/**/*.d.ts",
"dist/*/bin/**/*.js",
"dist/*/bin/**/*.js.map",
"dist/*/lib/**/*.d.ts",
"dist/*/lib/**/*.js",
"dist/*/lib/**/*.js.map",
"dist/cjs/package.json"
],
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"build": "yarn build:ts && yarn build:cjs",
"build:ts": "node \"../../node_modules/typescript/bin/tsc\" -b",
"build:cjs": "node \"../../node_modules/typescript/bin/tsc\" -b tsconfig.cjs.json"
},
"dependencies": {
"@traqula/algebra-transformations-1-1": "^1.0.4",
"@traqula/cli-utils": "^1.0.4",
"@traqula/core": "^1.0.3",
"@traqula/rules-sparql-1-1": "^1.0.4"
"@traqula/rules-sparql-1-1": "^1.0.4",
"commander": "^14.0.3"
},
"devDependencies": {
"@traqula/generator-sparql-1-1": "^1.0.4",
"@traqula/parser-sparql-1-1": "^1.0.4",
"@traqula/test-utils": "^1.0.4",
"@types/node": "^24.3.1",
"sparqlalgebrajs": "^5.0.1",
"sparqljs": "^3.7.3"
}
Expand Down
Loading
Loading