Skip to content

Commit 848cfd3

Browse files
authored
Add sparql-playground (#41)
* Add sparql-playground * Add schema/data/playground WIP * Add script to gen-rdf * Add script to update-graph * Update C01 example project * Add sparql-playground github action * Update README * Remove sparql-playground dir * Add primary impact * Add GRAPH_STORE_URL env and secret * TEMP use endpoints.dev for graph store * Check that dataset exists * Do not add / to url * Add -f to fail requests * Add graph store auth * Clear graph before adding data * Add curl silent mode * Add status check with link to yasgui * Add permission for statuses write * Remove test data
1 parent 6653228 commit 848cfd3

File tree

6 files changed

+211
-7
lines changed

6 files changed

+211
-7
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
on:
2+
push:
3+
branches:
4+
- main
5+
pull_request:
6+
jobs:
7+
deploy:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
contents: read
11+
deployments: write
12+
statuses: write
13+
name: Validate and Convert data
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
- uses: actions/setup-python@v5
18+
with:
19+
python-version: '3.10'
20+
cache: 'pip'
21+
- name: Install python dependencies
22+
run: pip install -r requirements.txt
23+
- name: Generate RDF
24+
run: make -C schema gen-rdf
25+
- name: Check if dataset exists
26+
id: check-dataset
27+
env:
28+
GRAPH_STORE_URL: ${{ vars.GRAPH_STORE_URL }}
29+
GRAPH_STORE_USER: ${{ secrets.GRAPH_STORE_USER }}
30+
GRAPH_STORE_PW: ${{ secrets.GRAPH_STORE_PW }}
31+
DATASET: ${{ github.event_name == 'pull_request' && format('PR-{0}', github.event.number) || 'main' }}
32+
run: |
33+
URL="${GRAPH_STORE_URL}${DATASET}"
34+
echo "Using dataset: ${DATASET}"
35+
echo "Full URL: ${URL}"
36+
echo "url=${URL}" >> $GITHUB_OUTPUT
37+
38+
GRAPH_STORE_AUTH="${GRAPH_STORE_USER}:${GRAPH_STORE_PW}"
39+
echo "auth=${GRAPH_STORE_AUTH}" >> $GITHUB_OUTPUT
40+
41+
echo "Checking if dataset exists at: ${URL}"
42+
if curl -s -f -o /dev/null --user "${GRAPH_STORE_AUTH}" "${URL}"; then
43+
echo "✅ Dataset exists at ${URL}"
44+
echo "exists=true" >> $GITHUB_OUTPUT
45+
else
46+
echo "❌ Dataset does not exist at ${URL}"
47+
echo "⚠️ Skipping graph update step"
48+
echo "exists=false" >> $GITHUB_OUTPUT
49+
fi
50+
51+
- name: Update graph
52+
if: steps.check-dataset.outputs.exists == 'true'
53+
env:
54+
GRAPH_STORE_URL: ${{ steps.check-dataset.outputs.url }}
55+
GRAPH_STORE_AUTH: ${{ steps.check-dataset.outputs.auth }}
56+
run: make -C schema update-graph
57+
- name: Create SPARQL Playground Status
58+
if: steps.check-dataset.outputs.exists == 'true'
59+
env:
60+
GRAPH_STORE_URL: ${{ steps.check-dataset.outputs.url }}
61+
GH_TOKEN: ${{ github.token }}
62+
run: |
63+
# Define the SPARQL query in plain text
64+
SPARQL_QUERY="
65+
PREFIX rfs: <https://framework.regen.network/schema/>
66+
67+
SELECT * WHERE {
68+
?sub ?pred ?obj .
69+
} LIMIT 1000"
70+
71+
# URL encode the SPARQL query
72+
QUERY_ENDPOINT="${GRAPH_STORE_URL}/query"
73+
ENCODED_QUERY=$(printf '%s' "${SPARQL_QUERY}" | jq -sRr @uri)
74+
75+
# URL encode the query endpoint
76+
ENCODED_ENDPOINT=$(printf '%s' "${QUERY_ENDPOINT}" | jq -sRr @uri)
77+
78+
# Create the YASGUI URL
79+
YASGUI_URL="https://yasgui.triply.cc/#query=${ENCODED_QUERY}&endpoint=${ENCODED_ENDPOINT}&requestMethod=POST&tabTitle=Query&headers=%7B%7D&contentTypeConstruct=application%2Fn-triples%2C*%2F*%3Bq%3D0.9&contentTypeSelect=application%2Fsparql-results%2Bjson%2C*%2F*%3Bq%3D0.9&outputFormat=table&outputSettings=%7B%22isEllipsed%22%3Afalse%2C%22compact%22%3Afalse%7D"
80+
81+
# Create commit status
82+
gh api repos/${{ github.repository }}/statuses/${{ github.sha }} \
83+
--method POST \
84+
--field state=success \
85+
--field target_url="${YASGUI_URL}" \
86+
--field description="Click to explore RDF data in SPARQL playground" \
87+
--field context="sparql-playground/${DATASET}"

schema/Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ lint:
77
gen-doc:
88
gen-doc src/schema.yaml --directory generated --diagram-type er_diagram -v
99

10-
gen-jsonld:
11-
linkml-convert --input-format yaml --output-format json-ld --schema src/schema.yaml data/BT01ProjectInfoData.yaml --output data/BT01ProjectInfoData.jsonld --target-class BT01ProjectInfo
10+
gen-rdf:
11+
scripts/gen-rdf.sh
1212

13-
validate:
14-
linkml-validate -s src/schema.yaml --target-class BT01ProjectInfo data/BT01ProjectInfoData.yaml
13+
update-graph:
14+
scripts/update-graph.sh
1515

16-
all: gen-taxonomy lint gen-doc gen-jsonld validate
16+
all: gen-taxonomy lint gen-doc gen-rdf update-graph

schema/README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,22 @@
1212
- Create separate schema files for each logical schema class and `import` into the root `schemas.yaml` file.
1313
- Generated markdown from schemas:
1414
```shell
15-
gen-doc schema/src/schemas.yaml --directory schema/generated --diagram-type er_diagram
1615
make gen-doc
1716
```
1817
- Generate linkml enums for taxonomy terms:
1918
```shell
2019
make gen-taxonomy
21-
```
20+
```
21+
22+
## Playground
23+
24+
- Datasets are provided inside `schema/data/playground/{Credit-Class}/{LinkML-Class}/*.yaml` files
25+
- Validate and generate RDF data. This creates `.ttl` and `.jsonld` files for each dataset.
26+
```shell
27+
make gen-rdf
28+
```
29+
- Add data to graph. This adds all `.ttl` files to the graph. Override the `GRAPH_STORE_URL` env var:
30+
```shell
31+
export GRAPH_STORE_URL=http://localhost:7878/store
32+
make update-graph
33+
```

schema/data/playground/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*/*/*.jsonld
2+
*/*/*.ttl

schema/scripts/gen-rdf.sh

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#!/bin/bash
2+
3+
# Root directory for data
4+
DATA_DIR="data/playground"
5+
SCHEMA_PATH="src/schema.yaml"
6+
7+
# Use globbing to iterate through the nested structure
8+
shopt -s nullglob # Handle cases where no files match pattern
9+
10+
# Initialize counters
11+
failed_count=0
12+
total_count=0
13+
14+
# Loop through nested directories of linkml classes
15+
for linkml_class_dir in "$DATA_DIR"/*/*/; do
16+
17+
# Convert yaml files to RDF using linkml class schema
18+
linkml_class=$(basename "$linkml_class_dir")
19+
for yaml_file in "$linkml_class_dir"*.yaml; do
20+
21+
((total_count++))
22+
# Create output filename by replacing .yaml extension with .jsonld
23+
output_file="${yaml_file%.yaml}.jsonld"
24+
if ! linkml-convert -s "$SCHEMA_PATH" --validate --input-format yaml --output-format json-ld --target-class "$linkml_class" --output "$output_file" "$yaml_file" ; then
25+
echo "❌ JSON-LD conversion failed for: $yaml_file"
26+
((failed_count++))
27+
else
28+
echo "✅ JSON-LD conversion passed for: $yaml_file"
29+
fi
30+
31+
# Create output filename by replacing .yaml extension with .ttl
32+
output_file="${yaml_file%.yaml}.ttl"
33+
((total_count++))
34+
if ! linkml-convert -s "$SCHEMA_PATH" --validate --input-format yaml --output-format ttl --target-class "$linkml_class" --output "$output_file" "$yaml_file" ; then
35+
echo "❌ TTL conversion failed for: $yaml_file"
36+
((failed_count++))
37+
else
38+
echo "✅ TTL conversion passed for: $yaml_file"
39+
fi
40+
done
41+
done
42+
43+
echo "RDF conversion complete: $((total_count - failed_count)) passed, $failed_count failed out of $total_count total files"
44+
45+
# Exit with failure if any validations failed
46+
[[ $failed_count -eq 0 ]] || exit 1

schema/scripts/update-graph.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/bash
2+
3+
# Root directory for data
4+
DATA_DIR="data/playground"
5+
6+
# Only set default values if environment variables are not set
7+
: "${GRAPH_STORE_URL:=http://localhost:7878/store}"
8+
: "${GRAPH:=default}"
9+
10+
# Build auth variable if GRAPH_STORE_AUTH is present.
11+
# GRAPH_STORE_AUTH should be in format user:pass
12+
if [ -n "$GRAPH_STORE_AUTH" ]; then
13+
AUTH="--user $GRAPH_STORE_AUTH"
14+
else
15+
AUTH=""
16+
fi
17+
18+
# Set METHOD and GRAPH_PARAM based on GRAPH value
19+
# Use POST to append to default graph, and PUT to replace named graphs
20+
if [ "$GRAPH" = "default" ]; then
21+
METHOD=POST
22+
GRAPH_PARAM="?default"
23+
else
24+
METHOD=PUT
25+
GRAPH_PARAM="?graph=$GRAPH"
26+
fi
27+
28+
# First, clear the graph.
29+
if ! curl -s -X DELETE -f $AUTH "$GRAPH_STORE_URL$GRAPH_PARAM" ; then
30+
echo "❌ Failed to delete content in graph: $GRAPH"
31+
else
32+
echo "✅ Deleted content in graph: $GRAPH with $file"
33+
fi
34+
35+
# Use globbing to iterate through the nested structure
36+
shopt -s nullglob # Handle cases where no files match pattern
37+
38+
# Initialize counters
39+
failed_count=0
40+
total_count=0
41+
42+
# Loop through turtle files
43+
for file in "$DATA_DIR"/*/*/*.ttl; do
44+
((total_count++))
45+
46+
if ! curl -s -X $METHOD -f -H 'Content-Type: text/turtle' -T "$file" $AUTH "$GRAPH_STORE_URL$GRAPH_PARAM" ; then
47+
echo "❌ Failed to update graph: $GRAPH with $file"
48+
((failed_count++))
49+
else
50+
echo "✅ Updated graph: $GRAPH with $file"
51+
fi
52+
done
53+
54+
echo "Updating graph complete: $((total_count - failed_count)) passed, $failed_count failed out of $total_count total files"
55+
56+
# Exit with failure if any validations failed
57+
[[ $failed_count -eq 0 ]] || exit 1

0 commit comments

Comments
 (0)