diff --git a/gren.json b/gren.json index 4a534d8..72a0bfc 100644 --- a/gren.json +++ b/gren.json @@ -1,34 +1,34 @@ { - "type": "package", - "platform": "node", - "name": "gren-lang/node", - "summary": "Run Gren on Node.js", - "license": "BSD-3-Clause", - "version": "6.1.3", - "exposed-modules": [ - "Node", - "Init", - "Terminal", - "ChildProcess", - "FileSystem", - "FileSystem.FileHandle", - "FileSystem.Path", - "HttpClient", - "HttpServer", - "HttpServer.Response", - "WebSocketServer", - "WebSocketServer.Connection", - "Sqlite", - "Sqlite.Decode", - "Sqlite.Decode.Row", - "Sqlite.Encode", - "Sqlite.Encode.Row", - "Sqlite.Function", - "Sqlite.Aggregate" - ], - "gren-version": "0.6.0 <= v < 0.7.0", - "dependencies": { - "gren-lang/core": "7.0.0 <= v < 8.0.0", - "gren-lang/url": "6.0.0 <= v < 7.0.0" - } + "type": "package", + "platform": "node", + "name": "gren-lang/node", + "summary": "Run Gren on Node.js", + "license": "BSD-3-Clause", + "version": "6.1.3", + "exposed-modules": [ + "Node", + "Init", + "Terminal", + "ChildProcess", + "FileSystem", + "FileSystem.FileHandle", + "FileSystem.Path", + "HttpClient", + "HttpServer", + "HttpServer.Response", + "WebSocketServer", + "WebSocketServer.Connection", + "Sqlite", + "Sqlite.Decode", + "Sqlite.Decode.Row", + "Sqlite.Encode", + "Sqlite.Encode.Row", + "Sqlite.Function", + "Sqlite.Aggregate" + ], + "gren-version": "0.6.0 <= v < 0.7.0", + "dependencies": { + "gren-lang/core": "7.0.0 <= v < 8.0.0", + "gren-lang/url": "6.0.0 <= v < 7.0.0" + } } diff --git a/integration-tests/sqlite/src/Main.gren b/integration-tests/sqlite/src/Main.gren index b93fe21..c2cc4fc 100644 --- a/integration-tests/sqlite/src/Main.gren +++ b/integration-tests/sqlite/src/Main.gren @@ -54,7 +54,7 @@ tests fsPerm = , awaitError "syntax error" (Sqlite.executeScript db "SELECT *") <| \err -> test "Is right type" <| \_ -> when err is - Sqlite.GenericError _ -> + Sqlite.Error _ -> Expect.pass _ -> @@ -62,18 +62,14 @@ tests fsPerm = , awaitError "Define friends" (defineFriendsById 1 2 db) <| \err -> test "Fails due to foreign key constraints" <| \_ -> when err is - Sqlite.ForeignKeyError message -> - if String.contains "foreign key" (String.toLower message) then - Expect.pass - - else - Expect.fail "Correct error type, but message doesn't mention foreign key" + Sqlite.ConstraintError Sqlite.ForeignKeyConstraintError -> + Expect.pass _ -> Expect.fail "Failed for unknown reason" , awaitError "Too many templates" (execBadTemplate 3 db) <| \err -> test "Is invalid" <| \_ -> - Expect.equal (Sqlite.GenericError "Unknown named parameter 'id1'") err + Expect.equal (Sqlite.Error "Unknown named parameter 'id1'") err , await "Closing the database" (Sqlite.close db) <| \_ -> test "Works" <| \_ -> Expect.pass @@ -203,11 +199,11 @@ tests fsPerm = , awaitError "Define same friends again" (defineFriends robin.name justin.name db) <| \err -> test "Fails due to unique constraint" <| \_ -> when err is - Sqlite.UniqueConstraintError _ -> + Sqlite.ConstraintError Sqlite.UniqueConstraintError -> Expect.pass _ -> - Expect.fail ("Expected UniqueConstraintError, but got: " ++ Sqlite.errorToString err) + Expect.fail ("Expected UniqueConstraintError") ] ] , await "Open db for executeAll tests" createTestDb <| \db -> diff --git a/src/Gren/Kernel/Sqlite.js b/src/Gren/Kernel/Sqlite.js index b193a46..0905fda 100644 --- a/src/Gren/Kernel/Sqlite.js +++ b/src/Gren/Kernel/Sqlite.js @@ -1,6 +1,6 @@ /* -import Sqlite exposing (GenericError, ForeignKeyError, UniqueConstraintError, DecodingError, MultipleResultsError) +import Sqlite exposing (errorCodeToError, DecodingError, MultipleResultsError) import Gren.Kernel.FilePath exposing (toString) import Gren.Kernel.Scheduler exposing (binding, succeed, fail) import Gren.Kernel.Json exposing (wrap, unwrap) @@ -255,13 +255,7 @@ var _Sqlite_executeScript = F2(function (script, db) { }); var _Sqlite_constructError = function (e) { - if (e.errcode === 787) { - return __Scheduler_fail(__Sqlite_ForeignKeyError(e.message)); - } - - if (e.errcode === 2067) { - return __Scheduler_fail(__Sqlite_UniqueConstraintError(e.message)); - } - - return __Scheduler_fail(__Sqlite_GenericError(e.message)); + return __Scheduler_fail( + A3(__Sqlite_errorCodeToError, e.code, e.errcode, e.message), + ); }; diff --git a/src/Sqlite.gren b/src/Sqlite.gren index 08f84b5..5612d9b 100644 --- a/src/Sqlite.gren +++ b/src/Sqlite.gren @@ -218,33 +218,811 @@ inTransaction db f = -- ERRORS --- TODO: How detailed should we be with errors? +{-|-} type Error - = GenericError String + = AbortError AbortError + | AuthError AuthError + | BusyError BusyError + | CantOpenError CantOpenError + | ConstraintError ConstraintError + | CorruptError CorruptError + | Error String + | IoError IoError + | LockedError LockedError + | MismatchError + | MisuseError + | NoLfsError + | NoMemError + | NotADbError + | NotFoundError + | NoticeError NoticeError + | PermError + | ProtocolError + | RangeError + | ReadOnlyError ReadOnlyError + | FullError + | InternalError + | InterruptError + | TooBigError | NoResultsError + | SchemaError | MultipleResultsError Int - | ForeignKeyError String - | UniqueConstraintError String | DecodingError Decode.Error +{-|-} +type AbortError + = GenericAbortError String + | RollbackAbortError + + +{-|-} +type AuthError + = GenericAuthError String + | UserAuthError + + +{-|-} +type BusyError + = GenericBusyError String + | RecoveryBusyError + | SnapshotBusyError + | TimeoutBusyError + + +{-|-} +type CantOpenError + = GenericCantOpenError String + | ConvPathCantOpenError + | DirtyWalCantOpenError + | FullPathCantOpenError + | IsDirCantOpenError + | NoTempDirCantOpenError + | SymLinkCantOpenError + + +{-|-} +type ConstraintError + = GenericConstraintError String + | CheckConstraintError + | CommitHookConstraintError + | DataTypeConstraintError + | ForeignKeyConstraintError + | FunctionConstraintError + | NotNullConstraintError + | PinnedConstraintError + | PrimaryKeyConstraintError + | RowIdConstraintError + | TriggerConstraintError + | UniqueConstraintError + | VTabConstraintError + + +{-|-} +type CorruptError + = GenericCorruptError String + | IndexCorruptError + | SequenceCorruptError + | VTabCorruptError + + +{-|-} +type IoError + = GenericIoError String + | AccessIoError + | AuthIoError + | BeginAtomicIoError + | BlockedIoError + | CheckReservedLockIoError + | CloseIoError + | CommitAtomicIoError + | ConvPathIoError + | CorruptFsIoError + | DataIoError + | DeleteIoError + | DeleteNoEntIoError + | DirectoryCloseIoError + | DirFSyncIoError + | FStatIoError + | FSyncIoError + | GetTempPathIoError + | LockIoError + | MMapIoError + | NoMemIoError + | RdLockIoError + | ReadIoError + | RollbackAtomicIoError + | SeekIoError + | ShmLockIoError + | ShmMapIoError + | ShmOpenIoError + | ShmSizeIoError + | ShortReadIoError + | TruncateIoError + | UnlockIoError + | VNodeIoError + | WriteIoError + + +{-|-} +type LockedError + = GenericLockedError String + | SharedCacheLockedError + | VTabLockedError + + +{-|-} +type NoticeError + = GenericNoticeError String + | RecoverRollbackNoticeError + | RecoverWalNoticeError + + +{-|-} +type ReadOnlyError + = GenericReadOnlyError String + | CantInitReadOnlyError + | CantLockReadOnlyError + | DbMovedReadOnlyError + | DirectoryReadOnlyError + | RecoveryReadOnlyError + | RollbackReadOnlyError + + +{-|-} +errorCodeToError : String -> Int -> String -> Error +errorCodeToError errorType errorCode message = + when errorType is + "ERR_INVALID_STATE" -> + Error message + + "ERR_SQLITE_ERROR" -> + when errorCode is + -- Abort errors + + 4 -> + AbortError (GenericAbortError message) + + 516 -> + AbortError RollbackAbortError + + -- Auth errors + + 23 -> + AuthError (GenericAuthError message) + + 279 -> + AuthError UserAuthError + + -- Busy errors + + 5 -> + BusyError (GenericBusyError message) + + 261 -> + BusyError RecoveryBusyError + + 517 -> + BusyError SnapshotBusyError + + 773 -> + BusyError TimeoutBusyError + + -- Can't open errors + + 14 -> + CantOpenError (GenericCantOpenError message) + + 1038 -> + CantOpenError ConvPathCantOpenError + + 1294 -> + CantOpenError DirtyWalCantOpenError + + 782 -> + CantOpenError FullPathCantOpenError + + 526 -> + CantOpenError IsDirCantOpenError + + 270 -> + CantOpenError NoTempDirCantOpenError + + 1550 -> + CantOpenError SymLinkCantOpenError + + -- Constraint errors + + 19 -> + ConstraintError (GenericConstraintError message) + + 275 -> + ConstraintError CheckConstraintError + + 531 -> + ConstraintError CommitHookConstraintError + + 3091 -> + ConstraintError DataTypeConstraintError + + 787 -> + ConstraintError ForeignKeyConstraintError + + 1043 -> + ConstraintError FunctionConstraintError + + 1299 -> + ConstraintError NotNullConstraintError + + 2835 -> + ConstraintError PrimaryKeyConstraintError + + 1555 -> + ConstraintError PrimaryKeyConstraintError + + 2579 -> + ConstraintError RowIdConstraintError + + 1811 -> + ConstraintError TriggerConstraintError + + 2067 -> + ConstraintError UniqueConstraintError + + 2323 -> + ConstraintError VTabConstraintError + + -- Corrupt errors + + 11 -> + CorruptError (GenericCorruptError message) + + 779 -> + CorruptError IndexCorruptError + + 523 -> + CorruptError SequenceCorruptError + + 267 -> + CorruptError VTabCorruptError + + -- Error + + 1 -> + Error message + + 257 -> + Error message + + 513 -> + Error message + + 769 -> + Error message + + -- Full error + + 13 -> + FullError + + -- Internal error + + 2 -> + InternalError + + -- Interrupt Error + + 9 -> + InterruptError + + -- IO errors + + 10 -> + IoError (GenericIoError message) + + 3338 -> + IoError AccessIoError + + 7178 -> + IoError AuthIoError + + 7434 -> + IoError BeginAtomicIoError + + 2826 -> + IoError BlockedIoError + + 3594 -> + IoError CheckReservedLockIoError + + 4106 -> + IoError CloseIoError + + 7690 -> + IoError CommitAtomicIoError + + 6666 -> + IoError ConvPathIoError + + 8458 -> + IoError CorruptFsIoError + + 8202 -> + IoError DataIoError + + 2570 -> + IoError DeleteIoError + + 5898 -> + IoError DeleteNoEntIoError + + 4362 -> + IoError CloseIoError + + 1290 -> + IoError DirFSyncIoError + + 1802 -> + IoError FStatIoError + + 1034 -> + IoError FSyncIoError + + 6410 -> + IoError GetTempPathIoError + + 3850 -> + IoError LockIoError + + 6154 -> + IoError MMapIoError + + 3082 -> + IoError NoMemIoError + + 2314 -> + IoError RdLockIoError + + 266 -> + IoError ReadIoError + + 7946 -> + IoError RollbackAtomicIoError + + 5642 -> + IoError SeekIoError + + 5130 -> + IoError ShmLockIoError + + 5386 -> + IoError ShmMapIoError + + 4618 -> + IoError ShmOpenIoError + + 4874 -> + IoError ShmSizeIoError + + 522 -> + IoError ShortReadIoError + + 1546 -> + IoError TruncateIoError + + 2058 -> + IoError UnlockIoError + + 6922 -> + IoError VNodeIoError + + 778 -> + IoError WriteIoError + + -- Locked errors + + 6 -> + LockedError (GenericLockedError message) + + 262 -> + LockedError SharedCacheLockedError + + 518 -> + LockedError VTabLockedError + + -- Mismatch error + + 20 -> + MismatchError + + -- Misuse error + + 21 -> + MisuseError + + -- No LFS error + + 22 -> + NoLfsError + + -- No memory error + + 7 -> + NoMemError + + -- Not a DB error + + 26 -> + NotADbError + + -- Not found error + + 12 -> + NotFoundError + + -- Notice errors + + 27 -> + NoticeError (GenericNoticeError message) + + 539 -> + NoticeError RecoverRollbackNoticeError + + 283 -> + NoticeError RecoverWalNoticeError + + -- Perm error + + 3 -> + PermError + + -- Protocol error + + 15 -> + ProtocolError + + -- Range error + + 25 -> + RangeError + + -- Read only errors + + 8 -> + ReadOnlyError (GenericReadOnlyError message) + + 1288 -> + ReadOnlyError CantInitReadOnlyError + + 520 -> + ReadOnlyError CantLockReadOnlyError + + 1032 -> + ReadOnlyError DbMovedReadOnlyError + + 1544 -> + ReadOnlyError DirectoryReadOnlyError + + 264 -> + ReadOnlyError RecoveryReadOnlyError + + 776 -> + ReadOnlyError RollbackReadOnlyError + + -- Schema error + + 17 -> + SchemaError + + -- Too big error + + 18 -> + TooBigError + + -- All other errors (unknown) + + _ -> + Error message + + _ -> + Error message + + +{-| Transform a given `Error` into a descriptive `String`. + +Each error string for known SQLite errors contain the error code found at https://sqlite.org/rescode.html. +More details on the errors can be found by their code on that page. +-} errorToString : Error -> String -errorToString error = - when error is - GenericError s -> - s +errorToString passedError = + when passedError is + AbortError (GenericAbortError string) -> + "(4) SQLite abort error: " ++ string - NoResultsError -> - "Expected a result but got none." + AbortError RollbackAbortError -> + "(516) SQLite abort error: Transaction rolled back" + + AuthError (GenericAuthError string) -> + "(23) SQLite auth error: " ++ string + + AuthError UserAuthError -> + "(279) SQlite auth error: User lacks the proper authorization" + + BusyError (GenericBusyError string) -> + "(5) SQLite busy error: " ++ string + + BusyError RecoveryBusyError -> + "(261) SQLite busy error: Recovering WAL" + + BusyError SnapshotBusyError -> + "(517) SQLite busy error: Snapshot" + + BusyError TimeoutBusyError -> + "(773) SQLite busy error: Timeout " + + CantOpenError (GenericCantOpenError string) -> + "(14) SQLite can't open error: " ++ string + + CantOpenError ConvPathCantOpenError -> + "(1038) SQLite can't open error: Error with Cygwin VFS" + + CantOpenError DirtyWalCantOpenError -> + "(1294) SQLite can't open error: Error code not in use by SQLite at this time. Please report if you run into this!" + + CantOpenError FullPathCantOpenError -> + "(782) SQLite can't open error: Unable to convert the filename into a full pathname" + + CantOpenError IsDirCantOpenError -> + "(526) SQLite can't open error: File is actually a directory" + + CantOpenError NoTempDirCantOpenError -> + "(270) SQLite can't open error: Error code no longer in use. Please report if you run into this!" + + CantOpenError SymLinkCantOpenError -> + "(1550) SQLite can't open error: SQLITE_OPEN_NOFOLLOW flag is used and the database file is a symbolic link" + + ConstraintError (GenericConstraintError string) -> + "(19) SQLite constraint error: " ++ string + + ConstraintError CheckConstraintError -> + "(275) SQLite constraint error: CHECK constraint failed" + + ConstraintError CommitHookConstraintError -> + "(531) SQLite constraint error: Commit hook callback returned non-zero" + + ConstraintError DataTypeConstraintError -> + "(3091) SQLite constraint error: Incorrect value type inserted into column in STRICT table" + + ConstraintError ForeignKeyConstraintError -> + "(787) SQLite constraint error: Foreign key constraint failed" + + ConstraintError FunctionConstraintError -> + "(1043) SQLite constraint error: Error returned by extension function" + + ConstraintError NotNullConstraintError -> + "(1299) SQLite constraint error: NOT NULL constraint failed" + + ConstraintError PinnedConstraintError -> + "(2835) SQLite constraint error: UPDATE trigger attempted to delete the row that was being updated in the middle of the update" + + ConstraintError PrimaryKeyConstraintError -> + "(1555) SQLite constraint error: PRIMARY KEY constraint failed" + + ConstraintError RowIdConstraintError -> + "(2579) SQLite constraint error: rowid is not unique" + + ConstraintError TriggerConstraintError -> + "(1811) SQLite constraint error: RAISE function within a trigger fired, causing the SQL statement to abort" + + ConstraintError UniqueConstraintError -> + "(2067) SQLite constraint error: UNIQUE constraint failed" + + ConstraintError VTabConstraintError -> + "(2323) SQLite constraint error: Error with application-defined virtual table" + + CorruptError (GenericCorruptError string) -> + "(11) SQLite corrupt error: " ++ string + + CorruptError IndexCorruptError -> + "(779) SQLite corrupt error: Entry missing from index" + + CorruptError SequenceCorruptError -> + "(523) SQLite corrupt error: sqlite_sequence table schema corrupt" + + CorruptError VTabCorruptError -> + "(267) SQLite corrupt error: Virtual table corrupt" + + Error string -> + "Unknown or generic SQLite erorr: " ++ string + + IoError (GenericIoError string) -> + "(10) SQLite IO error: " ++ string + + IoError AccessIoError -> + "(3338) SQLite IO error: I/O error within the xAccess method on the sqlite3_vfs object" + + IoError AuthIoError -> + "(7178) SQLite IO error: SQLite extension error" + + IoError BeginAtomicIoError -> + "(7434) SQLite IO error: Begin atomic write error" + + IoError BlockedIoError -> + "(2826) SQLite IO error: Error code no longer used. Please report if you run into this!" + + IoError CheckReservedLockIoError -> + "(3594) SQLite IO error: xCheckReservedLock method" + + IoError CloseIoError -> + "(4106) SQLite IO error: xClose method" + + IoError CommitAtomicIoError -> + "(7690) SQLite IO error: Commit atomic write error" + + IoError ConvPathIoError -> + "(6666) SQLite IO error: cygwin_conv_path() system call failed" + + IoError CorruptFsIoError -> + "(8458) SQLite IO error: Corrupt filesystem" + + IoError DataIoError -> + "(8202) SQLite IO error: Database page checksum incorrect" + + IoError DeleteIoError -> + "(2570) SQLite IO error: xDelete method" + + IoError DeleteNoEntIoError -> + "(5898) SQLite IO error: File does not exist" + + IoError DirectoryCloseIoError -> + "(4362) SQLite IO error: Error code no longer used. Please report if you run into this!" + + IoError DirFSyncIoError -> + "(1290) SQLite IO error: VFS layer while trying to invoke fsync() on directory" + + IoError FStatIoError -> + "(1802) SQLite IO error: VFS layer while trying to invoke fstat()" - MultipleResultsError n -> - "Expected one result but got " ++ String.fromInt n + IoError FSyncIoError -> + "(1034) SQLite IO error: VFS layer while trying to invoke fsync()" + + IoError GetTempPathIoError -> + "(6410) SQLite IO error: Cannot determine place to put temporary files" + + IoError LockIoError -> + "(3850) SQLite IO error: Advisory file locking logic" + + IoError MMapIoError -> + "(6154) SQLite IO error: xFetch or xUnfetch methods on the sqlite3_io_methods object" + + IoError NoMemIoError -> + "(3082) SQLite IO error: Insufficient memory" + + IoError RdLockIoError -> + "(2314) SQLite IO error: Locking file" + + IoError ReadIoError -> + "(266) SQLite IO error: Reading file from disk" + + IoError RollbackAtomicIoError -> + "(7946) SQLite IO error: Rollback atomic write error" + + IoError SeekIoError -> + "(5642) SQLite IO error: Problem while trying to seek a file descriptor to the beginning point of the file where the read or write is to occur" + + IoError ShmLockIoError -> + "(5130) SQLite IO error: Error code no longer used. Please report if you run into this!" + + IoError ShmMapIoError -> + "(5386) SQLite IO error: xShmMap method on the sqlite3_io_methods object" + + IoError ShmOpenIoError -> + "(4618) SQLite IO error: xShmMap method on the sqlite3_io_methods object while trying to open a new shared memory segment" + + IoError ShmSizeIoError -> + "(4874) SQLite IO error: Filesystem may be out of space" + + IoError ShortReadIoError -> + "(522) SQLite IO error: Bytes gotten does not equal bytes requested" + + IoError TruncateIoError -> + "(1546) SQLite IO error: Error trying to changes the size of a file" + + IoError UnlockIoError -> + "(2058) SQLite IO error: xUnlock method on the sqlite3_io_methods object" + + IoError VNodeIoError -> + "(6922) SQLite IO error: Error returned by extension" + + IoError WriteIoError -> + "(778) SQLite IO error: Writing file to disk" + + LockedError (GenericLockedError string) -> + "(6) SQLite locked error: " ++ string + + LockedError SharedCacheLockedError -> + "(262) SQLite locked error: Access blocked due to another database connecting using the same record" + + LockedError VTabLockedError -> + "(518) SQLite locked error: Virtual table extension locked by another operation" + + MismatchError -> + "(20) SQLite datatype mismatch error" + + MisuseError -> + "(21) SQLite misuse error" + + NoLfsError -> + "(22) SQLite no LFS error: File too large" + + NoMemError -> + "(7) SQLite no memory error: Unable to allocated necessary memory for operation" + + NotADbError -> + "(26) SQLite not a db error: The given file does not seem to be a SQLite database file" + + NotFoundError -> + "(12) SQLite not found error" + + NoticeError (GenericNoticeError string) -> + "(27) SQLite notice: " ++ string + + NoticeError RecoverRollbackNoticeError -> + "(539) SQLite notice: Hot journal rolled back" + + NoticeError RecoverWalNoticeError -> + "(283) SQLite notice: WAL mode database file recovered" + + PermError -> + "(3) SQLite perm error: Requested access mode for a newly created database could not be provided" + + ProtocolError -> + "(15) SQLite protocol error: Problem with file locking protocol" + + RangeError -> + "(25) SQLite range error" + + ReadOnlyError (GenericReadOnlyError string) -> + "(8) SQLite read error: " ++ string + + ReadOnlyError CantInitReadOnlyError -> + "(1288) SQLite read error: Shared memory issue" + + ReadOnlyError CantLockReadOnlyError -> + "(520) SQLite read error: Unable to obtain read lock for WAL" + + ReadOnlyError DbMovedReadOnlyError -> + "(1032) SQLite read error: Database file moved since it was opened" + + ReadOnlyError DirectoryReadOnlyError -> + "(1544) SQLite read error: Unable to create journal file in same directory as database" + + ReadOnlyError RecoveryReadOnlyError -> + "(264) SQLite read error: Database needs recovery but only has read, not write, access" + + ReadOnlyError RollbackReadOnlyError -> + "(776) SQLite read error: Cannot rollback hot journal due to database being read only" + + FullError -> + "(13) SQLite full error: Disk is full and cannot write anymore data to the database" + + InternalError -> + "(2) SQLite internal error: Malfunction with SQLite internals" + + InterruptError -> + "(9) SQLite interrupt error: Operation interrupted" + + TooBigError -> + "(18) SQLite too big error: String or blob larger than 1,000,000,000 bytes" + + NoResultsError -> + "No results returned for the given query" - ForeignKeyError s -> - "Foreign key error: " ++ s + SchemaError -> + "(17) SQLite schema error: Database scheme changed" - UniqueConstraintError s -> - "Unique constraint error: " ++ s + MultipleResultsError int -> + "Obtained multiple results when one was expected. Result count: " ++ (String.fromInt int) - DecodingError e -> - "Error decoding results: " ++ Decode.errorToString e + DecodingError error -> + "SQLite JSON decoding error: " ++ error