Skip to content

Commit d42e29f

Browse files
committed
JSON_VALID options
1 parent b65a77d commit d42e29f

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed

GRDB/JSON/SQLJSONFunctions.swift

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,8 +341,19 @@ extension Database {
341341
/// ```
342342
///
343343
/// Related SQLite documentation: <https://www.sqlite.org/json1.html#jvalid>
344-
public static func jsonIsValid(_ value: some SQLExpressible) -> SQLExpression {
345-
.function("JSON_VALID", [value.sqlExpression])
344+
///
345+
/// - parameter value: The tested value.
346+
/// - parameter options: See eventual second argument of the
347+
/// `JSON_VALID` function. See <https://www.sqlite.org/json1.html#the_json_valid_function>.
348+
public static func jsonIsValid(
349+
_ value: some SQLExpressible,
350+
options: JSONValidationOptions? = nil
351+
) -> SQLExpression {
352+
if let options {
353+
.function("JSON_VALID", [value.sqlExpression, options.rawValue.sqlExpression])
354+
} else {
355+
.function("JSON_VALID", [value.sqlExpression])
356+
}
346357
}
347358

348359
/// The `JSON_QUOTE` SQL function.
@@ -425,6 +436,17 @@ extension Database {
425436
// MARK: - JSONB
426437

427438
extension Database {
439+
public struct JSONValidationOptions: OptionSet, Sendable {
440+
public let rawValue: Int
441+
442+
public init(rawValue: Int) { self.rawValue = rawValue }
443+
444+
public static let json = JSONValidationOptions(rawValue: 1)
445+
public static let json5 = JSONValidationOptions(rawValue: 2)
446+
public static let probablyJSONB = JSONValidationOptions(rawValue: 4)
447+
public static let jsonb = JSONValidationOptions(rawValue: 8)
448+
}
449+
428450
/// Validates and returns a binary JSONB representation of the provided
429451
/// JSON, with the `JSONB` SQL function.
430452
///

Tests/GRDBTests/JSONExpressionsTests.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,40 @@ final class JSONExpressionsTests: GRDBTestCase {
20772077
}
20782078
}
20792079

2080+
func test_Database_jsonIsValid_options() throws {
2081+
#if GRDBCUSTOMSQLITE || GRDBCIPHER
2082+
// Prevent SQLCipher failures
2083+
guard sqlite3_libversion_number() >= 3045000 else {
2084+
throw XCTSkip("JSON_VALID options are not available")
2085+
}
2086+
2087+
try makeDatabaseQueue().inDatabase { db in
2088+
try assertEqualSQL(db, Database.jsonIsValid(#"{"x":35""#, options: .json), """
2089+
JSON_VALID('{"x":35"', 1)
2090+
""")
2091+
2092+
try assertEqualSQL(db, Database.jsonIsValid(#"{"x":35""#, options: .json5), """
2093+
JSON_VALID('{"x":35"', 2)
2094+
""")
2095+
2096+
try assertEqualSQL(db, Database.jsonIsValid(#"{"x":35""#, options: .probablyJSONB), """
2097+
JSON_VALID('{"x":35"', 4)
2098+
""")
2099+
2100+
try assertEqualSQL(db, Database.jsonIsValid(#"{"x":35""#, options: .jsonb), """
2101+
JSON_VALID('{"x":35"', 8)
2102+
""")
2103+
2104+
try assertEqualSQL(db, Database.jsonIsValid(#"{"x":35""#, options: [.json, .jsonb]), """
2105+
JSON_VALID('{"x":35"', 9)
2106+
""")
2107+
2108+
}
2109+
#else
2110+
throw XCTSkip("JSON_VALID options are not available")
2111+
#endif
2112+
}
2113+
20802114
func test_Database_jsonQuote() throws {
20812115
#if GRDBCUSTOMSQLITE || GRDBCIPHER
20822116
// Prevent SQLCipher failures

0 commit comments

Comments
 (0)