indexeddb: Implement autoincremented keys and report autoincrementedness properly through DOM interface (#38723)

Autoincrementedness was previously being reported as always false. This
PR makes the state become queried from the backend, as the spec
specifies. Additionally this PR ensures the backend correctly handles an
object store which autoincrements.

Testing: WPT
Fixes: None

---------

Signed-off-by: Ashwin Naren <arihant2math@gmail.com>
This commit is contained in:
Ashwin Naren 2025-08-30 20:54:18 -07:00 committed by GitHub
parent ce35161a6e
commit 91b2ab5458
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 80 additions and 74 deletions

View file

@ -8,7 +8,8 @@ use ipc_channel::ipc::IpcSender;
use log::{error, info};
use net_traits::indexeddb_thread::{
AsyncOperation, AsyncReadOnlyOperation, AsyncReadWriteOperation, BackendError, BackendResult,
CreateObjectResult, IndexedDBKeyRange, IndexedDBTxnMode, KeyPath, PutItemResult,
CreateObjectResult, IndexedDBKeyRange, IndexedDBKeyType, IndexedDBTxnMode, KeyPath,
PutItemResult,
};
use rusqlite::{Connection, Error, OptionalExtension, params};
use sea_query::{Condition, Expr, ExprTrait, IntoCondition, SqliteQueryBuilder};
@ -237,6 +238,22 @@ impl SqliteEngine {
.query_row(&*values.as_params(), |row| row.get(0))
.map(|count: i64| count as usize)
}
fn generate_key(
connection: &Connection,
store: &object_store_model::Model,
) -> Result<IndexedDBKeyType, Error> {
if store.auto_increment == 0 {
unreachable!("Should be caught in the script thread");
}
// TODO: handle overflows, this also needs to be able to handle 2^53 as per spec
let new_key = store.auto_increment + 1;
connection.execute(
"UPDATE object_store SET auto_increment = ? WHERE id = ?",
params![new_key, store.id],
)?;
Ok(IndexedDBKeyType::Number(new_key as f64))
}
}
impl KvsEngine for SqliteEngine {
@ -260,7 +277,7 @@ impl KvsEngine for SqliteEngine {
params![
store_name.to_string(),
key_path.map(|v| bincode::serialize(&v).unwrap()),
auto_increment
auto_increment as i32
],
)?;
@ -350,6 +367,16 @@ impl KvsEngine for SqliteEngine {
let Ok(object_store) = process_object_store(object_store, &sender) else {
continue;
};
let key = match key
.map(Ok)
.unwrap_or_else(|| Self::generate_key(&connection, &object_store))
{
Ok(key) => key,
Err(e) => {
let _ = sender.send(Err(BackendError::DbErr(format!("{:?}", e))));
continue;
},
};
let serialized_key: Vec<u8> = bincode::serialize(&key).unwrap();
let _ = sender.send(
Self::put_item(
@ -442,7 +469,8 @@ impl KvsEngine for SqliteEngine {
.optional()
.unwrap()
// TODO: Wrong (change trait definition for this function)
.unwrap_or_default()
.unwrap_or_default() !=
0
}
fn key_path(&self, store_name: &str) -> Option<KeyPath> {

View file

@ -22,7 +22,7 @@ create table object_store (
name varchar not null
unique,
key_path varbinary_blob,
auto_increment boolean default FALSE not null
auto_increment integer default FALSE not null
);"#;
conn.execute(OBJECT_STORE, [])?;

View file

@ -20,7 +20,7 @@ pub struct Model {
pub id: i32,
pub name: String,
pub key_path: Option<Vec<u8>>,
pub auto_increment: bool,
pub auto_increment: i32,
}
impl TryFrom<&Row<'_>> for Model {

View file

@ -210,7 +210,7 @@ fn test_async_operations() {
store_name: store_name.to_owned(),
operation: AsyncOperation::ReadWrite(AsyncReadWriteOperation::PutItem {
sender: channel.0,
key: IndexedDBKeyType::Number(1.0),
key: Some(IndexedDBKeyType::Number(1.0)),
value: vec![1, 2, 3],
should_overwrite: false,
}),