rework aux table sorting

Instead of inserting text into the aux table and sorting on the fly
(which does a binary sort), we insert the ids in unicase-sorted order,
and then sort based on the automatically assigned rowids - giving
us faster sorts, and proper unicase folding.
This commit is contained in:
Damien Elmes 2020-05-02 17:13:18 +10:00
parent 8246ba148e
commit 8d17edc1e6
7 changed files with 65 additions and 62 deletions

View file

@ -158,7 +158,7 @@ impl Collection {
}
}
#[derive(Deserialize, PartialEq, Debug)]
#[derive(Deserialize, PartialEq, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum SortKind {
#[serde(rename = "noteCrt")]

View file

@ -8,7 +8,6 @@ use crate::collection::Collection;
use crate::config::SortKind;
use crate::err::Result;
use crate::search::parser::parse;
use rusqlite::params;
pub enum SortMode {
NoOrder,
@ -31,14 +30,14 @@ impl Collection {
SortMode::NoOrder => (),
SortMode::FromConfig => {
let kind = self.get_browser_sort_kind();
prepare_sort(self, &kind)?;
prepare_sort(self, kind)?;
sql.push_str(" order by ");
write_order(&mut sql, &kind, self.get_browser_sort_reverse())?;
write_order(&mut sql, kind, self.get_browser_sort_reverse())?;
}
SortMode::Builtin { kind, reverse } => {
prepare_sort(self, &kind)?;
prepare_sort(self, kind)?;
sql.push_str(" order by ");
write_order(&mut sql, &kind, reverse)?;
write_order(&mut sql, kind, reverse)?;
}
SortMode::Custom(order_clause) => {
sql.push_str(" order by ");
@ -56,7 +55,7 @@ impl Collection {
}
/// Add the order clause to the sql.
fn write_order(sql: &mut String, kind: &SortKind, reverse: bool) -> Result<()> {
fn write_order(sql: &mut String, kind: SortKind, reverse: bool) -> Result<()> {
let tmp_str;
let order = match kind {
SortKind::NoteCreation => "n.id asc, c.ord asc",
@ -72,9 +71,13 @@ fn write_order(sql: &mut String, kind: &SortKind, reverse: bool) -> Result<()> {
SortKind::CardLapses => "c.lapses asc",
SortKind::CardInterval => "c.ivl asc",
SortKind::NoteTags => "n.tags asc",
SortKind::CardDeck => "(select v from sort_order where k = c.did) asc",
SortKind::NoteType => "(select v from sort_order where k = n.mid) asc",
SortKind::CardTemplate => "(select v from sort_order where k1 = n.mid and k2 = c.ord) asc",
SortKind::CardDeck => "(select pos from sort_order where did = c.did) asc",
SortKind::NoteType => "(select pos from sort_order where ntid = n.mid) asc",
SortKind::CardTemplate => concat!(
"coalesce((select pos from sort_order where ntid = n.mid and ord = c.ord),",
// need to fall back on ord 0 for cloze cards
"(select pos from sort_order where ntid = n.mid and ord = 0)) asc"
),
};
if order.is_empty() {
return Ok(());
@ -92,60 +95,28 @@ fn write_order(sql: &mut String, kind: &SortKind, reverse: bool) -> Result<()> {
Ok(())
}
// fixme: use the new tables
fn prepare_sort(col: &mut Collection, kind: &SortKind) -> Result<()> {
fn needs_aux_sort_table(kind: SortKind) -> bool {
use SortKind::*;
match kind {
CardDeck | NoteType => {
prepare_sort_order_table(col)?;
let mut stmt = col
.storage
.db
.prepare("insert into sort_order (k,v) values (?,?)")?;
CardDeck | NoteType | CardTemplate => true,
_ => false,
}
}
match kind {
CardDeck => {
for (k, v) in col.storage.get_all_decks_as_schema11()? {
stmt.execute(params![k, v.name()])?;
}
}
NoteType => {
for (k, v) in col.storage.get_all_notetypes_as_schema11()? {
stmt.execute(params![k, v.name])?;
}
fn prepare_sort(col: &mut Collection, kind: SortKind) -> Result<()> {
if !needs_aux_sort_table(kind) {
return Ok(());
}
use SortKind::*;
let sql = match kind {
CardDeck => include_str!("deck_order.sql"),
NoteType => include_str!("notetype_order.sql"),
CardTemplate => include_str!("template_order.sql"),
_ => unreachable!(),
}
}
CardTemplate => {
prepare_sort_order_table2(col)?;
let mut stmt = col
.storage
.db
.prepare("insert into sort_order (k1,k2,v) values (?,?,?)")?;
};
for (ntid, nt) in col.storage.get_all_notetypes_as_schema11()? {
for tmpl in nt.tmpls {
stmt.execute(params![ntid, tmpl.ord, tmpl.name])?;
}
}
}
_ => (),
}
col.storage.db.execute_batch(sql)?;
Ok(())
}
fn prepare_sort_order_table(col: &mut Collection) -> Result<()> {
col.storage
.db
.execute_batch(include_str!("sort_order.sql"))?;
Ok(())
}
fn prepare_sort_order_table2(col: &mut Collection) -> Result<()> {
col.storage
.db
.execute_batch(include_str!("sort_order2.sql"))?;
Ok(())
}

View file

@ -0,0 +1,11 @@
drop table if exists sort_order;
create temporary table sort_order (
pos integer primary key,
did integer not null unique
);
insert into sort_order (did)
select
id
from decks
order by
name;

View file

@ -0,0 +1,11 @@
drop table if exists sort_order;
create temporary table sort_order (
pos integer primary key,
ntid integer not null unique
);
insert into sort_order (ntid)
select
id
from notetypes
order by
name;

View file

@ -1,2 +0,0 @@
drop table if exists sort_order;
create temporary table sort_order (k int primary key, v text);

View file

@ -1,2 +0,0 @@
drop table if exists sort_order;
create temporary table sort_order (k1 int, k2 int, v text, primary key (k1, k2)) without rowid;

View file

@ -0,0 +1,14 @@
drop table if exists sort_order;
create temporary table sort_order (
pos integer primary key,
ntid integer not null,
ord integer not null,
unique(ntid, ord)
);
insert into sort_order (ntid, ord)
select
ntid,
ord
from templates
order by
name