Skip to content
Open
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
2 changes: 1 addition & 1 deletion actions/s2dm-publish/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ runs:
working-directory: ${{ inputs.repository-path }}
shell: bash
run: |
CMD="s2dm generate schema-rdf -s ${{ inputs.spec-path }} -o ${{ github.workspace }}/.artifacts/schema-rdf --namespace '${{ inputs.schema-rdf-namespace }}'"
CMD="s2dm generate schema-rdf -s ${{ inputs.spec-path }} -o ${{ github.workspace }}/.artifacts/schema-rdf --namespace '${{ inputs.schema-rdf-namespace }}' --output-formats nt,ttl,jsonld"
[ -n "${{ inputs.schema-rdf-prefix }}" ] && CMD="$CMD --prefix '${{ inputs.schema-rdf-prefix }}'"
[ -n "${{ inputs.schema-rdf-language }}" ] && CMD="$CMD --language '${{ inputs.schema-rdf-language }}'"
eval "$CMD"
Expand Down
228 changes: 228 additions & 0 deletions docs-gen/content/docs/tools/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,234 @@ s2dm export avro schema --help
s2dm export avro protocol --help
```

## Generate Commands

### Schema RDF

The `generate schema-rdf` command materializes a GraphQL schema as RDF triples using the s2dm ontology. The generated RDF mirrors the schema's structure (types, fields, enums, unions, interfaces) as a semantic graph that can be queried with SPARQL.

#### Usage

```bash
s2dm generate schema-rdf -s <schema_path> -o <output_dir> --namespace <uri>
```

#### Options

- `-s, --schema PATH`: GraphQL schema file, directory, or URL (required, can be specified multiple times)
- `-o, --output DIR`: Output directory for RDF artifacts (required)
- `--namespace URI`: Namespace URI for concept URIs (required)
- `--prefix TEXT`: Prefix for concept URIs (default: `ns`)
- `--language TEXT`: BCP 47 language tag for prefLabels (default: `en`)
- `--output-formats TEXT`: Comma-separated output formats (default: `nt,turtle`). Supported: `json-ld` (or `jsonld`), `nt`, `turtle` (or `ttl`)

#### Examples

Generate sorted n-triples and Turtle (default):

```bash
s2dm generate schema-rdf \
-s spec/ \
-o ./rdf-output \
--namespace "https://covesa.org/s2dm/mydomain#"
```

Generate all formats including JSON-LD (for releases):

```bash
s2dm generate schema-rdf \
-s spec/ \
-o ./rdf-output \
--namespace "https://covesa.org/s2dm/mydomain#" \
--output-formats nt,turtle,json-ld
```

Generate only n-triples (for git):

```bash
s2dm generate schema-rdf \
-s spec/ \
-o ./rdf-output \
--namespace "https://covesa.org/s2dm/mydomain#" \
--output-formats nt
```

#### Output Formats

| Format | Alias | Extension | Description |
|--------|-------|-----------|-------------|
| `nt` | | `.nt` | Sorted n-triples (deterministic, git-friendly diffs) |
| `turtle` | `ttl` | `.ttl` | Turtle (human-readable, for consumption) |
| `json-ld` | `jsonld` | `.jsonld` | JSON-LD (for web and linked data tooling) |

The `nt` format is special-cased to produce lexicographically sorted lines, ensuring deterministic output suitable for version control.

#### Ontology Mapping

The s2dm ontology maps GraphQL SDL elements to RDF as follows:

- **Object types**: `rdf:type skos:Concept, s2dm:ObjectType`
- **Fields**: `rdf:type skos:Concept, s2dm:Field` with `s2dm:hasOutputType` and `s2dm:usesTypeWrapperPattern`
- **Enum types**: `rdf:type skos:Concept, s2dm:EnumType` with `s2dm:hasEnumValue`
- **Enum values**: `rdf:type skos:Concept, s2dm:EnumValue`
- **Interface types**: `rdf:type skos:Concept, s2dm:InterfaceType`
- **Input object types**: `rdf:type skos:Concept, s2dm:InputObjectType`
- **Union types**: `rdf:type skos:Concept, s2dm:UnionType` with `s2dm:hasUnionMember`
- **Built-in scalars**: `s2dm:Int`, `s2dm:Float`, `s2dm:String`, `s2dm:Boolean`, `s2dm:ID`

## Query Commands

The `query` command group provides predefined SPARQL queries for traversing and analysing an RDF-materialized schema. Each command can either load a pre-generated RDF file or materialize on-the-fly from a GraphQL schema.

### Input Options (shared by all query commands)

Provide **one** of the following:

- `--rdf PATH`: Path to a pre-generated `.nt` or `.ttl` file
- `-s, --schema PATH` + `--namespace URI`: Materialize from GraphQL schema on-the-fly

Additional option:

- `--json`: Output results as JSON instead of a table

### fields-outputting-enum

Find all fields whose output type is an enum type.

```bash
# From a pre-generated file
s2dm query fields-outputting-enum --rdf schema.nt

# From a GraphQL schema
s2dm query fields-outputting-enum -s spec/ --namespace "https://example.org/#"

