diff --git a/exercises/concept/intro-select/create_fixture.sql b/exercises/concept/intro-select/create_fixture.sql new file mode 100644 index 00000000..c96de796 --- /dev/null +++ b/exercises/concept/intro-select/create_fixture.sql @@ -0,0 +1,10 @@ +DROP TABLE IF EXISTS weather_readings; +CREATE TABLE weather_readings ( + date TEXT NOT NULL, + location TEXT NOT NULL, + temperature INTEGER NOT NULL, + humidity INTEGER NOT NULL +); + +.mode csv +.import ./data.csv weather_readings diff --git a/exercises/concept/intro-select/data.csv b/exercises/concept/intro-select/data.csv new file mode 100644 index 00000000..cbe5e09a --- /dev/null +++ b/exercises/concept/intro-select/data.csv @@ -0,0 +1,6 @@ +"2025-10-22","Portland",53,72 +"2025-10-22","Seattle",56,66 +"2025-10-22","Boise",60,55 +"2025-10-23","Portland",54,70 +"2025-10-23","Seattle",57,68 +"2025-10-23","Boise",62,58 diff --git a/exercises/concept/intro-select/intro-select.sql b/exercises/concept/intro-select/intro-select.sql new file mode 100644 index 00000000..4c512429 --- /dev/null +++ b/exercises/concept/intro-select/intro-select.sql @@ -0,0 +1,33 @@ +CREATE TABLE all_data AS + -- Task 1. Select all records. + SELECT * FROM weather_readings +; + +CREATE TABLE location_and_temperature AS + -- Task 2. Select only location and temperature data. + -- Expect failure + SELECT temperature FROM weather_readings +; + +CREATE TABLE seattle AS + -- Task 3. Select all data for Seattle. + SELECT * FROM weather_readings WHERE location = 'Seattle' +; + +CREATE TABLE limited_humidity AS + -- Task 4. Select all data where the humidity is between 60% and 70%. + -- Expect failure + SELECT * FROM weather_readings WHERE humidity BETWEEN 50 AND 62 +; +.print "My debugging output:" +SELECT humidity from weather_readings; + +CREATE TABLE location AS + -- Task 5. Select only location data. + SELECT location FROM weather_readings +; + +CREATE TABLE unique_location AS + -- Task 5. Select only unique location data. + SELECT DISTINCT location FROM weather_readings +; diff --git a/exercises/concept/intro-select/intro-select_test.sql b/exercises/concept/intro-select/intro-select_test.sql new file mode 100644 index 00000000..d844e726 --- /dev/null +++ b/exercises/concept/intro-select/intro-select_test.sql @@ -0,0 +1,17 @@ +-- Create database: +.read ./create_fixture.sql + +-- ASK: How can we correlate user output with specific tests? One way is to add .output statements +-- in the stub file. But that introduces more noise into the stub file. + +-- Run user solution and store results +.mode markdown +.output user_output.md +.read ./intro-select.sql +.shell rm -f ./results.db +.save ./results.db + +.output + +-- Report results +.shell sh ./report-results.sh results.db diff --git a/exercises/concept/intro-select/report-results.sh b/exercises/concept/intro-select/report-results.sh new file mode 100644 index 00000000..323980d3 --- /dev/null +++ b/exercises/concept/intro-select/report-results.sh @@ -0,0 +1,15 @@ +DB_FILE=$1 +SLUGS=$(jq -n --slurpfile test_data test_data.json '$test_data[0] | keys' | sed 's/[][",]//g') + +# Generate result for each test +rm -f results.txt +for SLUG in $SLUGS; do + ACTUAL=$(sqlite3 -json $DB_FILE "SELECT * FROM ${SLUG};" | tr -d '[:space:]') + if [ -z "$ACTUAL" ]; then + ACTUAL="[]" + fi + jq -n --slurpfile test_data test_data.json --argjson got ''${ACTUAL}'' --arg slug ${SLUG} -f test-result.jq >> results.txt +done + +# Aggregate results +jq -n --slurpfile results results.txt '$results' > output.json diff --git a/exercises/concept/intro-select/test-result.jq b/exercises/concept/intro-select/test-result.jq new file mode 100644 index 00000000..606e710b --- /dev/null +++ b/exercises/concept/intro-select/test-result.jq @@ -0,0 +1,30 @@ +def columns: + if (. | length) == 0 then [] + else .[0] | keys + end; + +def rows: + [map(to_entries)[] | map(.value)]; + +def failure_message(got; expected): + (got | columns | tostring) as $got_columns + | (expected | columns | tostring) as $expected_columns + | if $got_columns != $expected_columns then + "Expected columns " + $expected_columns + "; but got " + $got_columns + else + (got | rows | tostring) as $got_rows + | (expected | rows | tostring) as $expected_rows + | "With columns " + $got_columns + ", expected " + $expected_rows + "; but got " + $got_rows + end; + +$test_data[0][$slug] as $single_test_data +| $single_test_data.description as $description +| $single_test_data.expected as $expected +| $single_test_data.task_id as $task_id +| if $task_id then {$task_id} else {} end as $entry +| $entry + {$description} as $entry +| if $got != $expected then + $entry + {"status": "fail", "message": failure_message($got; $expected)} + else + $entry + {"status": "pass"} + end diff --git a/exercises/concept/intro-select/test_data.json b/exercises/concept/intro-select/test_data.json new file mode 100644 index 00000000..295e3f66 --- /dev/null +++ b/exercises/concept/intro-select/test_data.json @@ -0,0 +1,64 @@ +{ + "all_data": { + "task_id": 1, + "description": "All data", + "expected": [ + {"date":"2025-10-22","location":"Portland","temperature":53,"humidity":72}, + {"date":"2025-10-22","location":"Seattle","temperature":56,"humidity":66}, + {"date":"2025-10-22","location":"Boise","temperature":60,"humidity":55}, + {"date":"2025-10-23","location":"Portland","temperature":54,"humidity":70}, + {"date":"2025-10-23","location":"Seattle","temperature":57,"humidity":68}, + {"date":"2025-10-23","location":"Boise","temperature":62,"humidity":58} + ] + }, + "location_and_temperature": { + "task_id": 2, + "description": "Just location and temperature", + "expected": [ + {"location":"Portland","temperature":53}, + {"location":"Seattle","temperature":56}, + {"location":"Boise","temperature":60}, + {"location":"Portland","temperature":54}, + {"location":"Seattle","temperature":57}, + {"location":"Boise","temperature":62} + ] + }, + "seattle": { + "task_id": 3, + "description": "Seattle only", + "expected": [ + {"date":"2025-10-22","location":"Seattle","temperature":56,"humidity":66}, + {"date":"2025-10-23","location":"Seattle","temperature":57,"humidity":68} + ] + }, + "limited_humidity": { + "task_id": 4, + "description": "Humidity within range", + "expected": [ + {"date":"2025-10-22","location":"Seattle","temperature":56,"humidity":66}, + {"date":"2025-10-23","location":"Portland","temperature":54,"humidity":70}, + {"date":"2025-10-23","location":"Seattle","temperature":57,"humidity":68} + ] + }, + "location": { + "task_id": 5, + "description": "Just locations", + "expected": [ + {"location":"Portland"}, + {"location":"Seattle"}, + {"location":"Boise"}, + {"location":"Portland"}, + {"location":"Seattle"}, + {"location":"Boise"} + ] + }, + "unique_location": { + "task_id": 5, + "description": "Only unique locations", + "expected": [ + {"location":"Portland"}, + {"location":"Seattle"}, + {"location":"Boise"} + ] + } +} \ No newline at end of file