Query Package
The @traceweave/trf-query package provides SQL query capabilities for .twpack files, allowing flexible data extraction and analysis.
Installation
npm install @traceweave/trf-query
Quick Start
const { TwpackQuery } = require('@traceweave/trf-query');
const query = new TwpackQuery();
await query.loadTwpack('./my-pack.twpack');
// Get all requirements
const requirements = query.getByKind('requirement');
// Execute SQL query
const results = query.sql(
'SELECT kind, COUNT(*) as count FROM artifacts GROUP BY kind'
);
// Always close when done
query.close();
API Reference
TwpackQuery
loadTwpack(path)
Load a .twpack file for querying.
await query.loadTwpack('./my-pack.twpack');
sql(query, params?)
Execute a raw SQL query.
// Simple query
const results = query.sql('SELECT * FROM artifacts WHERE kind = ?', ['requirement']);
// Complex query
const results = query.sql(`
SELECT
a.id,
a.title,
l.relation,
b.title as linked_to
FROM artifacts a
JOIN links l ON a.id = l.from_id
JOIN artifacts b ON l.to_id = b.id
WHERE a.kind = 'requirement'
`);
Returns an array of result objects.
getByKind(kind)
Get all artifacts of a specific kind.
const requirements = query.getByKind('requirement');
const tests = query.getByKind('test');
getByRelation(relation)
Get all links with a specific relation.
const verifiedBy = query.getByRelation('verified_by');
const implements = query.getByRelation('implements');
getArtifacts(filter?)
Get artifacts with optional filtering.
// All artifacts
const all = query.getArtifacts();
// With predicate filter
const filtered = query.getArtifacts({
predicate: (artifact) => artifact.kind === 'requirement' &&
artifact.fields.priority === 'high'
});
getLinks(filter?)
Get links with optional filtering.
// All links
const all = query.getLinks();
// With predicate filter
const filtered = query.getLinks({
predicate: (link) => link.relation === 'verified_by'
});
close()
Close the query engine and cleanup resources.
query.close();
Important: Always call close() when done to release database connections.
Database Schema
The query engine loads .twpack data into SQLite tables:
artifacts table
| Column | Type | Description |
|---|---|---|
| id | TEXT | Artifact ID (primary key) |
| kind | TEXT | Artifact kind |
| version | TEXT | Artifact version |
| title | TEXT | Artifact title |
| fields | TEXT | JSON string of custom fields |
links table
| Column | Type | Description |
|---|---|---|
| id | TEXT | Link ID (primary key) |
| from_id | TEXT | Source artifact ID |
| to_id | TEXT | Target artifact ID |
| relation | TEXT | Relation type |
provenance table
| Column | Type | Description |
|---|---|---|
| id | TEXT | Activity ID (primary key) |
| type | TEXT | Activity type |
| timestamp | TEXT | ISO 8601 timestamp |
| actor | TEXT | Actor/agent |
| fields | TEXT | JSON string of custom fields |
Complete Examples
Basic Queries
const { TwpackQuery } = require('@traceweave/trf-query');
async function basicQueries() {
const query = new TwpackQuery();
try {
await query.loadTwpack('./my-pack.twpack');
// Count artifacts by kind
const kindCounts = query.sql(`
SELECT kind, COUNT(*) as count
FROM artifacts
GROUP BY kind
`);
console.log('Artifacts by kind:', kindCounts);
// Count links by relation
const relationCounts = query.sql(`
SELECT relation, COUNT(*) as count
FROM links
GROUP BY relation
`);
console.log('Links by relation:', relationCounts);
// Get all high-priority requirements
const highPriority = query.sql(`
SELECT id, title
FROM artifacts
WHERE kind = 'requirement'
AND json_extract(fields, '$.priority') = 'high'
`);
console.log('High priority requirements:', highPriority);
} finally {
query.close();
}
}
Advanced Joins
async function advancedQueries() {
const query = new TwpackQuery();
try {
await query.loadTwpack('./automotive-iso26262.twpack');
// Requirements with their tests
const reqsWithTests = query.sql(`
SELECT
r.id as requirement_id,
r.title as requirement_title,
t.id as test_id,
t.title as test_title,
json_extract(t.fields, '$.status') as test_status
FROM artifacts r
JOIN links l ON r.id = l.from_id
JOIN artifacts t ON l.to_id = t.id
WHERE r.kind = 'requirement'
AND t.kind = 'test'
AND l.relation = 'verified_by'
`);
console.log('Requirements with tests:');
reqsWithTests.forEach(row => {
console.log(` ${row.requirement_id}: ${row.requirement_title}`);
console.log(` → ${row.test_id} (${row.test_status})`);
});
// ASIL-D requirements without tests
const uncoveredASILD = query.sql(`
SELECT r.id, r.title
FROM artifacts r
LEFT JOIN links l ON r.id = l.from_id AND l.relation = 'verified_by'
WHERE r.kind = 'requirement'
AND json_extract(r.fields, '$.safety_level') = 'ASIL-D'
AND l.id IS NULL
`);
if (uncoveredASILD.length > 0) {
console.log('\n⚠️ ASIL-D requirements without tests:');
uncoveredASILD.forEach(req => {
console.log(` - ${req.id}: ${req.title}`);
});
}
} finally {
query.close();
}
}
JSON Field Queries
async function jsonFieldQueries() {
const query = new TwpackQuery();
try {
await query.loadTwpack('./my-pack.twpack');
// Query JSON fields using json_extract
const results = query.sql(`
SELECT
id,
title,
json_extract(fields, '$.priority') as priority,
json_extract(fields, '$.safety_level') as safety_level,
json_extract(fields, '$.status') as status
FROM artifacts
WHERE kind = 'requirement'
AND json_extract(fields, '$.priority') IN ('high', 'critical')
ORDER BY
CASE json_extract(fields, '$.priority')
WHEN 'critical' THEN 1
WHEN 'high' THEN 2
ELSE 3
END
`);
console.log('Priority requirements:');
results.forEach(row => {
console.log(` ${row.id} [${row.priority}]: ${row.title}`);
});
} finally {
query.close();
}
}
Traceability Matrix
async function traceabilityMatrix() {
const query = new TwpackQuery();
try {
await query.loadTwpack('./compliance.twpack');
// Create traceability matrix
const matrix = query.sql(`
SELECT
r.id as requirement,
GROUP_CONCAT(t.id, ', ') as tests
FROM artifacts r
LEFT JOIN links l ON r.id = l.from_id AND l.relation = 'verified_by'
LEFT JOIN artifacts t ON l.to_id = t.id AND t.kind = 'test'
WHERE r.kind = 'requirement'
GROUP BY r.id
ORDER BY r.id
`);
console.log('Traceability Matrix:');
console.log('Requirement | Tests');
console.log('------------|------');
matrix.forEach(row => {
console.log(`${row.requirement} | ${row.tests || '(none)'}`);
});
} finally {
query.close();
}
}
Export to JSON
async function exportData() {
const query = new TwpackQuery();
try {
await query.loadTwpack('./my-pack.twpack');
// Export all requirements with their metadata
const requirements = query.sql(`
SELECT
id,
title,
version,
fields
FROM artifacts
WHERE kind = 'requirement'
`);
// Parse JSON fields
const parsed = requirements.map(req => ({
id: req.id,
title: req.title,
version: req.version,
...JSON.parse(req.fields)
}));
// Write to file
const fs = require('fs');
fs.writeFileSync(
'./requirements-export.json',
JSON.stringify(parsed, null, 2)
);
console.log(`Exported ${parsed.length} requirements`);
} finally {
query.close();
}
}
CLI Usage
All query functionality is available via CLI:
# Get artifacts by kind
trf query artifacts -f my-pack.twpack -k requirement
# Get links by relation
trf query links -f my-pack.twpack -r verified_by
# Execute SQL query
trf query sql -f my-pack.twpack \
-q "SELECT kind, COUNT(*) FROM artifacts GROUP BY kind"
# JSON output for automation
trf query artifacts -f my-pack.twpack -k test --json > tests.json
See CLI Reference for details.
Performance
Query performance depends on the complexity and data size:
| Query Type | 10K artifacts | 100K artifacts |
|---|---|---|
| Simple SELECT | <5ms | <20ms |
| Single JOIN | <20ms | <100ms |
| Complex JOIN | <50ms | <300ms |
| Aggregation | <10ms | <50ms |
Tips
Indexing
The query engine automatically creates indexes on:
artifacts.idartifacts.kindlinks.from_idlinks.to_idlinks.relation
JSON Queries
Use json_extract() to query JSON fields:
-- Extract a field
json_extract(fields, '$.priority')
-- Nested extraction
json_extract(fields, '$.metadata.author')
-- Array access
json_extract(fields, '$.tags[0]')
Parameterized Queries
Always use parameterized queries to prevent SQL injection:
// Good
query.sql('SELECT * FROM artifacts WHERE kind = ?', [userInput]);
// Bad (vulnerable to injection)
query.sql(`SELECT * FROM artifacts WHERE kind = '${userInput}'`);
See Also
- Analyzer Package - Graph analytics
- Builder Package - Create packs
- CLI Reference - Command-line usage