Storing events seems like it'll be simpler than querying, so let's start brainstorming how writing new events might work! Based on @fluffyemily's explorations in https://github.com/fluffyemily/cross-platform-rust/, I'm guessing we'll need to expose a more low-level API in Rust, and wrap that in C++/Java/Swift for Gecko and Fennec to use.
I'm not really fond of the "key is a string" design in this one...it's too easy to mask typos, and using an Event
struct might also let us do interesting things like composing multiple events when we build up queries.
// Sets up the SQLite database, attaches to Places, etc.
let store = Store::open(...).expect("Failed to open store");
// Record some metadata for the URL.
store.record("http://example.com", |recorder| {
// Record page metadata: number of images, videos, etc. We can replace these
// directly, without storing the previous values: the number of images or
// videos on the page might change, but the old values aren't interesting.
// These are linked to rows in `moz_places`.
//
// In this sketch, it's possible to just declare the key and value: we'll create
// it if it doesn't exist, and overload `set()` for different value types:
// i64, time::Duration, &str, bool. A more structured design might add a
// `store.define()` API for every event we'd like to record. `define` would
// return an `Event` struct, which we could pass to `set` instead of the
// string name.
let page = recorder.page();
page.set("images", 4);
page.set("videos", 14);
// Record visit metadata: dwell time, time the page was left open in the
// background, referring search query, and so on. These are linked to rows
// in `moz_historyvisits`, which also gives us info that Places records like
// the visit time, referrer, and transition (link, bookmark, typed into
// awesomebar, etc).
let visit = recorder.visit();
visit.set("dwell-time", Duration::minutes(2));
visit.set("background-time", Duration::seconds(3));
visit.set("referring-search-query", "lolcats");
// Record actions for the visit. We can store timestamps and other
// interesting info automatically.
visit.action("share", "send-to-device");
visit.action("play", "#cat-video-1");
visit.action("pause", "#cat-video-1");
// Everything in this function happens in a transaction. At the end, the
// transaction commits.
}).expect("Failed to record metadata");