[niepce/lr-import: 7/20] Issue #40 - Added Albums to the database model
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce/lr-import: 7/20] Issue #40 - Added Albums to the database model
- Date: Mon, 20 Dec 2021 05:37:15 +0000 (UTC)
commit ed3c61bcc3c4813fb1ab3fe121ba7b87fa033121
Author: Hubert Figuière <hub figuiere net>
Date: Sat Nov 13 22:49:51 2021 -0500
Issue #40 - Added Albums to the database model
- Bump DB version to 10
https://gitlab.gnome.org/GNOME/niepce/-/issues/40
crates/npc-engine/src/db.rs | 9 +++
crates/npc-engine/src/db/album.rs | 91 ++++++++++++++++++++++
crates/npc-engine/src/db/library.rs | 59 +++++++++++++-
crates/npc-engine/src/importer/lrimporter.rs | 13 +++-
crates/npc-engine/src/library/commands.rs | 35 +++++++++
crates/npc-engine/src/library/notification.rs | 5 +-
crates/npc-engine/src/libraryclient.rs | 14 ++++
crates/npc-engine/src/libraryclient/clientimpl.rs | 25 +++++-
.../src/libraryclient/clientinterface.rs | 6 ++
doc/database.txt | 9 +++
src/Makefile.am | 1 +
11 files changed, 262 insertions(+), 5 deletions(-)
---
diff --git a/crates/npc-engine/src/db.rs b/crates/npc-engine/src/db.rs
index faa2309..902fb9b 100644
--- a/crates/npc-engine/src/db.rs
+++ b/crates/npc-engine/src/db.rs
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+pub mod album;
pub mod filebundle;
pub mod fsfile;
pub mod keyword;
@@ -29,7 +30,15 @@ pub mod props;
pub type LibraryId = i64;
+#[derive(Copy, Clone, PartialEq)]
+pub enum SortOrder {
+ NoSorting,
+ Ascending,
+ Descending,
+}
+
// flatten namespace a bit.
+pub use self::album::Album;
pub use self::keyword::Keyword;
pub use self::label::Label;
pub use self::libfolder::LibFolder;
diff --git a/crates/npc-engine/src/db/album.rs b/crates/npc-engine/src/db/album.rs
new file mode 100644
index 0000000..58f62ea
--- /dev/null
+++ b/crates/npc-engine/src/db/album.rs
@@ -0,0 +1,91 @@
+/*
+ * niepce - npc-engine/db/album.rs
+ *
+ * Copyright (C) 2021 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use super::FromDb;
+use super::LibraryId;
+use super::SortOrder;
+
+/// Represents an album, that contains image
+#[derive(Clone)]
+pub struct Album {
+ /// Album ID
+ id: LibraryId,
+ /// Album name as displayed
+ name: String,
+ /// Album Parent. -1 for no parent.
+ parent: LibraryId,
+ /// Sorting
+ order: SortOrder,
+ /// Key
+ order_by: String,
+}
+
+impl Album {
+ pub fn new(id: LibraryId, name: &str, parent: LibraryId) -> Self {
+ Album {
+ id,
+ name: name.to_owned(),
+ parent,
+ order: SortOrder::NoSorting,
+ order_by: "".to_owned(),
+ }
+ }
+
+ /// Get the album ID
+ pub fn id(&self) -> LibraryId {
+ self.id
+ }
+
+ /// Get the album name
+ pub fn name(&self) -> &str {
+ &self.name
+ }
+
+ /// Get parent album ID.
+ pub fn parent(&self) -> LibraryId {
+ self.parent
+ }
+
+ pub fn order(&self) -> SortOrder {
+ self.order
+ }
+
+ pub fn set_order(&mut self, order: SortOrder) {
+ self.order = order;
+ }
+}
+
+impl FromDb for Album {
+ fn read_db_columns() -> &'static str {
+ "id,name,parent_id"
+ }
+
+ fn read_db_tables() -> &'static str {
+ "albums"
+ }
+
+ fn read_db_where_id() -> &'static str {
+ "id"
+ }
+
+ fn read_from(row: &rusqlite::Row) -> rusqlite::Result<Self> {
+ let name: String = row.get(1)?;
+ Ok(Album::new(row.get(0)?, &name, row.get(2)?))
+ }
+}
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index d5decf7..6e010a4 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -29,6 +29,7 @@ use rusqlite::{functions::FunctionFlags, params};
use super::props::NiepceProperties as Np;
use super::props::NiepcePropertyIdx::*;
use super::{FromDb, LibraryId};
+use crate::db::album::Album;
use crate::db::filebundle::{FileBundle, Sidecar};
use crate::db::keyword::Keyword;
use crate::db::label::Label;
@@ -48,7 +49,7 @@ pub enum Managed {
YES = 1,
}
-const DB_SCHEMA_VERSION: i32 = 9;
+const DB_SCHEMA_VERSION: i32 = 10;
const DATABASENAME: &str = "niepcelibrary.db";
#[derive(Debug)]
@@ -258,6 +259,22 @@ impl Library {
)
.unwrap();
+ // version 10
+ conn.execute(
+ "CREATE TABLE albums (id INTEGER PRIMARY KEY,\
+ name TEXT, \
+ parent_id INTEGER)",
+ [],
+ )
+ .unwrap();
+ conn.execute(
+ "CREATE TABLE albuming (\
+ file_id INTEGER, album_id INTEGER)",
+ [],
+ )
+ .unwrap();
+ //
+
conn.execute(
"CREATE TABLE files (id INTEGER PRIMARY KEY,\
main_file INTEGER, name TEXT, parent_id INTEGER,\
@@ -295,6 +312,11 @@ impl Library {
BEGIN \
DELETE FROM sidecars WHERE file_id = old.id; \
DELETE FROM keywording WHERE file_id = old.id; \
+ DELETE FROM albuming WHERE file_id = old.id; \
+ END; \
+ CREATE TRIGGER album_delete_trigger AFTER DELETE ON albums \
+ BEGIN \
+ DELETE FROM albuming WHERE album_id = old.id; \
END; \
COMMIT;",
)
@@ -605,6 +627,41 @@ impl Library {
Err(Error::NoSqlDb)
}
+ /// Add an album to the library
+ pub fn add_album(&self, name: &str, parent: LibraryId) -> Result<Album> {
+ if let Some(ref conn) = self.dbconn {
+ let c = conn.execute(
+ "INSERT INTO albums (name,parent_id) VALUES(?1, ?2)",
+ params![name, parent],
+ )?;
+ if c != 1 {
+ return Err(Error::InvalidResult);
+ }
+ let id = conn.last_insert_rowid();
+ return Ok(Album::new(id, &name, parent));
+ }
+ Err(Error::NoSqlDb)
+ }
+
+ /// Get all the albums.
+ pub fn get_all_albums(&self) -> Result<Vec<Album>> {
+ if let Some(ref conn) = self.dbconn {
+ let sql = format!(
+ "SELECT {} FROM {}",
+ Album::read_db_columns(),
+ Album::read_db_tables()
+ );
+ let mut stmt = conn.prepare(&sql)?;
+ let mut rows = stmt.query([])?;
+ let mut albums: Vec<Album> = vec![];
+ while let Ok(Some(row)) = rows.next() {
+ albums.push(Album::read_from(&row)?);
+ }
+ return Ok(albums);
+ }
+ Err(Error::NoSqlDb)
+ }
+
pub fn add_fs_file<P: AsRef<Path>>(&self, f: P) -> Result<LibraryId> {
if let Some(ref conn) = self.dbconn {
let file = f.as_ref().to_string_lossy();
diff --git a/crates/npc-engine/src/importer/lrimporter.rs b/crates/npc-engine/src/importer/lrimporter.rs
index 349dd08..7f6c602 100644
--- a/crates/npc-engine/src/importer/lrimporter.rs
+++ b/crates/npc-engine/src/importer/lrimporter.rs
@@ -22,7 +22,9 @@ use gettextrs::gettext;
use std::collections::BTreeMap;
use std::path::Path;
-use lrcat::{Catalog, CatalogVersion, Folder, Keyword, KeywordTree, LibraryFile, LrId, LrObject};
+use lrcat::{
+ Catalog, CatalogVersion, Collection, Folder, Keyword, KeywordTree, LibraryFile, LrId, LrObject,
+};
use super::libraryimporter::LibraryImporter;
use crate::db::filebundle::FileBundle;
@@ -69,6 +71,12 @@ impl LrImporter {
self.folder_map.insert(folder.id(), (nid, path.into()));
}
+ fn import_collection(&mut self, collection: &Collection, libclient: &mut LibraryClient) {
+ let parent = self.collection_map.get(&collection.parent).unwrap_or(&-1);
+ let nid = libclient.create_album_sync(collection.name.clone(), *parent);
+ self.collection_map.insert(collection.id(), nid);
+ }
+
fn import_library_file(&mut self, file: &LibraryFile, libclient: &mut LibraryClient) {
if let Some(folder_id) = self.folder_map.get(&file.folder) {
let main_file = format!("{}/{}.{}", &folder_id.1, &file.basename, &file.extension);
@@ -144,7 +152,8 @@ impl LibraryImporter for LrImporter {
let collections = catalog.load_collections();
collections.iter().for_each(|collection| {
if !collection.system_only {
- dbg_out!("Found collection {}", collection.name);
+ dbg_out!("Found collection {}", &collection.name);
+ self.import_collection(&collection, libclient);
}
});
diff --git a/crates/npc-engine/src/library/commands.rs b/crates/npc-engine/src/library/commands.rs
index 6ecc0c1..38e66f2 100644
--- a/crates/npc-engine/src/library/commands.rs
+++ b/crates/npc-engine/src/library/commands.rs
@@ -178,6 +178,41 @@ pub fn cmd_delete_folder(lib: &Library, id: LibraryId) -> bool {
}
}
+pub fn cmd_list_all_albums(lib: &Library) -> bool {
+ match lib.get_all_albums() {
+ Ok(albums) => {
+ // XXX change this notification type
+ for album in albums {
+ if let Err(err) = lib.notify(LibNotification::AddedAlbum(album)) {
+ err_out!("Failed to notify AddedAlbum {:?}", err);
+ return false;
+ }
+ }
+ true
+ }
+ Err(err) => {
+ err_out_line!("get_all_albums failed: {:?}", err);
+ false
+ }
+ }
+}
+
+pub fn cmd_create_album(lib: &Library, name: &str, parent: LibraryId) -> LibraryId {
+ match lib.add_album(name, parent) {
+ Ok(album) => {
+ let id = album.id();
+ if lib.notify(LibNotification::AddedAlbum(album)).is_err() {
+ err_out!("Failed to notify AddedAlbum");
+ }
+ id
+ }
+ Err(err) => {
+ err_out_line!("Album creation failed {:?}", err);
+ -1
+ }
+ }
+}
+
pub fn cmd_request_metadata(lib: &Library, file_id: LibraryId) -> bool {
match lib.get_metadata(file_id) {
Ok(lm) => {
diff --git a/crates/npc-engine/src/library/notification.rs b/crates/npc-engine/src/library/notification.rs
index 30452c9..86bf61e 100644
--- a/crates/npc-engine/src/library/notification.rs
+++ b/crates/npc-engine/src/library/notification.rs
@@ -19,7 +19,7 @@
use super::queriedcontent::QueriedContent;
use crate::db::libfile::FileStatus;
-use crate::db::{Keyword, Label, LibFolder, LibMetadata, LibraryId, NiepceProperties};
+use crate::db::{Album, Keyword, Label, LibFolder, LibMetadata, LibraryId, NiepceProperties};
use npc_fwk::base::PropertyIndex;
use npc_fwk::toolkit;
use npc_fwk::toolkit::thumbnail;
@@ -38,6 +38,7 @@ pub enum NotificationType {
ADDED_FILES,
ADDED_KEYWORD,
ADDED_LABEL,
+ ADDED_ALBUM,
FOLDER_CONTENT_QUERIED,
FOLDER_DELETED,
FOLDER_COUNTED,
@@ -121,6 +122,7 @@ pub enum LibNotification {
AddedFolder(LibFolder),
AddedKeyword(Keyword),
AddedLabel(Label),
+ AddedAlbum(Album),
FileMoved(FileMove),
FileStatusChanged(FileStatusChange),
FolderContentQueried(QueriedContent),
@@ -175,6 +177,7 @@ pub unsafe extern "C" fn engine_library_notification_type(
Some(&LibNotification::AddedFolder(_)) => NotificationType::ADDED_FOLDER,
Some(&LibNotification::AddedKeyword(_)) => NotificationType::ADDED_KEYWORD,
Some(&LibNotification::AddedLabel(_)) => NotificationType::ADDED_LABEL,
+ Some(&LibNotification::AddedAlbum(_)) => NotificationType::ADDED_ALBUM,
Some(&LibNotification::FileMoved(_)) => NotificationType::FILE_MOVED,
Some(&LibNotification::FileStatusChanged(_)) => NotificationType::FILE_STATUS_CHANGED,
Some(&LibNotification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
diff --git a/crates/npc-engine/src/libraryclient.rs b/crates/npc-engine/src/libraryclient.rs
index 38207cf..36958fa 100644
--- a/crates/npc-engine/src/libraryclient.rs
+++ b/crates/npc-engine/src/libraryclient.rs
@@ -116,6 +116,16 @@ impl ClientInterface for LibraryClient {
self.pimpl.delete_folder(id);
}
+ /// get all the albums
+ fn get_all_albums(&mut self) {
+ self.pimpl.get_all_albums();
+ }
+
+ /// Create an album (async)
+ fn create_album(&mut self, name: String, parent: LibraryId) {
+ self.pimpl.create_album(name, parent);
+ }
+
fn request_metadata(&mut self, id: LibraryId) {
self.pimpl.request_metadata(id);
}
@@ -171,6 +181,10 @@ impl ClientInterfaceSync for LibraryClient {
self.pimpl.create_folder_sync(name, path)
}
+ fn create_album_sync(&mut self, name: String, parent: LibraryId) -> LibraryId {
+ self.pimpl.create_album_sync(name, parent)
+ }
+
fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId {
self.pimpl.add_bundle_sync(bundle, folder)
}
diff --git a/crates/npc-engine/src/libraryclient/clientimpl.rs
b/crates/npc-engine/src/libraryclient/clientimpl.rs
index 41804c7..f2808e7 100644
--- a/crates/npc-engine/src/libraryclient/clientimpl.rs
+++ b/crates/npc-engine/src/libraryclient/clientimpl.rs
@@ -125,7 +125,7 @@ impl ClientInterface for ClientImpl {
self.schedule_op(move |lib| commands::cmd_count_keyword(&lib, id));
}
- /// get all the folder
+ /// get all the folders
fn get_all_folders(&mut self) {
self.schedule_op(move |lib| commands::cmd_list_all_folders(&lib));
}
@@ -146,6 +146,16 @@ impl ClientInterface for ClientImpl {
self.schedule_op(move |lib| commands::cmd_delete_folder(&lib, id));
}
+ /// get all the albums
+ fn get_all_albums(&mut self) {
+ self.schedule_op(move |lib| commands::cmd_list_all_albums(&lib));
+ }
+
+ /// Create an album (async)
+ fn create_album(&mut self, name: String, parent: LibraryId) {
+ self.schedule_op(move |lib| commands::cmd_create_album(&lib, &name, parent) != 0);
+ }
+
fn request_metadata(&mut self, file_id: LibraryId) {
self.schedule_op(move |lib| commands::cmd_request_metadata(&lib, file_id));
}
@@ -232,6 +242,19 @@ impl ClientInterfaceSync for ClientImpl {
rx.recv().unwrap()
}
+ fn create_album_sync(&mut self, name: String, parent: LibraryId) -> LibraryId {
+ // can't use futures::sync::oneshot
+ let (tx, rx) = mpsc::sync_channel::<LibraryId>(1);
+
+ self.schedule_op(move |lib| {
+ tx.send(commands::cmd_create_album(&lib, &name, parent))
+ .unwrap();
+ true
+ });
+
+ rx.recv().unwrap()
+ }
+
fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId {
let (tx, rx) = mpsc::sync_channel::<LibraryId>(1);
diff --git a/crates/npc-engine/src/libraryclient/clientinterface.rs
b/crates/npc-engine/src/libraryclient/clientinterface.rs
index 88aaa1f..80ba1ee 100644
--- a/crates/npc-engine/src/libraryclient/clientinterface.rs
+++ b/crates/npc-engine/src/libraryclient/clientinterface.rs
@@ -39,6 +39,9 @@ pub trait ClientInterface {
fn create_folder(&mut self, name: String, path: Option<String>);
fn delete_folder(&mut self, id: LibraryId);
+ fn get_all_albums(&mut self);
+ fn create_album(&mut self, name: String, parent: LibraryId);
+
fn request_metadata(&mut self, id: LibraryId);
/// set the metadata
fn set_metadata(&mut self, id: LibraryId, meta: Np, value: &PropertyValue);
@@ -74,6 +77,9 @@ pub trait ClientInterfaceSync {
/// Create a folder. Return the id of the newly created folder.
fn create_folder_sync(&mut self, name: String, path: Option<String>) -> LibraryId;
+ /// Create an album. Return the id to the newly created album.
+ fn create_album_sync(&mut self, name: String, parent: LibraryId) -> LibraryId;
+
/// Add a bundle.
fn add_bundle_sync(&mut self, bundle: &FileBundle, folder: LibraryId) -> LibraryId;
}
diff --git a/doc/database.txt b/doc/database.txt
index 48439cd..29b3537 100644
--- a/doc/database.txt
+++ b/doc/database.txt
@@ -77,6 +77,15 @@ labels id The ID of the label
name The name of the label (user displayed)
color The RGB8 color in "R G B" format.
+Albums contain files
+
+albums id The ID of the album
+ name The name of the album (user displayed)
+ parent_id The parent album. -1 means on the top
+
+albuming file_id The file in the album.
+ album_id The album the file is in.
+
The update queue for XMP. When an XMP is changed in the DB it is
queued in the table.
diff --git a/src/Makefile.am b/src/Makefile.am
index 9d7bf4b..6f620f7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -10,6 +10,7 @@ RUST_SOURCES = \
@top_srcdir@/crates/npc-engine/Cargo.toml \
@top_srcdir@/crates/npc-engine/build.rs \
@top_srcdir@/crates/npc-engine/src/db.rs \
+ @top_srcdir@/crates/npc-engine/src/db/album.rs \
@top_srcdir@/crates/npc-engine/src/db/filebundle.rs \
@top_srcdir@/crates/npc-engine/src/db/fsfile.rs \
@top_srcdir@/crates/npc-engine/src/db/keyword.rs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]