Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Indexeddb #342

Open
wants to merge 105 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
8bb3823
First sketch of a Indexed DB API wrpper.
Joe-Jones Jan 8, 2018
4691a8c
Merge branch 'master' into indexeddb-merge
Joe-Jones May 10, 2018
bee82d7
Merge branch 'master' into indexeddb
Joe-Jones May 12, 2018
61b3a18
start of indexeddb example
Joe-Jones May 20, 2018
4c7c2ed
Saving here before I have to change IDBCursor
Joe-Jones May 21, 2018
b8b968e
finished display_data
Joe-Jones May 21, 2018
1a0f826
made this compile
Joe-Jones May 24, 2018
52e5408
Adding and displaying.
Joe-Jones May 24, 2018
2f47e9c
Last function needed for the demo, not working yet.
Joe-Jones May 27, 2018
25c02ad
It's working.
May 28, 2018
ec4b8e5
Tidy up all the console.logs I added.
Joe-Jones May 28, 2018
66fd193
Get rid of all the warings in the example code.
Joe-Jones May 28, 2018
9af4a54
Get rid of most the warnings and add a little more documentation.
Joe-Jones May 29, 2018
a86733a
Merge branch 'master' into indexeddb
Joe-Jones May 29, 2018
70926f9
remove changes I made to minimal example.
Joe-Jones May 29, 2018
38a39e2
Get rid of pointless white spae change.
Joe-Jones May 30, 2018
9c339b9
Work on IDBRequest.
Joe-Jones May 31, 2018
e6a24f4
Merge branch 'master' into indexeddb
Joe-Jones Jun 25, 2018
a3da606
Finished with IDBRequest.
Joe-Jones Jun 25, 2018
e78d890
Finished with IDBOpenDBRequest.
Joe-Jones Jun 25, 2018
0dca1a0
working on the advance method in IDBCursorSharedMethods.
Joe-Jones Jun 25, 2018
5390ff0
Finished with IDBCursor and IDBCursorWithValue.
Joe-Jones Jun 26, 2018
11d1b77
Merge branch 'master' into indexeddb
Joe-Jones Jul 15, 2018
bea659a
Not finished with create_index or delete index.
Joe-Jones Jul 16, 2018
df4b455
Merge branch 'master' into indexeddb
Joe-Jones Jul 16, 2018
c45baaa
Finished with IDBKeyRange
Joe-Jones Jul 16, 2018
c2435d8
Merge branch 'master' into indexeddb
Joe-Jones Jul 17, 2018
6054f0f
Some more of IDBTransaction.
Joe-Jones Jul 17, 2018
5511d2e
Still got a couple more interfaces to finish.
Joe-Jones Jul 25, 2018
6478b5a
Merge branch 'master' into indexeddb
Joe-Jones Jul 25, 2018
bcfbe69
A little more work on IDBDatabase.
Joe-Jones Jul 25, 2018
2b0434a
Sort out the error enum names and reformat a bit.
Joe-Jones Jul 25, 2018
71ddbd9
An implementaiotn of DOMStringList
Joe-Jones Jul 29, 2018
e38012e
More bits and bobs.
Joe-Jones Jul 30, 2018
0da2963
This ain't working.
Joe-Jones Aug 1, 2018
94d097f
Sort out transaction.
Joe-Jones Aug 1, 2018
b453bc1
Add a little more documentation.
Joe-Jones Aug 1, 2018
8bfe9b5
Merge branch 'master' into indexeddb
Joe-Jones Aug 1, 2018
5d29d4a
Think I've fixed this.
Joe-Jones Aug 6, 2018
44f87b5
Merge branch 'master' into indexeddb
Joe-Jones Aug 6, 2018
ef87bcc
Merge branch 'master' into indexeddb
Joe-Jones Sep 3, 2018
76139fb
Merge branch 'master' into indexeddb
Joe-Jones Sep 23, 2018
ff22c06
Make it compile again.
Joe-Jones Sep 24, 2018
04cf8bf
Get rid of warnings.
Joe-Jones Sep 24, 2018
43bcb27
Merge branch 'master' into indexeddb
Joe-Jones Sep 25, 2018
f812296
Merge branch 'master' into indexeddb
Joe-Jones Oct 17, 2018
cc9b9a3
Merge branch 'master' into indexeddb
Joe-Jones Nov 2, 2018
65cd91f
Merge branch 'master' into indexeddb
Nov 12, 2018
2d85286
Merge branch 'master' into indexeddb
Nov 18, 2018
c7990fe
Little tidy up.
Nov 18, 2018
7f0de89
Merge branch 'master' into indexeddb
Nov 26, 2018
324ac9b
Merge branch 'master' into indexeddb
Jan 26, 2019
788e8a8
Remove dead code in example
iceiix May 23, 2019
d87b81a
Remove unnecessary <script> for canvas in indexeddb example
iceiix May 23, 2019
5fa10bd
Replace IDB -> Db
iceiix May 23, 2019
cc1d178
Fix revert reference instance_of IDB
iceiix May 23, 2019
fddd754
Add comment links to WebIDL errors
iceiix May 23, 2019
d7dacbd
Remove more dead code comments
iceiix May 23, 2019
48da190
Remove IDL comments
iceiix May 23, 2019
21abe13
Add documentation for oncomplete/onerror handlers
iceiix May 23, 2019
c975d4a
Remove the None variant of DbRequestSource
iceiix May 23, 2019
220776c
Revert IDB -> Db change back to Db -> IDB, broke links
iceiix May 23, 2019
f83cff3
Add link to specs IDBRequest
iceiix May 23, 2019
42438a5
Add missing return to error
iceiix May 23, 2019
a392a39
Fix doubled whitespace after ->
iceiix May 23, 2019
d3db3d4
Change source to return an Option<IDBRequestSource>
iceiix May 23, 2019
454de21
Fix typo with backticks in IDBRequest
iceiix May 23, 2019
6ac1bcb
Word-wrap comment
iceiix May 23, 2019
40f1aed
Add link to IDBFactory specs
iceiix May 23, 2019
5b08f18
Split database open() to open_with_version(), removing <T: Into<Optio…
iceiix May 23, 2019
6e94092
Derive more for IDBCursorDirection
iceiix May 24, 2019
b835ee5
Use match instead of chained if/else
iceiix May 24, 2019
6833fd5
Fix value typo
iceiix May 24, 2019
365bc9b
Remove empty doc comments
iceiix May 24, 2019
93551a4
Add missing semicolons in JavaScript
iceiix May 24, 2019
04953f5
Actually fix missing return in error return
iceiix May 24, 2019
7b5eecb
Add link to IDBCursor spec
iceiix May 24, 2019
03816a4
Fix missing semicolon in js value and indentation
iceiix May 24, 2019
6047c3d
Add IDBKeyRange spec link
iceiix May 24, 2019
9cacfec
Fix mothods typo
iceiix May 24, 2019
3640e30
Fix get_all() method typo
iceiix May 24, 2019
fbb0691
Simplify get_all count param to Option<u32>
iceiix May 24, 2019
49a253e
Revert "Remove empty doc comments"
iceiix May 24, 2019
cb99095
Write a docstring for IDBAddError
iceiix May 24, 2019
a0b2543
Replace more Into<Option<>> generic with Option<>
iceiix May 24, 2019
6ba12cb
More spec links
iceiix May 24, 2019
c6c76f5
Fix the typo
iceiix May 24, 2019
694f7ca
Add missing index_names js semicolon
iceiix May 24, 2019
38c08a6
Into<Option> -> Option
iceiix May 24, 2019
a1eaa97
Another generic removal, add
iceiix May 24, 2019
0ae7cde
Capitalize comment
iceiix May 24, 2019
d1618ff
Remove dead comment:
iceiix May 24, 2019
84d1413
Use match in string_to_transaction_mode
iceiix May 24, 2019
763c8bc
Remove unnecessary whitespace change in window
iceiix May 24, 2019
29399ed
Improve the indexed_db docstring
iceiix May 24, 2019
9b397c5
Merge branch 'master' into indexeddb
iceiix May 24, 2019
238eabf
Add IDBIndexParameters, change create_index to take instead of Value
iceiix May 24, 2019
5d2dd5d
Split create_index to _with_options
iceiix May 24, 2019
5919271
Use match on ready_state
iceiix May 24, 2019
c48b7bd
Extract redundant IDBCursorSource
iceiix May 24, 2019
205086d
IDBCursorWithValue subclasses IDBCursor
iceiix May 24, 2019
aa4e630
Rename IDBObjectStoreIndexSharedMethods to DatabaseStorage
iceiix May 24, 2019
5f9ef94
Fix typo in example comment, didn't
iceiix May 24, 2019
7ae6f14
Rebuild
iceiix May 25, 2019
f5b0209
Rebuild
iceiix May 29, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[workspace]
members = ["canvas", "drag", "echo", "gamepad", "hasher", "minimal", "todomvc", "webgl", "wasm-bindgen-minimal"]
members = ["canvas", "drag", "echo", "gamepad", "hasher", "indexeddb", "minimal", "todomvc", "webgl", "wasm-bindgen-minimal"]
9 changes: 9 additions & 0 deletions examples/indexeddb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "indexeddb_example"
version = "0.1.0"
authors = ["Joe Jones <[email protected]>"]

