From f45a800e13f9ba786cbec50576bea30e0e1ff0e5 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Tue, 19 Aug 2025 11:27:52 -0300 Subject: [PATCH 1/6] * add practice exercise: proverb --- config.json | 8 ++ .../practice/proverb/.docs/instructions.md | 19 ++++ exercises/practice/proverb/.meta/config.json | 19 ++++ exercises/practice/proverb/.meta/example.sql | 33 +++++++ exercises/practice/proverb/.meta/tests.toml | 28 ++++++ .../practice/proverb/canonical-data.json | 92 +++++++++++++++++++ exercises/practice/proverb/create_fixture.sql | 10 ++ .../practice/proverb/create_test_table.sql | 26 ++++++ exercises/practice/proverb/data.csv | 6 ++ exercises/practice/proverb/proverb.sql | 7 ++ exercises/practice/proverb/proverb_test.sql | 40 ++++++++ 11 files changed, 288 insertions(+) create mode 100644 exercises/practice/proverb/.docs/instructions.md create mode 100644 exercises/practice/proverb/.meta/config.json create mode 100644 exercises/practice/proverb/.meta/example.sql create mode 100644 exercises/practice/proverb/.meta/tests.toml create mode 100644 exercises/practice/proverb/canonical-data.json create mode 100644 exercises/practice/proverb/create_fixture.sql create mode 100644 exercises/practice/proverb/create_test_table.sql create mode 100644 exercises/practice/proverb/data.csv create mode 100644 exercises/practice/proverb/proverb.sql create mode 100644 exercises/practice/proverb/proverb_test.sql diff --git a/config.json b/config.json index ea86b75..2c76660 100644 --- a/config.json +++ b/config.json @@ -330,6 +330,14 @@ "prerequisites": [], "difficulty": 8 }, + { + "slug": "proverb", + "name": "Proverb", + "uuid": "10c51241-2399-4a0c-84cf-390a000f3c3b", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "rest-api", "name": "REST API", diff --git a/exercises/practice/proverb/.docs/instructions.md b/exercises/practice/proverb/.docs/instructions.md new file mode 100644 index 0000000..f6fb859 --- /dev/null +++ b/exercises/practice/proverb/.docs/instructions.md @@ -0,0 +1,19 @@ +# Instructions + +For want of a horseshoe nail, a kingdom was lost, or so the saying goes. + +Given a list of inputs, generate the relevant proverb. +For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme: + +```text +For want of a nail the shoe was lost. +For want of a shoe the horse was lost. +For want of a horse the rider was lost. +For want of a rider the message was lost. +For want of a message the battle was lost. +For want of a battle the kingdom was lost. +And all for the want of a nail. +``` + +Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. +No line of the output text should be a static, unchanging string; all should vary according to the input given. diff --git a/exercises/practice/proverb/.meta/config.json b/exercises/practice/proverb/.meta/config.json new file mode 100644 index 0000000..bea1ff5 --- /dev/null +++ b/exercises/practice/proverb/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "jimmytty" + ], + "files": { + "solution": [ + "proverb.sql" + ], + "test": [ + "proverb_test.sql" + ], + "example": [ + ".meta/example.sql" + ] + }, + "blurb": "For want of a horseshoe nail, a kingdom was lost, or so the saying goes. Output the full text of this proverbial rhyme.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/For_Want_of_a_Nail" +} diff --git a/exercises/practice/proverb/.meta/example.sql b/exercises/practice/proverb/.meta/example.sql new file mode 100644 index 0000000..b2f7199 --- /dev/null +++ b/exercises/practice/proverb/.meta/example.sql @@ -0,0 +1,33 @@ +UPDATE proverb + SET result = '' + WHERE JSON(strings) = '[]' +; + +UPDATE proverb + SET result = ( + WITH RECURSIVE to_pieces (strings, i, len, piece) AS ( + VALUES(strings, 0, JSON_ARRAY_LENGTH(strings) - 1, NULL) + UNION ALL + SELECT strings, i+1, len, + PRINTF( + 'For want of a %s the %s was lost.', + JSON_EXTRACT(strings, PRINTF('$[%d]', i)), + JSON_EXTRACT(strings, PRINTF('$[%d]', i+1)) + ) + FROM to_pieces + WHERE i < len + ) + SELECT group_concat(piece, CHAR(10)) + FROM ( + SELECT piece + FROM to_pieces + WHERE piece NOTNULL + UNION ALL + SELECT PRINTF( + 'And all for the want of a %s.', + JSON_EXTRACT(strings, '$[0]') + ) + ) + ) + WHERE result ISNULL +; diff --git a/exercises/practice/proverb/.meta/tests.toml b/exercises/practice/proverb/.meta/tests.toml new file mode 100644 index 0000000..dc92a0c --- /dev/null +++ b/exercises/practice/proverb/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[e974b73e-7851-484f-8d6d-92e07fe742fc] +description = "zero pieces" + +[2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4] +description = "one piece" + +[d9d0a8a1-d933-46e2-aa94-eecf679f4b0e] +description = "two pieces" + +[c95ef757-5e94-4f0d-a6cb-d2083f5e5a83] +description = "three pieces" + +[433fb91c-35a2-4d41-aeab-4de1e82b2126] +description = "full proverb" + +[c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7] +description = "four pieces modernized" diff --git a/exercises/practice/proverb/canonical-data.json b/exercises/practice/proverb/canonical-data.json new file mode 100644 index 0000000..6784c9a --- /dev/null +++ b/exercises/practice/proverb/canonical-data.json @@ -0,0 +1,92 @@ +{ + "exercise": "proverb", + "comments": [ + "JSON doesn't allow for multi-line strings, so all expected outputs are presented ", + "here as arrays of strings. It's up to the test generator to join the ", + "lines together with line breaks. " + ], + "cases": [ + { + "uuid": "e974b73e-7851-484f-8d6d-92e07fe742fc", + "description": "zero pieces", + "property": "recite", + "input": { + "strings": [] + }, + "expected": [] + }, + { + "uuid": "2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4", + "description": "one piece", + "property": "recite", + "input": { + "strings": ["nail"] + }, + "expected": ["And all for the want of a nail."] + }, + { + "uuid": "d9d0a8a1-d933-46e2-aa94-eecf679f4b0e", + "description": "two pieces", + "property": "recite", + "input": { + "strings": ["nail", "shoe"] + }, + "expected": [ + "For want of a nail the shoe was lost.", + "And all for the want of a nail." + ] + }, + { + "uuid": "c95ef757-5e94-4f0d-a6cb-d2083f5e5a83", + "description": "three pieces", + "property": "recite", + "input": { + "strings": ["nail", "shoe", "horse"] + }, + "expected": [ + "For want of a nail the shoe was lost.", + "For want of a shoe the horse was lost.", + "And all for the want of a nail." + ] + }, + { + "uuid": "433fb91c-35a2-4d41-aeab-4de1e82b2126", + "description": "full proverb", + "property": "recite", + "input": { + "strings": [ + "nail", + "shoe", + "horse", + "rider", + "message", + "battle", + "kingdom" + ] + }, + "expected": [ + "For want of a nail the shoe was lost.", + "For want of a shoe the horse was lost.", + "For want of a horse the rider was lost.", + "For want of a rider the message was lost.", + "For want of a message the battle was lost.", + "For want of a battle the kingdom was lost.", + "And all for the want of a nail." + ] + }, + { + "uuid": "c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7", + "description": "four pieces modernized", + "property": "recite", + "input": { + "strings": ["pin", "gun", "soldier", "battle"] + }, + "expected": [ + "For want of a pin the gun was lost.", + "For want of a gun the soldier was lost.", + "For want of a soldier the battle was lost.", + "And all for the want of a pin." + ] + } + ] +} diff --git a/exercises/practice/proverb/create_fixture.sql b/exercises/practice/proverb/create_fixture.sql new file mode 100644 index 0000000..56bacea --- /dev/null +++ b/exercises/practice/proverb/create_fixture.sql @@ -0,0 +1,10 @@ +DROP TABLE IF EXISTS proverb; +CREATE TABLE proverb ( + strings TEXT NOT NULL, -- json array + result TEXT +); + +.mode csv +.import ./data.csv proverb + +UPDATE proverb SET result = NULL; diff --git a/exercises/practice/proverb/create_test_table.sql b/exercises/practice/proverb/create_test_table.sql new file mode 100644 index 0000000..0b54d0f --- /dev/null +++ b/exercises/practice/proverb/create_test_table.sql @@ -0,0 +1,26 @@ +DROP TABLE IF EXISTS tests; +CREATE TABLE IF NOT EXISTS tests ( + -- uuid and description are taken from the test.toml file + uuid TEXT PRIMARY KEY, + description TEXT NOT NULL, + -- The following section is needed by the online test-runner + status TEXT DEFAULT 'fail', + message TEXT, + output TEXT, + test_code TEXT, + task_id INTEGER DEFAULT NULL, + -- Here are columns for the actual tests + strings TEXT NOT NULL, -- json array + expected TEXT NOT NULL +); + +INSERT INTO tests (uuid, description, strings, expected) + VALUES + ('e974b73e-7851-484f-8d6d-92e07fe742fc', 'zero pieces', '[]', ''), + ('2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4', 'one piece', '["nail"]', 'And all for the want of a nail.'), + ('d9d0a8a1-d933-46e2-aa94-eecf679f4b0e', 'two pieces', '["nail","shoe"]', 'For want of a nail the shoe was lost.\nAnd all for the want of a nail.'), + ('c95ef757-5e94-4f0d-a6cb-d2083f5e5a83', 'three pieces', '["nail","shoe","horse"]', 'For want of a nail the shoe was lost.\nFor want of a shoe the horse was lost.\nAnd all for the want of a nail.'), + ('433fb91c-35a2-4d41-aeab-4de1e82b2126', 'full proverb', '["nail","shoe","horse","rider","message","battle","kingdom"]', 'For want of a nail the shoe was lost.\nFor want of a shoe the horse was lost.\nFor want of a horse the rider was lost.\nFor want of a rider the message was lost.\nFor want of a message the battle was lost.\nFor want of a battle the kingdom was lost.\nAnd all for the want of a nail.'), + ('c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7', 'four pieces modernized', '["pin","gun","soldier","battle"]', 'For want of a pin the gun was lost.\nFor want of a gun the soldier was lost.\nFor want of a soldier the battle was lost.\nAnd all for the want of a pin.'); + +UPDATE tests SET expected = REPLACE(expected, '\n', CHAR(10)); diff --git a/exercises/practice/proverb/data.csv b/exercises/practice/proverb/data.csv new file mode 100644 index 0000000..c8357e1 --- /dev/null +++ b/exercises/practice/proverb/data.csv @@ -0,0 +1,6 @@ +"[]", +"[""nail""]", +"[""nail"",""shoe""]", +"[""nail"",""shoe"",""horse""]", +"[""nail"",""shoe"",""horse"",""rider"",""message"",""battle"",""kingdom""]", +"[""pin"",""gun"",""soldier"",""battle""]", diff --git a/exercises/practice/proverb/proverb.sql b/exercises/practice/proverb/proverb.sql new file mode 100644 index 0000000..a7de0bd --- /dev/null +++ b/exercises/practice/proverb/proverb.sql @@ -0,0 +1,7 @@ +-- Schema: +-- CREATE TABLE proverb ( +-- strings TEXT NOT NULL, -- json array +-- result TEXT +-- ); +-- +-- Task: update proverb table and set result column based on the strings. diff --git a/exercises/practice/proverb/proverb_test.sql b/exercises/practice/proverb/proverb_test.sql new file mode 100644 index 0000000..d730ed6 --- /dev/null +++ b/exercises/practice/proverb/proverb_test.sql @@ -0,0 +1,40 @@ +-- Create database: +.read ./create_fixture.sql + +-- Read user student solution and save any output as markdown in user_output.md: +.mode markdown +.output user_output.md +.read ./proverb.sql +.output + +-- Create a clean testing environment: +.read ./create_test_table.sql + +-- Comparison of user input and the tests updates the status for each test: +UPDATE tests +SET status = 'pass' +FROM (SELECT strings, result FROM proverb) AS actual +WHERE (actual.strings, actual.result) = (tests.strings, tests.expected); + +-- Update message for failed tests to give helpful information: +UPDATE tests +SET message = ( + 'Result for "' + || tests.strings + || '"' + || ' is <' || COALESCE(actual.result, 'NULL') + || '> but should be <' || tests.expected || '>' +) +FROM (SELECT strings, result FROM proverb) AS actual +WHERE actual.strings = tests.strings AND tests.status = 'fail'; + +-- Save results to ./output.json (needed by the online test-runner) +.mode json +.once './output.json' +SELECT description, status, message, output, test_code, task_id +FROM tests; + +-- Display test results in readable form for the student: +.mode table +SELECT description, status, message +FROM tests; From 366a4bfa6172555e13eb0cec27ae28c2fc259856 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Tue, 19 Aug 2025 11:41:12 -0300 Subject: [PATCH 2/6] * add instructions.append.md --- .../proverb/.docs/instructions.append.md | 23 +++++ .../practice/proverb/canonical-data.json | 92 ------------------- 2 files changed, 23 insertions(+), 92 deletions(-) create mode 100644 exercises/practice/proverb/.docs/instructions.append.md delete mode 100644 exercises/practice/proverb/canonical-data.json diff --git a/exercises/practice/proverb/.docs/instructions.append.md b/exercises/practice/proverb/.docs/instructions.append.md new file mode 100644 index 0000000..4a07008 --- /dev/null +++ b/exercises/practice/proverb/.docs/instructions.append.md @@ -0,0 +1,23 @@ +# SQLite-specific instructions + +The **strings** column contains a JSON-encoded list of strings. + +Example: +```json +["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"] +``` + +## Table Schema + +```sql +CREATE TABLE proverb ( + strings TEXT NOT NULL, -- json array + result TEXT +); +``` + +## JSON documentation + +[JSON Functions And Operators][json-docs] + +[json-docs]: https://www.sqlite.org/json1.html diff --git a/exercises/practice/proverb/canonical-data.json b/exercises/practice/proverb/canonical-data.json deleted file mode 100644 index 6784c9a..0000000 --- a/exercises/practice/proverb/canonical-data.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "exercise": "proverb", - "comments": [ - "JSON doesn't allow for multi-line strings, so all expected outputs are presented ", - "here as arrays of strings. It's up to the test generator to join the ", - "lines together with line breaks. " - ], - "cases": [ - { - "uuid": "e974b73e-7851-484f-8d6d-92e07fe742fc", - "description": "zero pieces", - "property": "recite", - "input": { - "strings": [] - }, - "expected": [] - }, - { - "uuid": "2fcd5f5e-8b82-4e74-b51d-df28a5e0faa4", - "description": "one piece", - "property": "recite", - "input": { - "strings": ["nail"] - }, - "expected": ["And all for the want of a nail."] - }, - { - "uuid": "d9d0a8a1-d933-46e2-aa94-eecf679f4b0e", - "description": "two pieces", - "property": "recite", - "input": { - "strings": ["nail", "shoe"] - }, - "expected": [ - "For want of a nail the shoe was lost.", - "And all for the want of a nail." - ] - }, - { - "uuid": "c95ef757-5e94-4f0d-a6cb-d2083f5e5a83", - "description": "three pieces", - "property": "recite", - "input": { - "strings": ["nail", "shoe", "horse"] - }, - "expected": [ - "For want of a nail the shoe was lost.", - "For want of a shoe the horse was lost.", - "And all for the want of a nail." - ] - }, - { - "uuid": "433fb91c-35a2-4d41-aeab-4de1e82b2126", - "description": "full proverb", - "property": "recite", - "input": { - "strings": [ - "nail", - "shoe", - "horse", - "rider", - "message", - "battle", - "kingdom" - ] - }, - "expected": [ - "For want of a nail the shoe was lost.", - "For want of a shoe the horse was lost.", - "For want of a horse the rider was lost.", - "For want of a rider the message was lost.", - "For want of a message the battle was lost.", - "For want of a battle the kingdom was lost.", - "And all for the want of a nail." - ] - }, - { - "uuid": "c1eefa5a-e8d9-41c7-91d4-99fab6d6b9f7", - "description": "four pieces modernized", - "property": "recite", - "input": { - "strings": ["pin", "gun", "soldier", "battle"] - }, - "expected": [ - "For want of a pin the gun was lost.", - "For want of a gun the soldier was lost.", - "For want of a soldier the battle was lost.", - "And all for the want of a pin." - ] - } - ] -} From 83fc4789087f0531214815e6f6fe92afc4bb1789 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Wed, 20 Aug 2025 22:53:53 -0300 Subject: [PATCH 3/6] Update exercises/practice/proverb/.docs/instructions.append.md Co-authored-by: Isaac Good --- exercises/practice/proverb/.docs/instructions.append.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/proverb/.docs/instructions.append.md b/exercises/practice/proverb/.docs/instructions.append.md index 4a07008..dec5433 100644 --- a/exercises/practice/proverb/.docs/instructions.append.md +++ b/exercises/practice/proverb/.docs/instructions.append.md @@ -1,6 +1,6 @@ # SQLite-specific instructions -The **strings** column contains a JSON-encoded list of strings. +The **strings** column contains a JSON-encoded list of words which is the input values you should use. Example: ```json From b25ea4bafcdff3b5a47b01c20070f8c6d178a7a0 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Wed, 20 Aug 2025 22:54:16 -0300 Subject: [PATCH 4/6] Update exercises/practice/proverb/create_fixture.sql Co-authored-by: Isaac Good --- exercises/practice/proverb/create_fixture.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/proverb/create_fixture.sql b/exercises/practice/proverb/create_fixture.sql index 56bacea..c52db92 100644 --- a/exercises/practice/proverb/create_fixture.sql +++ b/exercises/practice/proverb/create_fixture.sql @@ -1,6 +1,6 @@ DROP TABLE IF EXISTS proverb; CREATE TABLE proverb ( - strings TEXT NOT NULL, -- json array + strings TEXT NOT NULL, -- json array containing the input words result TEXT ); From d0f38c85083c3c300eb6ace62d60fc2eb9387390 Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Wed, 20 Aug 2025 22:54:31 -0300 Subject: [PATCH 5/6] Update exercises/practice/proverb/proverb.sql Co-authored-by: Isaac Good --- exercises/practice/proverb/proverb.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/practice/proverb/proverb.sql b/exercises/practice/proverb/proverb.sql index a7de0bd..e134291 100644 --- a/exercises/practice/proverb/proverb.sql +++ b/exercises/practice/proverb/proverb.sql @@ -1,6 +1,6 @@ -- Schema: -- CREATE TABLE proverb ( --- strings TEXT NOT NULL, -- json array +-- strings TEXT NOT NULL, -- json array containing the input words -- result TEXT -- ); -- From d1df30bad89b336eabaf52e60431c2a272d4779b Mon Sep 17 00:00:00 2001 From: Ronaldo Ferreira de Lima Date: Wed, 20 Aug 2025 22:56:34 -0300 Subject: [PATCH 6/6] * removing duplicate info from instructions.append.md --- .../proverb/.docs/instructions.append.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/exercises/practice/proverb/.docs/instructions.append.md b/exercises/practice/proverb/.docs/instructions.append.md index dec5433..27d1e44 100644 --- a/exercises/practice/proverb/.docs/instructions.append.md +++ b/exercises/practice/proverb/.docs/instructions.append.md @@ -1,21 +1,5 @@ # SQLite-specific instructions -The **strings** column contains a JSON-encoded list of words which is the input values you should use. - -Example: -```json -["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"] -``` - -## Table Schema - -```sql -CREATE TABLE proverb ( - strings TEXT NOT NULL, -- json array - result TEXT -); -``` - ## JSON documentation [JSON Functions And Operators][json-docs]