diff --git a/src/DataIntegrity.php b/src/DataIntegrity.php index 2031fd6..6ff56e0 100644 --- a/src/DataIntegrity.php +++ b/src/DataIntegrity.php @@ -187,10 +187,18 @@ public static function ensureFieldsPresent(dict $row, table_schem // validate json string $json_obj = \json_decode((string)$row[$field_name]); if ($json_obj is null) { - // invalid json - throw new SQLFakeRuntimeException( - "Invalid value '{$field_value}' for column '{$field_name}' on '{$schema['name']}', expected json", - ); + // MySQL will accept the string 'null' in a json column and it converts it to a proper NULL + // the string 'null', however, returns NULL when decoded via \json_decode() which is the same + // as what we get from decoding invalid json + if ((string)$row[$field_name] === 'null') { + $row[$field_name] = null; + $field_value = null; + } else { + // invalid json + throw new SQLFakeRuntimeException( + "Invalid value '{$field_value}' for column '{$field_name}' on '{$schema['name']}', expected json", + ); + } } } else { // empty strings are not valid for json columns diff --git a/tests/InsertQueryTest.php b/tests/InsertQueryTest.php index 7694486..60880b0 100644 --- a/tests/InsertQueryTest.php +++ b/tests/InsertQueryTest.php @@ -260,6 +260,24 @@ final class InsertQueryTest extends HackTest { ); } + public async function testNullStringCapsInsertIntoJsonColumn(): Awaitable { + $conn = static::$conn as nonnull; + QueryContext::$strictSQLMode = true; + expect(() ==> $conn->query("INSERT INTO table_with_json (id, data) VALUES (1, 'NULL')")) + ->toThrow( + SQLFakeRuntimeException::class, + "Invalid value 'NULL' for column 'data' on 'table_with_json', expected json", + ); + } + + public async function testNullStringLowercaseInsertIntoJsonColumn(): Awaitable { + $conn = static::$conn as nonnull; + QueryContext::$strictSQLMode = true; + await $conn->query("INSERT INTO table_with_json (id, data) VALUES (1, 'null')"); + $result = await $conn->query('SELECT * FROM table_with_json'); + expect($result->rows())->toBeSame(vec[dict['id' => 1, 'data' => null]]); + } + public async function testNullInsertIntoJsonColumn(): Awaitable { $conn = static::$conn as nonnull; QueryContext::$strictSQLMode = true;