[dependencies]
stdweb = { path = "../.." }
serde="*"
serde_derive="*"
250 changes: 250 additions & 0 deletions examples/indexeddb/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
#[macro_use]
extern crate stdweb;

#[macro_use]
extern crate serde_derive;

extern crate serde;

use std::cell::RefCell;

use stdweb::traits::*;
use stdweb::web::{
Element,
window,
document,
IEventTarget,
};

use stdweb::web::html_element::InputElement;

use stdweb::web::event::IEvent;

use stdweb::web::event::{
IDBSuccessEvent,
IDBVersionChangeEvent,
IDBCompleteEvent,
IDBErrorEvent,
SubmitEvent,
ClickEvent
};

use stdweb::web::indexeddb::{
IDBOpenDBRequest,
IDBDatabase,
IDBRequest,
IDBRequestSharedMethods,
DatabaseStorage,
IDBCursorWithValue,
IDBCursorSharedMethods,
IDBIndexParameters,
IDBTransactionMode
};

use stdweb::unstable::TryInto;

#[derive(Serialize, Deserialize)]
struct Note {
title: String,
body: String
}

js_serializable!( Note );
js_deserializable!( Note );

thread_local!(static DB: RefCell<Option<IDBDatabase>> = RefCell::new(None));

fn display_data_inner(db: &IDBDatabase) {
let list = document().query_selector("ul").unwrap().unwrap();
// Here we empty the contents of the list element each time the display is updated
// If you didn't do this, you'd get duplicates listed each time a new note is added
while list.first_child().is_some() {
list.remove_child(&list.first_child().unwrap()).unwrap();
}
// Open our object store and then get a cursor - which iterates through all the
// different data items in the store
let object_store = db.transaction(vec!["notes"], IDBTransactionMode::ReadOnly).object_store("notes").unwrap();
object_store.open_cursor(None, None).unwrap()
.add_event_listener( move |e: IDBSuccessEvent| {
// Get a reference to the cursor
let db_request: IDBRequest = e.target().unwrap().try_into().unwrap();
let maybe_cursor: Result<IDBCursorWithValue, stdweb::private::ConversionError> = db_request.result().unwrap().try_into();

// If there is still another data item to iterate through, keep running this code
if let Ok(cursor) = maybe_cursor {
// Create a list item, h3, and p to put each data item inside when displaying it
// structure the HTML fragment, and append it inside the list
let list_item = document().create_element("li").unwrap();
let h3 = document().create_element("h3").unwrap();
let para = document().create_element("p").unwrap();

list_item.append_child(&h3);
list_item.append_child(&para);
list.append_child(&list_item);

let note: Note = cursor.value().try_into().unwrap();

// Put the data from the cursor inside the h3 and para
h3.set_text_content(&note.title);
para.set_text_content(&note.body);

// Store the ID of the data item inside an attribute on the list_item, so we know
// which item it corresponds to. This will be useful later when we want to delete items
let id: u32 = cursor.key().try_into().unwrap();
list_item.set_attribute("data-note-id", &format!("{}", id)).unwrap();
// Create a button and place it inside each list_item
let delete_btn = document().create_element("button").unwrap();
list_item.append_child(&delete_btn);
delete_btn.set_text_content("Delete");

// Set an event handler so that when the button is clicked, the deleteItem()
// function is run
delete_btn.add_event_listener( delete_item );

// Iterate to the next item in the cursor
cursor.advance(1).unwrap(); // Todo this was continue

} else {
// Again, if list item is empty, display a 'No notes stored' message
if list.first_child().is_none() {
let list_item = document().create_element("li").unwrap();
list_item.set_text_content("No notes stored.");
list.append_child(&list_item);
}
// if there are no more cursor items to iterate through, say so
console!(log, "Notes all displayed");
}
});}

