empty commit to trigger formatting ci (#20378)

Co-authored-by: nektro <5464072+nektro@users.noreply.github.com>
This commit is contained in:
Meghan Denny
2025-06-13 14:18:28 -08:00
committed by GitHub
parent 82b34bbbdd
commit a445b45e55
3 changed files with 78 additions and 80 deletions

View File

@@ -767,36 +767,36 @@ declare module "bun:sqlite" {
/** /**
* The actual SQLite column types from the first row of the result set. * The actual SQLite column types from the first row of the result set.
* Useful for expressions and computed columns, which are not covered by `declaredTypes` * Useful for expressions and computed columns, which are not covered by `declaredTypes`
* *
* Returns an array of SQLite type constants as uppercase strings: * Returns an array of SQLite type constants as uppercase strings:
* - `"INTEGER"` for integer values * - `"INTEGER"` for integer values
* - `"FLOAT"` for floating-point values * - `"FLOAT"` for floating-point values
* - `"TEXT"` for text values * - `"TEXT"` for text values
* - `"BLOB"` for binary data * - `"BLOB"` for binary data
* - `"NULL"` for null values * - `"NULL"` for null values
* - `null` for unknown/unsupported types * - `null` for unknown/unsupported types
* *
* **Requirements:** * **Requirements:**
* - Only available for read-only statements (SELECT queries) * - Only available for read-only statements (SELECT queries)
* - For non-read-only statements, throws an error * - For non-read-only statements, throws an error
* *
* **Behavior:** * **Behavior:**
* - Uses `sqlite3_column_type()` to get actual data types from the first row * - Uses `sqlite3_column_type()` to get actual data types from the first row
* - Returns `null` for columns with unknown SQLite type constants * - Returns `null` for columns with unknown SQLite type constants
* *
* @example * @example
* ```ts * ```ts
* const stmt = db.prepare("SELECT id, name, age FROM users WHERE id = 1"); * const stmt = db.prepare("SELECT id, name, age FROM users WHERE id = 1");
* *
* console.log(stmt.columnTypes); * console.log(stmt.columnTypes);
* // => ["INTEGER", "TEXT", "INTEGER"] * // => ["INTEGER", "TEXT", "INTEGER"]
* *
* // For expressions: * // For expressions:
* const exprStmt = db.prepare("SELECT length('bun') AS str_length"); * const exprStmt = db.prepare("SELECT length('bun') AS str_length");
* console.log(exprStmt.columnTypes); * console.log(exprStmt.columnTypes);
* // => ["INTEGER"] * // => ["INTEGER"]
* ``` * ```
* *
* @throws Error if statement is not read-only (INSERT, UPDATE, DELETE, etc.) * @throws Error if statement is not read-only (INSERT, UPDATE, DELETE, etc.)
* @since Bun v1.2.13 * @since Bun v1.2.13
*/ */
@@ -804,19 +804,19 @@ declare module "bun:sqlite" {
/** /**
* The declared column types from the table schema. * The declared column types from the table schema.
* *
* Returns an array of declared type strings from `sqlite3_column_decltype()`: * Returns an array of declared type strings from `sqlite3_column_decltype()`:
* - Raw type strings as declared in the CREATE TABLE statement * - Raw type strings as declared in the CREATE TABLE statement
* - `null` for columns without declared types (e.g., expressions, computed columns) * - `null` for columns without declared types (e.g., expressions, computed columns)
* *
* **Requirements:** * **Requirements:**
* - Statement must be executed at least once before accessing this property * - Statement must be executed at least once before accessing this property
* - Available for both read-only and read-write statements * - Available for both read-only and read-write statements
* *
* **Behavior:** * **Behavior:**
* - Uses `sqlite3_column_decltype()` to get schema-declared types * - Uses `sqlite3_column_decltype()` to get schema-declared types
* - Returns the exact type string from the table definition * - Returns the exact type string from the table definition
* *
* @example * @example
* ```ts * ```ts
* // For table columns: * // For table columns:
@@ -824,14 +824,14 @@ declare module "bun:sqlite" {
* stmt.get(); * stmt.get();
* console.log(stmt.declaredTypes); * console.log(stmt.declaredTypes);
* // => ["INTEGER", "TEXT", "REAL"] * // => ["INTEGER", "TEXT", "REAL"]
* *
* // For expressions (no declared types): * // For expressions (no declared types):
* const exprStmt = db.prepare("SELECT length('bun') AS str_length"); * const exprStmt = db.prepare("SELECT length('bun') AS str_length");
* exprStmt.get(); * exprStmt.get();
* console.log(exprStmt.declaredTypes); * console.log(exprStmt.declaredTypes);
* // => [null] * // => [null]
* ``` * ```
* *
* @throws Error if statement hasn't been executed * @throws Error if statement hasn't been executed
* @since Bun v1.2.13 * @since Bun v1.2.13
*/ */
@@ -913,10 +913,10 @@ declare module "bun:sqlite" {
* Native object representing the underlying `sqlite3_stmt` * Native object representing the underlying `sqlite3_stmt`
* *
* This is left untyped because the ABI of the native bindings may change at any time. * This is left untyped because the ABI of the native bindings may change at any time.
* *
* For stable, typed access to statement metadata, use the typed properties on the Statement class: * For stable, typed access to statement metadata, use the typed properties on the Statement class:
* - {@link columnNames} for column names * - {@link columnNames} for column names
* - {@link paramsCount} for parameter count * - {@link paramsCount} for parameter count
* - {@link columnTypes} for actual data types from the first row * - {@link columnTypes} for actual data types from the first row
* - {@link declaredTypes} for schema-declared column types * - {@link declaredTypes} for schema-declared column types
*/ */

View File

@@ -2375,22 +2375,22 @@ JSC_DEFINE_CUSTOM_GETTER(jsSqlStatementGetColumnTypes, (JSGlobalObject * lexical
CHECK_PREPARED CHECK_PREPARED
int count = sqlite3_column_count(castedThis->stmt); int count = sqlite3_column_count(castedThis->stmt);
// We need to reset and step the statement to get fresh types, // We need to reset and step the statement to get fresh types,
// but only do this for read-only statements to avoid side effects // but only do this for read-only statements to avoid side effects
bool isReadOnly = sqlite3_stmt_readonly(castedThis->stmt) != 0; bool isReadOnly = sqlite3_stmt_readonly(castedThis->stmt) != 0;
if (! isReadOnly) { if (!isReadOnly) {
// For non-read-only statements, throw an error since column types don't make sense // For non-read-only statements, throw an error since column types don't make sense
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "columnTypes is not available for non-read-only statements (INSERT, UPDATE, DELETE, etc.)"_s)); throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "columnTypes is not available for non-read-only statements (INSERT, UPDATE, DELETE, etc.)"_s));
return { }; return {};
} }
// Reset the statement (safe for read-only statements) // Reset the statement (safe for read-only statements)
int resetStatus = sqlite3_reset(castedThis->stmt); int resetStatus = sqlite3_reset(castedThis->stmt);
if (resetStatus != SQLITE_OK) { if (resetStatus != SQLITE_OK) {
throwException(lexicalGlobalObject, scope, createSQLiteError(lexicalGlobalObject, castedThis->version_db->db)); throwException(lexicalGlobalObject, scope, createSQLiteError(lexicalGlobalObject, castedThis->version_db->db));
return { }; return {};
} }
MarkedArgumentBuffer args; MarkedArgumentBuffer args;
@@ -2439,7 +2439,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsSqlStatementGetColumnTypes, (JSGlobalObject * lexical
// If there was an error stepping, throw it // If there was an error stepping, throw it
throwException(lexicalGlobalObject, scope, createSQLiteError(lexicalGlobalObject, castedThis->version_db->db)); throwException(lexicalGlobalObject, scope, createSQLiteError(lexicalGlobalObject, castedThis->version_db->db));
sqlite3_reset(castedThis->stmt); sqlite3_reset(castedThis->stmt);
return { }; return {};
} }
// Reset the statement back to its original state // Reset the statement back to its original state
@@ -2462,7 +2462,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsSqlStatementGetColumnDeclaredTypes, (JSGlobalObject *
// Ensure the statement has been executed at least once // Ensure the statement has been executed at least once
if (!castedThis->hasExecuted) { if (!castedThis->hasExecuted) {
throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "Statement must be executed before accessing declaredTypes"_s)); throwException(lexicalGlobalObject, scope, createError(lexicalGlobalObject, "Statement must be executed before accessing declaredTypes"_s));
return { }; return {};
} }
int count = sqlite3_column_count(castedThis->stmt); int count = sqlite3_column_count(castedThis->stmt);
@@ -2472,7 +2472,7 @@ JSC_DEFINE_CUSTOM_GETTER(jsSqlStatementGetColumnDeclaredTypes, (JSGlobalObject *
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
const char* declType = sqlite3_column_decltype(castedThis->stmt, i); const char* declType = sqlite3_column_decltype(castedThis->stmt, i);
JSC::JSValue typeValue; JSC::JSValue typeValue;
if (declType != nullptr) { if (declType != nullptr) {
String typeStr = String::fromUTF8(declType); String typeStr = String::fromUTF8(declType);
typeValue = JSC::jsNontrivialString(vm, typeStr); typeValue = JSC::jsNontrivialString(vm, typeStr);
@@ -2480,10 +2480,10 @@ JSC_DEFINE_CUSTOM_GETTER(jsSqlStatementGetColumnDeclaredTypes, (JSGlobalObject *
// If no declared type (e.g., for expressions or results of functions) // If no declared type (e.g., for expressions or results of functions)
typeValue = JSC::jsNull(); typeValue = JSC::jsNull();
} }
array->putDirectIndex(lexicalGlobalObject, i, typeValue); array->putDirectIndex(lexicalGlobalObject, i, typeValue);
} }
RELEASE_AND_RETURN(scope, JSC::JSValue::encode(array)); RELEASE_AND_RETURN(scope, JSC::JSValue::encode(array));
} }

