a database layer insipred by caqti and ecto
at main 6.4 kB view raw
1open Repodb 2 3let test_sql_type_name_int () = 4 Alcotest.(check string) 5 "int maps to INTEGER" "INTEGER" 6 (Types.sql_type_name Types.int) 7 8let test_sql_type_name_int64 () = 9 Alcotest.(check string) 10 "int64 maps to BIGINT" "BIGINT" 11 (Types.sql_type_name Types.int64) 12 13let test_sql_type_name_string () = 14 Alcotest.(check string) 15 "string maps to TEXT" "TEXT" 16 (Types.sql_type_name Types.string) 17 18let test_sql_type_name_bool () = 19 Alcotest.(check string) 20 "bool maps to BOOLEAN" "BOOLEAN" 21 (Types.sql_type_name Types.bool) 22 23let test_sql_type_name_float () = 24 Alcotest.(check string) 25 "float maps to DOUBLE PRECISION" "DOUBLE PRECISION" 26 (Types.sql_type_name Types.float) 27 28let test_sql_type_name_ptime () = 29 Alcotest.(check string) 30 "ptime maps to TIMESTAMPTZ" "TIMESTAMPTZ" 31 (Types.sql_type_name Types.ptime) 32 33let test_sql_type_name_pdate () = 34 Alcotest.(check string) 35 "pdate maps to DATE" "DATE" 36 (Types.sql_type_name Types.pdate) 37 38let test_sql_type_name_pdate_sqlite () = 39 Alcotest.(check string) 40 "pdate maps to TEXT for SQLite" "TEXT" 41 (Types.sql_type_name_for_sqlite Types.pdate) 42 43let test_sql_type_name_uuid () = 44 Alcotest.(check string) 45 "uuid maps to UUID" "UUID" 46 (Types.sql_type_name Types.uuid) 47 48let test_sql_type_name_json () = 49 Alcotest.(check string) 50 "json maps to JSONB" "JSONB" 51 (Types.sql_type_name Types.json) 52 53let test_sql_type_name_option () = 54 Alcotest.(check string) 55 "option string still maps to TEXT" "TEXT" 56 (Types.sql_type_name (Types.option Types.string)) 57 58let test_sql_type_name_array () = 59 Alcotest.(check string) 60 "array int maps to INTEGER[]" "INTEGER[]" 61 (Types.sql_type_name (Types.array Types.int)) 62 63let test_is_nullable_option () = 64 Alcotest.(check bool) 65 "option is nullable" true 66 (Types.is_nullable (Types.option Types.string)) 67 68let test_is_nullable_non_option () = 69 Alcotest.(check bool) 70 "non-option is not nullable" false 71 (Types.is_nullable Types.string) 72 73let test_custom_type () = 74 let custom = 75 Types.custom 76 ~encode:(fun s -> Ok s) 77 ~decode:(fun s -> Ok s) 78 ~sql_type:"CUSTOM_TYPE" 79 in 80 Alcotest.(check string) 81 "custom type name" "CUSTOM_TYPE" 82 (Types.sql_type_name custom) 83 84let test_pdate_to_value () = 85 let date : Ptime.date = (2024, 1, 15) in 86 let value = Types.to_value Types.pdate date in 87 match value with 88 | Driver.Value.Text s -> 89 Alcotest.(check string) "date serializes to YYYY-MM-DD" "2024-01-15" s 90 | _ -> Alcotest.fail "expected Text value" 91 92let test_pdate_to_value_single_digit_month_day () = 93 let date : Ptime.date = (2024, 3, 5) in 94 let value = Types.to_value Types.pdate date in 95 match value with 96 | Driver.Value.Text s -> 97 Alcotest.(check string) "single digit month/day padded" "2024-03-05" s 98 | _ -> Alcotest.fail "expected Text value" 99 100let test_pdate_of_value () = 101 let value = Driver.Value.Text "2024-01-15" in 102 match Types.of_value Types.pdate value with 103 | Ok (y, m, d) -> 104 Alcotest.(check int) "year" 2024 y; 105 Alcotest.(check int) "month" 1 m; 106 Alcotest.(check int) "day" 15 d 107 | Error e -> Alcotest.fail ("failed to parse date: " ^ e) 108 109let test_pdate_of_value_unpadded () = 110 let value = Driver.Value.Text "2024-3-5" in 111 match Types.of_value Types.pdate value with 112 | Ok (y, m, d) -> 113 Alcotest.(check int) "year" 2024 y; 114 Alcotest.(check int) "month" 3 m; 115 Alcotest.(check int) "day" 5 d 116 | Error e -> Alcotest.fail ("failed to parse date: " ^ e) 117 118let test_pdate_roundtrip () = 119 let original : Ptime.date = (2023, 12, 31) in 120 let value = Types.to_value Types.pdate original in 121 match Types.of_value Types.pdate value with 122 | Ok result -> 123 Alcotest.(check (triple int int int)) 124 "roundtrip preserves date" original result 125 | Error e -> Alcotest.fail ("roundtrip failed: " ^ e) 126 127let test_pdate_of_value_invalid () = 128 let value = Driver.Value.Text "not-a-date" in 129 match Types.of_value Types.pdate value with 130 | Ok _ -> Alcotest.fail "should have failed on invalid date" 131 | Error _ -> () 132 133let test_pdate_of_value_null () = 134 let value = Driver.Value.Null in 135 match Types.of_value Types.pdate value with 136 | Ok _ -> Alcotest.fail "should have failed on NULL" 137 | Error _ -> () 138 139let test_pdate_option_null () = 140 let value = Driver.Value.Null in 141 match Types.of_value (Types.option Types.pdate) value with 142 | Ok None -> () 143 | Ok (Some _) -> Alcotest.fail "expected None for NULL" 144 | Error e -> Alcotest.fail ("unexpected error: " ^ e) 145 146let test_pdate_option_some () = 147 let value = Driver.Value.Text "2024-06-15" in 148 match Types.of_value (Types.option Types.pdate) value with 149 | Ok (Some (y, m, d)) -> 150 Alcotest.(check int) "year" 2024 y; 151 Alcotest.(check int) "month" 6 m; 152 Alcotest.(check int) "day" 15 d 153 | Ok None -> Alcotest.fail "expected Some date" 154 | Error e -> Alcotest.fail ("unexpected error: " ^ e) 155 156let tests = 157 [ 158 ("sql_type_name int", `Quick, test_sql_type_name_int); 159 ("sql_type_name int64", `Quick, test_sql_type_name_int64); 160 ("sql_type_name string", `Quick, test_sql_type_name_string); 161 ("sql_type_name bool", `Quick, test_sql_type_name_bool); 162 ("sql_type_name float", `Quick, test_sql_type_name_float); 163 ("sql_type_name ptime", `Quick, test_sql_type_name_ptime); 164 ("sql_type_name pdate", `Quick, test_sql_type_name_pdate); 165 ("sql_type_name pdate sqlite", `Quick, test_sql_type_name_pdate_sqlite); 166 ("sql_type_name uuid", `Quick, test_sql_type_name_uuid); 167 ("sql_type_name json", `Quick, test_sql_type_name_json); 168 ("sql_type_name option", `Quick, test_sql_type_name_option); 169 ("sql_type_name array", `Quick, test_sql_type_name_array); 170 ("is_nullable option", `Quick, test_is_nullable_option); 171 ("is_nullable non-option", `Quick, test_is_nullable_non_option); 172 ("custom type", `Quick, test_custom_type); 173 ("pdate to_value", `Quick, test_pdate_to_value); 174 ("pdate to_value padded", `Quick, test_pdate_to_value_single_digit_month_day); 175 ("pdate of_value", `Quick, test_pdate_of_value); 176 ("pdate of_value unpadded", `Quick, test_pdate_of_value_unpadded); 177 ("pdate roundtrip", `Quick, test_pdate_roundtrip); 178 ("pdate of_value invalid", `Quick, test_pdate_of_value_invalid); 179 ("pdate of_value null", `Quick, test_pdate_of_value_null); 180 ("pdate option null", `Quick, test_pdate_option_null); 181 ("pdate option some", `Quick, test_pdate_option_some); 182 ]