fn display_data() {
DB.with(|db_cell| {
if let Some(ref db) = *db_cell.borrow_mut() {
display_data_inner(db);
}})
}

// Define the deleteItem() function
fn delete_item( e: ClickEvent ) {
// retrieve the name of the task we want to delete. We need
// to convert it to a number before trying it use it with IDB; IDB key
// values are type-sensitive.
let button: Element = e.target().unwrap().try_into().unwrap();
let note: Element = button.parent_node().unwrap().try_into().unwrap();
let note_id = note.get_attribute("data-note-id").unwrap().parse::<u32>().unwrap();

// open a database transaction and delete the task, finding it using the id we retrieved above
DB.with(|db_cell| {
if let Some(ref db) = *db_cell.borrow_mut() {
let transaction = db.transaction(vec!["notes"], IDBTransactionMode::ReadWrite);
let object_store = transaction.object_store("notes").unwrap();
object_store.delete(note_id.try_into().unwrap()).unwrap();

// report that the data item has been deleted
transaction.add_event_listener( move |_e: IDBCompleteEvent| {
// delete the parent of the button
// which is the list item, so it is no longer displayed
note.parent_node().unwrap().remove_child(&note).unwrap();
console!(log, "Note ", note_id, "deleted.");

// Again, if list item is empty, display a 'No notes stored' message
let list = document().query_selector("ul").unwrap().unwrap();
if ! list.first_child().is_some() {
let list_item = document().create_element("li").unwrap();
list_item.set_text_content("No notes stored.");
list.append_child(&list_item);
}
});
}});
}

