1+ app [main!] { pf: platform " ../platform/main.roc" }
2+
3+ import pf.Env
4+ import pf.Stdout
5+ import pf.Sqlite
6+ import pf.Arg exposing [Arg ]
7+
8+ # Run this test with: `DB_PATH=./tests/test.db roc tests/sqlite.roc`
9+
10+ # Tests functions exposed by the Sqlite module that are not covered by the sqlite files in the examples folder.
11+
12+ # Sql to create the table:
13+ # CREATE TABLE test (
14+ # id INTEGER PRIMARY KEY AUTOINCREMENT,
15+ # col_text TEXT NOT NULL,
16+ # col_bytes BLOB NOT NULL,
17+ # col_i32 INTEGER NOT NULL,
18+ # col_i16 INTEGER NOT NULL,
19+ # col_i8 INTEGER NOT NULL,
20+ # col_u32 INTEGER NOT NULL,
21+ # col_u16 INTEGER NOT NULL,
22+ # col_u8 INTEGER NOT NULL,
23+ # col_f64 REAL NOT NULL,
24+ # col_f32 REAL NOT NULL,
25+ # col_nullable_str TEXT,
26+ # col_nullable_bytes BLOB,
27+ # col_nullable_i64 INTEGER,
28+ # col_nullable_i32 INTEGER,
29+ # col_nullable_i16 INTEGER,
30+ # col_nullable_i8 INTEGER,
31+ # col_nullable_u64 INTEGER,
32+ # col_nullable_u32 INTEGER,
33+ # col_nullable_u16 INTEGER,
34+ # col_nullable_u8 INTEGER,
35+ # col_nullable_f64 REAL,
36+ # col_nullable_f32 REAL
37+ # );
38+
39+ main ! : List Arg => Result {} _
40+ main ! = |_args |
41+ db_path = Env . var !("DB_PATH ")?
42+
43+ # Test Sqlite.str, Sqlite.bytes, Sqlite.i32...
44+
45+ all_rows = Sqlite . query_many !({
46+ path: db_path,
47+ query: " SELECT * FROM test;" ,
48+ bindings: [],
49+ # This uses the record builder syntax: https://www.roc-lang.org/examples/RecordBuilder/README.html
50+ rows: { Sqlite . decode_record <-
51+ col_text: Sqlite . str ("col_text "),
52+ col_bytes: Sqlite . bytes ("col_bytes "),
53+ col_i32: Sqlite . i32 ("col_i32 "),
54+ col_i16: Sqlite . i16 ("col_i16 "),
55+ col_i8: Sqlite . i8 ("col_i8 "),
56+ col_u32: Sqlite . u32 ("col_u32 "),
57+ col_u16: Sqlite . u16 ("col_u16 "),
58+ col_u8: Sqlite . u8 ("col_u8 "),
59+ col_f64: Sqlite . f64 ("col_f64 "),
60+ col_f32: Sqlite . f32 ("col_f32 "),
61+ col_nullable_str: Sqlite . nullable_str ("col_nullable_str "),
62+ col_nullable_bytes: Sqlite . nullable_bytes ("col_nullable_bytes "),
63+ col_nullable_i64: Sqlite . nullable_i64 ("col_nullable_i64 "),
64+ col_nullable_i32: Sqlite . nullable_i32 ("col_nullable_i32 "),
65+ col_nullable_i16: Sqlite . nullable_i16 ("col_nullable_i16 "),
66+ col_nullable_i8: Sqlite . nullable_i8 ("col_nullable_i8 "),
67+ col_nullable_u64: Sqlite . nullable_u64 ("col_nullable_u64 "),
68+ col_nullable_u32: Sqlite . nullable_u32 ("col_nullable_u32 "),
69+ col_nullable_u16: Sqlite . nullable_u16 ("col_nullable_u16 "),
70+ col_nullable_u8: Sqlite . nullable_u8 ("col_nullable_u8 "),
71+ col_nullable_f64: Sqlite . nullable_f64 ("col_nullable_f64 "),
72+ col_nullable_f32: Sqlite . nullable_f32 ("col_nullable_f32 "),
73+ },
74+ })?
75+
76+ rows_texts_str =
77+ all_rows
78+ |> List . map (|row | Inspect . to_str (row ))
79+ |> Str . join_with ("\n ")
80+
81+ Stdout . line !("Rows : ${rows_texts_str}" )?
82+
83+ # Test query_prepared! with count
84+
85+ prepared_count = Sqlite.prepare!({
86+ path: db_path,
87+ query: " SELECT COUNT (* ) as \" count\" FROM test;" ,
88+ })?
89+
90+ count = Sqlite . query_prepared !({
91+ stmt: prepared_count,
92+ bindings: [],
93+ row: Sqlite . u64 ("count "),
94+ })?
95+
96+ Stdout . line !("Row count: ${Num . to_str (count )}")?
97+
98+ # Test execute_prepared! with different params
99+
100+ prepared_update = Sqlite . prepare !({
101+ path: db_path,
102+ query: " UPDATE test SET col_text = :col_text WHERE id = :id;" ,
103+ })?
104+
105+ Sqlite . execute_prepared !({
106+ stmt: prepared_update,
107+ bindings: [
108+ { name: " :id" , value: Integer (1 ) },
109+ { name: " :col_text" , value: String (" Updated text 1" ) },
110+ ],
111+ })?
112+
113+ Sqlite . execute_prepared !({
114+ stmt: prepared_update,
115+ bindings: [
116+ { name: " :id" , value: Integer (2 ) },
117+ { name: " :col_text" , value: String (" Updated text 2" ) },
118+ ],
119+ })?
120+
121+ # Check if the updates were successful
122+ updated_rows = Sqlite . query_many !({
123+ path: db_path,
124+ query: " SELECT COL_TEXT FROM test;" ,
125+ bindings: [],
126+ rows: Sqlite . str ("col_text "),
127+ })?
128+
129+ Stdout . line !("Updated rows: ${Inspect . to_str (updated_rows )}")?
130+
131+ # revert update
132+ Sqlite . execute_prepared !({
133+ stmt: prepared_update,
134+ bindings: [
135+ { name: " :id" , value: Integer (1 ) },
136+ { name: " :col_text" , value: String (" example text" ) },
137+ ],
138+ })?
139+
140+ Sqlite . execute_prepared !({
141+ stmt: prepared_update,
142+ bindings: [
143+ { name: " :id" , value: Integer (2 ) },
144+ { name: " :col_text" , value: String (" sample text" ) },
145+ ],
146+ })?
147+
148+ # Test tagged_value
149+ tagged_value_test = Sqlite . query_many !({
150+ path: db_path,
151+ query: " SELECT * FROM test;" ,
152+ bindings: [],
153+ # This uses the record builder syntax: https://www.roc-lang.org/examples/RecordBuilder/README.html
154+ rows: Sqlite . tagged_value ("col_text "),
155+ })?
156+
157+ Stdout . line !("Tagged value test: ${Inspect . to_str (tagged_value_test )}")?
158+
159+ # Let's try to trigger a `Data type mismatch` error
160+ sql_res = Sqlite . execute !({
161+ path: db_path,
162+ query: " UPDATE test SET id = :id WHERE col_text = :col_text;" ,
163+ bindings: [
164+ { name: " :col_text" , value: String (" sample text" ) },
165+ { name: " :id" , value: String (" This should be an integer" ) },
166+ ],
167+ })
168+
169+ when sql_res is
170+ Ok (_ ) ->
171+ crash " This should be an error."
172+ Err (err) ->
173+ when err is
174+ SqliteErr (err_type, _ ) ->
175+ Stdout . line !("Error : ${Sqlite . errcode_to_str (err_type )}")?
176+ _ ->
177+ crash " This should be an Sqlite error."
178+
179+ Stdout . line !("Success !")
0 commit comments