# JSON output
s2dm query fields-outputting-enum --rdf schema.nt --json
```

**Example output:**

```
fields-outputting-enum
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ field ┃ enumType ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
│ Cabin.kind │ CabinKindEnum │
│ InCabinArea2x2.column │ TwoColumnsInCabinEnum │
│ InCabinArea2x2.row │ TwoRowsInCabinEnum │
└───────────────────────┴───────────────────────┘
```

### object-types-with-fields

List all object types and their fields.

```bash
s2dm query object-types-with-fields --rdf schema.nt
```

**Example output:**

```
object-types-with-fields
┏━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
┃ objectType ┃ field ┃
┡━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
│ Cabin │ Cabin.doors │
│ Cabin │ Cabin.kind │
│ Door │ Door.isOpen │
│ Door │ Door.window │
│ Window │ Window.isTinted │
└────────────────┴───────────────────────┘
```

### list-type-fields

Find all fields that use a list-like type wrapper pattern (`list`, `nonNullList`, `listOfNonNull`, `nonNullListOfNonNull`).

```bash
s2dm query list-type-fields --rdf schema.nt --json
```

**Example JSON output:**

```json
[
{
"field": "https://example.org/my-domain#Cabin.doors",
"pattern": "https://covesa.global/models/s2dm#list"
}
]
```

### Example SPARQL Queries

The CLI queries above are powered by SPARQL. Below are the raw queries for reference, which can also be run against any SPARQL endpoint or rdflib graph loaded with the materialized RDF.

**Find all fields that output an enum type:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>

SELECT ?field ?enumType
WHERE {
?field a s2dm:Field ;
s2dm:hasOutputType ?enumType .
?enumType a s2dm:EnumType .
}
ORDER BY ?field
```

**List all object types and their fields:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>

SELECT ?objectType ?field
WHERE {
?objectType a s2dm:ObjectType ;
s2dm:hasField ?field .
}
ORDER BY ?objectType ?field
```

**Find fields using list wrappers:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>

SELECT ?field ?pattern
WHERE {
?field a s2dm:Field ;
s2dm:usesTypeWrapperPattern ?pattern .
FILTER(?pattern IN (
s2dm:list,
s2dm:nonNullList,
s2dm:listOfNonNull,
s2dm:nonNullListOfNonNull
))
}
ORDER BY ?field
```

**Find fields whose output type has fields of enum type (nested pattern):**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>

SELECT ?parentType ?field ?nestedField ?enumType
WHERE {
?parentType a s2dm:ObjectType ;
s2dm:hasField ?field .
?field s2dm:hasOutputType ?outputType .
?outputType a s2dm:ObjectType ;
s2dm:hasField ?nestedField .
?nestedField s2dm:hasOutputType ?enumType .
?enumType a s2dm:EnumType .
}
ORDER BY ?parentType ?field
```

## Common Features

### Selection Query Filtering
Expand Down
88 changes: 88 additions & 0 deletions examples/schema-rdf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,94 @@ ns:CabinKindEnum a skos:Concept, s2dm:EnumType ;
s2dm:hasEnumValue ns:CabinKindEnum.SUV, ns:CabinKindEnum.VAN .
```

## Querying the Schema with SPARQL

The generated RDF can be queried using SPARQL -- either via the s2dm CLI or any SPARQL-capable tool (rdflib, Apache Jena, triple stores).

### Using the CLI

```bash
# Find all fields that output an enum type
s2dm query fields-outputting-enum --rdf output/schema.nt

# List all object types with their fields
s2dm query object-types-with-fields --rdf output/schema.nt

# Find fields using list wrappers (JSON output)
s2dm query list-type-fields --rdf output/schema.nt --json

# Or materialize on-the-fly from GraphQL
s2dm query fields-outputting-enum -s sample.graphql --namespace "https://example.org/my-domain#"
```

### Using rdflib (Python)

```python
from rdflib import Graph

g = Graph()
g.parse("output/schema.nt", format="nt")

results = g.query("""
PREFIX s2dm: <https://covesa.global/models/s2dm#>
SELECT ?field ?enumType
WHERE {
?field a s2dm:Field ;
s2dm:hasOutputType ?enumType .
?enumType a s2dm:EnumType .
}
ORDER BY ?field
""")

for row in results:
print(f"{row.field} -> {row.enumType}")
```

### Example SPARQL Queries

**Find all fields that output an enum type:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>
SELECT ?field ?enumType WHERE {
?field a s2dm:Field ; s2dm:hasOutputType ?enumType .
?enumType a s2dm:EnumType .
}
```

**List all object types and their fields:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>
SELECT ?objectType ?field WHERE {
?objectType a s2dm:ObjectType ; s2dm:hasField ?field .
}
ORDER BY ?objectType
```

**Find fields using list wrappers:**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>
SELECT ?field ?pattern WHERE {
?field a s2dm:Field ; s2dm:usesTypeWrapperPattern ?pattern .
FILTER(?pattern IN (s2dm:list, s2dm:nonNullList, s2dm:listOfNonNull, s2dm:nonNullListOfNonNull))
}
```

**Find nested patterns (fields whose output type has enum fields):**

```sparql
PREFIX s2dm: <https://covesa.global/models/s2dm#>
SELECT ?parentType ?field ?nestedField ?enumType WHERE {
?parentType a s2dm:ObjectType ; s2dm:hasField ?field .
?field s2dm:hasOutputType ?outputType .
?outputType a s2dm:ObjectType ; s2dm:hasField ?nestedField .
?nestedField s2dm:hasOutputType ?enumType .
?enumType a s2dm:EnumType .
}
```

## Exclusions

- Query, Mutation, and Subscription root types
Expand Down
Loading