fn main() {
stdweb::initialize();

// Open our database; it is created if it doesn't already exist
// (see onupgradeneeded below)
let request = window().indexed_db().open_with_version("notes", 1);

// onerror handler signifies that the database didn't open successfully
request.add_event_listener( | _e: IDBErrorEvent| {
js!(
console.log("Database failed to open");
);
});

// onsuccess handler signifies that the database opened successfully
request.add_event_listener( move |event: IDBSuccessEvent| {
js!(
console.log("Database opened succesfully");
);

let db_request: IDBOpenDBRequest = event.target().unwrap().try_into().unwrap();
// Store the opened database object in the db variable. This is used a lot below
let db : IDBDatabase = db_request.database_result().unwrap();

DB.with(|db_cell| {
db_cell.replace(Some(db));
});
// Run the displayData() function to display the notes already in the IDB
display_data();
});

request.add_event_listener( |event: IDBVersionChangeEvent| {
let db_request: IDBOpenDBRequest = event.target().unwrap().try_into().unwrap();
let db_: IDBDatabase = db_request.result().unwrap().try_into().unwrap();

// Create an object_store to store our notes in (basically like a single table)
let object_store = db_.create_object_store("notes", true, "").unwrap();

// Define what data items the object_store will contain
object_store.create_index("title", "title");

let body_options = IDBIndexParameters { unique: false, multi_entry: false };
object_store.create_index_with_options("body", "body", body_options);

js!(
console.log("Database setup complete");
);

});

let form = document().query_selector("form").unwrap().unwrap();
form.add_event_listener( move |e: SubmitEvent | {
// prevent default - we don't want the form to submit in the conventional way
e.prevent_default();

// grab the values entered into the form fields and store them in an object ready for being inserted into the DB
let title_input: InputElement = document().query_selector("#title").unwrap().unwrap().try_into().unwrap();
let body_input: InputElement = document().query_selector("#body").unwrap().unwrap().try_into().unwrap();
let new_item = Note{ title: title_input.raw_value(), body: body_input.raw_value() };

DB.with(|db_cell| {
if let Some(ref db) = *db_cell.borrow_mut() {
// open a read/write db transaction, ready for adding the data
let transaction = db.transaction(vec!["notes"], IDBTransactionMode::ReadWrite);

// call an object store that's already been added to the database
let object_store = transaction.object_store("notes").unwrap();

// Make a request to add our new_item object to the object store
let request = object_store.add(new_item.try_into().unwrap(), None).unwrap();

request.add_event_listener( move |_e: IDBSuccessEvent| {
// Clear the form, ready for adding the next entry
title_input.set_raw_value("");
body_input.set_raw_value("");
});

// Report on the success of the transaction completing, when everything is done
transaction.add_event_listener( |_e: IDBCompleteEvent| {
console!(log, "Transaction completed: database modification finished.");

// update the display of data to show the newly added item, by running displayData() again.
display_data();
});

transaction.add_event_listener( |_e: IDBErrorEvent| {
console!(log, "Transaction not opened due to error");
});
}});
});
}
43 changes: 43 additions & 0 deletions examples/indexeddb/static/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>IndexedDB demo</title>
<link href="style.css" rel="stylesheet">
</head>
<body>
<script src="indexeddb_example.js"></script>
<header>
<h1>IndexedDB notes demo</h1>
</header>