View File

@@ -1,5 +1,5 @@
import { describe, it, expect } from "bun:test";
import { Database } from "bun:sqlite"; import { Database } from "bun:sqlite";
import { describe, expect, it } from "bun:test";
describe("SQLite Statement column types", () => { describe("SQLite Statement column types", () => {
it("reports correct column types for a variety of data types", () => { it("reports correct column types for a variety of data types", () => {
@@ -25,25 +25,25 @@ describe("SQLite Statement column types", () => {
// Prepare a statement that selects all columns // Prepare a statement that selects all columns
const stmt = db.prepare("SELECT * FROM test_types"); const stmt = db.prepare("SELECT * FROM test_types");
// Execute the statement to get column types // Execute the statement to get column types
const row = stmt.get(); const row = stmt.get();
// Verify column metadata // Verify column metadata
expect(stmt.native.columns).toEqual(["id", "name", "weight", "image", "is_active"]); expect(stmt.native.columns).toEqual(["id", "name", "weight", "image", "is_active"]);
expect(stmt.native.columnsCount).toBe(5); expect(stmt.native.columnsCount).toBe(5);
// Test the columnTypes property (uses actual data types from sqlite3_column_type) // Test the columnTypes property (uses actual data types from sqlite3_column_type)
expect(stmt.columnTypes).toBeDefined(); expect(stmt.columnTypes).toBeDefined();
expect(Array.isArray(stmt.columnTypes)).toBe(true); expect(Array.isArray(stmt.columnTypes)).toBe(true);
expect(stmt.columnTypes.length).toBe(5); expect(stmt.columnTypes.length).toBe(5);
expect(stmt.columnTypes).toEqual(['INTEGER', 'TEXT', 'FLOAT', 'BLOB', 'INTEGER']); expect(stmt.columnTypes).toEqual(["INTEGER", "TEXT", "FLOAT", "BLOB", "INTEGER"]);
// Test the declaredTypes property (uses declared types from sqlite3_column_decltype) // Test the declaredTypes property (uses declared types from sqlite3_column_decltype)
expect(stmt.declaredTypes).toBeDefined(); expect(stmt.declaredTypes).toBeDefined();
expect(Array.isArray(stmt.declaredTypes)).toBe(true); expect(Array.isArray(stmt.declaredTypes)).toBe(true);
expect(stmt.declaredTypes.length).toBe(5); expect(stmt.declaredTypes.length).toBe(5);
expect(stmt.declaredTypes).toEqual(['INTEGER', 'TEXT', 'REAL', 'BLOB', 'INTEGER']); expect(stmt.declaredTypes).toEqual(["INTEGER", "TEXT", "REAL", "BLOB", "INTEGER"]);
}); });
it("handles NULL values correctly", () => { it("handles NULL values correctly", () => {
@@ -59,15 +59,15 @@ describe("SQLite Statement column types", () => {
db.run(`INSERT INTO nulls_test (id, nullable) VALUES (1, NULL)`); db.run(`INSERT INTO nulls_test (id, nullable) VALUES (1, NULL)`);
const stmt = db.prepare("SELECT * FROM nulls_test"); const stmt = db.prepare("SELECT * FROM nulls_test");
// Execute the statement to get column types // Execute the statement to get column types
const row = stmt.get(); const row = stmt.get();
// columnTypes now returns actual data types - NULL values are reported as 'NULL' // columnTypes now returns actual data types - NULL values are reported as 'NULL'
expect(stmt.columnTypes).toEqual(['INTEGER', 'NULL']); expect(stmt.columnTypes).toEqual(["INTEGER", "NULL"]);
// declaredTypes still shows the declared table schema // declaredTypes still shows the declared table schema
expect(stmt.declaredTypes).toEqual(['INTEGER', 'TEXT']); expect(stmt.declaredTypes).toEqual(["INTEGER", "TEXT"]);
}); });
it("reports actual column types based on data values", () => { it("reports actual column types based on data values", () => {
@@ -82,24 +82,24 @@ describe("SQLite Statement column types", () => {
// SQLite can store various types in the same column // SQLite can store various types in the same column
db.run(`INSERT INTO dynamic_types VALUES (1, 42)`); db.run(`INSERT INTO dynamic_types VALUES (1, 42)`);
let stmt = db.prepare("SELECT * FROM dynamic_types"); let stmt = db.prepare("SELECT * FROM dynamic_types");
// Execute the statement to get column types // Execute the statement to get column types
let row = stmt.get(); let row = stmt.get();
// We should get the actual type of the value (integer) // We should get the actual type of the value (integer)
expect(stmt.columnTypes).toEqual(['INTEGER', 'INTEGER']); expect(stmt.columnTypes).toEqual(["INTEGER", "INTEGER"]);
// Update to a text value // Update to a text value
db.run(`UPDATE dynamic_types SET value = 'text' WHERE id = 1`); db.run(`UPDATE dynamic_types SET value = 'text' WHERE id = 1`);
// Re-prepare to get fresh column type information // Re-prepare to get fresh column type information
stmt = db.prepare("SELECT * FROM dynamic_types"); stmt = db.prepare("SELECT * FROM dynamic_types");
row = stmt.get(); row = stmt.get();
// We should get the actual type of the value (text) // We should get the actual type of the value (text)
expect(stmt.columnTypes).toEqual(['INTEGER', 'TEXT']); expect(stmt.columnTypes).toEqual(["INTEGER", "TEXT"]);
// Update to a float value // Update to a float value
db.run(`UPDATE dynamic_types SET value = 3.14 WHERE id = 1`); db.run(`UPDATE dynamic_types SET value = 3.14 WHERE id = 1`);
@@ -109,7 +109,7 @@ describe("SQLite Statement column types", () => {
row = stmt.get(); row = stmt.get();
// We should get the actual type of the value (float) // We should get the actual type of the value (float)
expect(stmt.columnTypes).toEqual(['INTEGER', 'FLOAT']); expect(stmt.columnTypes).toEqual(["INTEGER", "FLOAT"]);
}); });
it("reports actual types for columns from expressions", () => { it("reports actual types for columns from expressions", () => {
@@ -124,14 +124,14 @@ describe("SQLite Statement column types", () => {
expect(row).toEqual({ expect(row).toEqual({
str_length: 3, str_length: 3,
magic_number: 42, magic_number: 42,
greeting: "hello" greeting: "hello",
}); });
// Check columns are correctly identified // Check columns are correctly identified
expect(stmt.native.columns).toEqual(['str_length', 'magic_number', 'greeting']); expect(stmt.native.columns).toEqual(["str_length", "magic_number", "greeting"]);
// For expressions, expect the actual data types // For expressions, expect the actual data types
expect(stmt.columnTypes).toEqual(['INTEGER', 'INTEGER', 'TEXT']); expect(stmt.columnTypes).toEqual(["INTEGER", "INTEGER", "TEXT"]);
}); });
it("handles multiple different expressions and functions", () => { it("handles multiple different expressions and functions", () => {
@@ -148,33 +148,31 @@ describe("SQLite Statement column types", () => {
length('bun') AS func_result, length('bun') AS func_result,
CURRENT_TIMESTAMP AS timestamp CURRENT_TIMESTAMP AS timestamp
`); `);
const row = stmt.get(); const row = stmt.get();
// Verify we have the expected columns // Verify we have the expected columns
expect(stmt.native.columns).toEqual([ expect(stmt.native.columns).toEqual([
'int_val', "int_val",
'float_val', "float_val",
'text_val', "text_val",
'blob_val', "blob_val",
'null_val', "null_val",
'func_result', "func_result",
'timestamp' "timestamp",
]); ]);
// Expression columns should be reported with their actual types // Expression columns should be reported with their actual types
expect(stmt.columnTypes).toEqual([ expect(stmt.columnTypes).toEqual(["INTEGER", "FLOAT", "TEXT", "BLOB", "NULL", "INTEGER", "TEXT"]);
'INTEGER', 'FLOAT', 'TEXT', 'BLOB', 'NULL', 'INTEGER', 'TEXT'
]);
// Verify data types were correctly identified at runtime // Verify data types were correctly identified at runtime
expect(typeof row.int_val).toBe('number'); expect(typeof row.int_val).toBe("number");
expect(typeof row.float_val).toBe('number'); expect(typeof row.float_val).toBe("number");
expect(typeof row.text_val).toBe('string'); expect(typeof row.text_val).toBe("string");
expect(row.blob_val instanceof Uint8Array).toBe(true); expect(row.blob_val instanceof Uint8Array).toBe(true);
expect(row.null_val).toBe(null); expect(row.null_val).toBe(null);
expect(typeof row.func_result).toBe('number'); expect(typeof row.func_result).toBe("number");
expect(typeof row.timestamp).toBe('string'); expect(typeof row.timestamp).toBe("string");
}); });
it("shows difference between columnTypes and declaredTypes for expressions", () => { it("shows difference between columnTypes and declaredTypes for expressions", () => {
@@ -185,8 +183,8 @@ describe("SQLite Statement column types", () => {
const row = stmt.get(); const row = stmt.get();
// columnTypes shows actual data types based on the values // columnTypes shows actual data types based on the values
expect(stmt.columnTypes).toEqual(['INTEGER', 'INTEGER', 'TEXT']); expect(stmt.columnTypes).toEqual(["INTEGER", "INTEGER", "TEXT"]);
// declaredTypes shows declared types (which are null for expressions without explicit declarations) // declaredTypes shows declared types (which are null for expressions without explicit declarations)
expect(stmt.declaredTypes).toEqual([null, null, null]); expect(stmt.declaredTypes).toEqual([null, null, null]);
}); });
@@ -203,27 +201,27 @@ describe("SQLite Statement column types", () => {
// Insert an integer value // Insert an integer value
db.run(`INSERT INTO dynamic_types VALUES (1, 42)`); db.run(`INSERT INTO dynamic_types VALUES (1, 42)`);
let stmt = db.prepare("SELECT * FROM dynamic_types"); let stmt = db.prepare("SELECT * FROM dynamic_types");
let row = stmt.get(); let row = stmt.get();
// columnTypes shows actual type (integer) for the current value // columnTypes shows actual type (integer) for the current value
expect(stmt.columnTypes).toEqual(['INTEGER', 'INTEGER']); expect(stmt.columnTypes).toEqual(["INTEGER", "INTEGER"]);
// declaredTypes shows the declared table schema // declaredTypes shows the declared table schema
expect(stmt.declaredTypes).toEqual(['INTEGER', 'ANY']); expect(stmt.declaredTypes).toEqual(["INTEGER", "ANY"]);
// Update to a text value // Update to a text value
db.run(`UPDATE dynamic_types SET value = 'text' WHERE id = 1`); db.run(`UPDATE dynamic_types SET value = 'text' WHERE id = 1`);
stmt = db.prepare("SELECT * FROM dynamic_types"); stmt = db.prepare("SELECT * FROM dynamic_types");
row = stmt.get(); row = stmt.get();
// columnTypes now shows text for the current value // columnTypes now shows text for the current value
expect(stmt.columnTypes).toEqual(['INTEGER', 'TEXT']); expect(stmt.columnTypes).toEqual(["INTEGER", "TEXT"]);
// declaredTypes still shows the declared table schema // declaredTypes still shows the declared table schema
expect(stmt.declaredTypes).toEqual(['INTEGER', 'ANY']); expect(stmt.declaredTypes).toEqual(["INTEGER", "ANY"]);
}); });
it("throws an error when accessing columnTypes before statement execution", () => { it("throws an error when accessing columnTypes before statement execution", () => {
@@ -235,7 +233,7 @@ describe("SQLite Statement column types", () => {
// Accessing columnTypes before executing is fine (implicitly executes the statement) // Accessing columnTypes before executing is fine (implicitly executes the statement)
expect(stmt.columnTypes).toBeArray(); expect(stmt.columnTypes).toBeArray();
// Accessing declaredTypes before executing should throw // Accessing declaredTypes before executing should throw
expect(() => { expect(() => {
stmt.declaredTypes; stmt.declaredTypes;