<main>
<section class="note-display">
<h2>Notes</h2>
<ul>

</ul>
</section>
<section class="new-note">
<h2>Enter a new note</h2>
<form>
<div>
<label for="title">Note title</label>
<input id="title" type="text" required>
</div>
<div>
<label for="body">Note text</label>
<input id="body" type="text" required>
</div>
<div>
<button>Create new note</button>
</div>
</form>
</section>
</main>

<footer>
<p>Copyright nobody. Use the code as you like.</p>
</footer>
</body>
</html>
35 changes: 35 additions & 0 deletions examples/indexeddb/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
html {
font-family: sans-serif;
}

body {
margin: 0 auto;
max-width: 800px;
}

header, footer {
background-color: green;
color: white;
line-height: 100px;
padding: 0 20px;
}

.new-note, .note-display {
padding: 20px;
}

.new-note {
background: #ddd;
}

h1 {
margin: 0;
}

ul {
list-style-type: none;
}

div {
margin-bottom: 10px;
}
33 changes: 33 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,32 @@ pub mod web {
interval_buffered
};


/// A module containing the IndexedDB API
pub mod indexeddb {
pub use webapi::indexeddb::{
IDBOpenDBRequest,
IDBDatabase,
IDBRequestSharedMethods,
IDBRequest,
IDBIndex,
IDBObjectStore,
IDBTransaction,
IDBTransactionMode,
IDBFactory,
DatabaseStorage,
IDBCursorDirection,
IDBRequestReadyState,
IDBCursorSharedMethods,
IDBCursor,
IDBCursorWithValue,
IDBIndexParameters,
IDBAddError
};
}

pub use webapi::dom_string_list::DOMStringList;

pub use webapi::window::{
Window,
window
Expand Down Expand Up @@ -434,6 +460,13 @@ pub mod web {
BlurEvent
};

pub use webapi::events::indexeddb:: {
IDBSuccessEvent,
IDBVersionChangeEvent,
IDBCompleteEvent,
IDBErrorEvent
};

pub use webapi::events::gamepad::{
IGamepadEvent,
GamepadConnectedEvent,
Expand Down
Loading