Skip to content

Commit

Permalink
feat: modified bookmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrot-lc committed Oct 27, 2024
1 parent 5476497 commit db64c62
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 33 deletions.
32 changes: 28 additions & 4 deletions src/buku_merger.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import gleam/dynamic
import gleam/io
import gleam/string
import sqlight.{type Connection}

Expand All @@ -13,16 +12,41 @@ pub type TableDiff {
/// Find the element present in the target table but not in source table. An
/// element identified by its ID and URL column value. Returns the primary IDs of the
/// selected rows.
pub fn bookmarks_added(
pub fn added_urls(
conn: Connection,
source source: String,
target target: String,
) -> List(Id) {
let query =
"
SELECT t1.id FROM target as t1
SELECT t1.id FROM target AS t1
WHERE t1.url NOT IN
( SELECT t2.url FROM source as t2 );
( SELECT t2.url FROM source AS t2 );
"
|> string.replace(each: "source", with: source)
|> string.replace(each: "target", with: target)

let decoder = dynamic.element(0, dynamic.int)
let assert Ok(ids) =
sqlight.query(query, on: conn, with: [], expecting: decoder)
ids
}

pub fn modified_urls(
conn: Connection,
source source: String,
target target: String,
) -> List(Id) {
let query =
"
SELECT t1.id FROM target AS t1
INNER JOIN source AS t2 ON t1.id=t2.id AND t1.url=t2.url
WHERE (
t1.desc!=t2.desc OR
t1.flags!=t2.flags OR
t1.metadata!=t2.metadata OR
t1.tags!=t2.tags
);
"
|> string.replace(each: "source", with: source)
|> string.replace(each: "target", with: target)
Expand Down
54 changes: 35 additions & 19 deletions test/buku_merger_test.gleam
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import buku_merger.{type Id}
import buku_merger
import db_generator.{Bookmark}
import gleam/dynamic
import gleam/int
import gleam/list
import gleam/order
import gleeunit
import gleeunit/should
import sqlight
Expand All @@ -13,45 +13,61 @@ pub fn main() {

pub fn added_bookmarks_test() {
let bookmarks_1 = [
Bookmark("www.google.fr", "Google website"),
Bookmark("www.gleam.run", "Try Gleam online!"),
Bookmark("www.google.fr", "Google", ",search,", "Google website", 0),
Bookmark("www.gleam.run", "Gleam", ",fp,", "Try Gleam online!", 0),
]
let bookmarks_2 = [
Bookmark("www.google.fr", "Google website"),
Bookmark("www.gleam.run", "Try Gleam online!"),
Bookmark("overfitted.dev", "My personal website."),
Bookmark("www.google.fr", "Google", ",search,", "Google website", 0),
Bookmark("www.gleam.run", "Gleam", ",fp,", "Try Gleam online!", 0),
Bookmark("overfitted.dev", "Overfitted", ",blog,", "My personal website", 0),
]
let added_ids = [3]

use conn <- sqlight.with_connection(":memory:")
let _ = db_generator.insert_bookmarks(bookmarks_1, "source", conn)
let _ = db_generator.insert_bookmarks(bookmarks_2, "target", conn)

buku_merger.bookmarks_added(conn, "source", "target")
|> list.sort(fn(a, b) {
case a < b {
True -> order.Lt
False -> order.Gt
}
})
buku_merger.added_urls(conn, "source", "target")
|> list.sort(int.compare)
|> should.equal(added_ids)
}

pub fn modified_bookmarks_test() {
let bookmarks_1 = [
Bookmark("www.google.fr", "Google", ",search,", "Google website", 0),
Bookmark("www.gleam.run", "Gleam", ",fp,", "Try Gleam!", 0),
Bookmark("overfitted.dev", "Overfitted", ",blog,", "My personal website", 0),
]
let bookmarks_2 = [
Bookmark("www.google.fr", "Google", ",search,", "Google website", 0),
Bookmark("www.gleam.run", "Gleam", ",fp,", "Try Gleam online!", 0),
Bookmark("overfitted.dev", "Overfitted", ",blog,", "My personal website", 0),
]
let added_ids = [2]

use conn <- sqlight.with_connection(":memory:")
let _ = db_generator.insert_bookmarks(bookmarks_1, "source", conn)
let _ = db_generator.insert_bookmarks(bookmarks_2, "target", conn)

buku_merger.modified_urls(conn, "source", "target")
|> list.sort(int.compare)
|> should.equal(added_ids)
}

/// Test the construction of a fictive bookmarks table.
pub fn fictive_bookmarks_test() {
let bookmarks = [
Bookmark("www.google.fr", "Google desc"),
Bookmark("www.gleam.run", "Gleam!"),
Bookmark("www.google.fr", "Google", ",search,", "Google website", 0),
Bookmark("www.gleam.run", "Gleam", ",fp,", "Try Gleam online!", 0),
]

use conn <- sqlight.with_connection(":memory:")
let _ = db_generator.insert_bookmarks(bookmarks, "bookmarks", conn)
let query = "SELECT url, desc FROM bookmarks;"
let decoder = dynamic.tuple2(dynamic.string, dynamic.string)
let query = "SELECT url, metadata, tags, desc, flags FROM bookmarks;"
let decoder = db_generator.bookmark_decoder
let assert Ok(res) =
sqlight.query(query, on: conn, with: [], expecting: decoder)

res
|> list.map(fn(b) { Bookmark(b.0, b.1) })
|> should.equal(bookmarks)
}
63 changes: 53 additions & 10 deletions test/db_generator.gleam
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
import gleam/dynamic
import gleam/dynamic.{type DecodeError, type Dynamic}
import gleam/int
import gleam/io
import gleam/list
import gleam/string
import sqlight.{type Connection}
import sqlight.{type Connection, type Value}

pub type Bookmark {
Bookmark(url: String, desc: String)
Bookmark(
url: String,
metadata: String,
tags: String,
desc: String,
flags: Int,
)
}

pub fn bookmark_to_sqlight_args(b: Bookmark) -> List(Value) {
[
sqlight.text(b.url),
sqlight.text(b.metadata),
sqlight.text(b.tags),
sqlight.text(b.desc),
sqlight.int(b.flags),
]
}

/// Make sure the query is fetching the columns in the right order!
pub fn bookmark_decoder(d: Dynamic) -> Result(Bookmark, List(DecodeError)) {
let decoder =
dynamic.tuple5(
dynamic.string,
dynamic.string,
dynamic.string,
dynamic.string,
dynamic.int,
)
case decoder(d) {
Ok(b) -> Ok(Bookmark(b.0, b.1, b.2, b.3, b.4))
Error(e) -> Error(e)
}
}

pub fn print_db(conn: Connection) {
Expand Down Expand Up @@ -45,22 +77,33 @@ pub fn insert_bookmarks(
) {
// Create the table if necessary.
let query =
" CREATE TABLE IF NOT EXISTS "
<> table
<> " ( id INTEGER PRIMARY KEY, url text, desc text);"
"
CREATE TABLE IF NOT EXISTS table_name (
id INTEGER PRIMARY KEY,
URL TEXT NOT NULL,
metadata TEXT DEFAULT '',
tags TEXT DEFAULT ',',
desc TEXT DEFAULT '',
flags INTEGER DEFAULT 0
);
"
|> string.replace(each: "table_name", with: table)
let assert Ok(Nil) = sqlight.exec(query, conn)

// Insert the bookmarks.
let query =
bookmarks
|> list.map(fn(_) { "(?, ?)" })
|> string.join(", ")
|> list.map(fn(_) { "(?, ?, ?, ?, ?)" })
|> string.join(",\n")
|> string.append(";")
|> string.append("INSERT INTO " <> table <> " (url, desc) VALUES ", _)
|> string.append(
"INSERT INTO " <> table <> " (URL, metadata, tags, desc, flags) VALUES ",
_,
)

let with =
bookmarks
|> list.map(fn(b) { [sqlight.text(b.url), sqlight.text(b.desc)] })
|> list.map(bookmark_to_sqlight_args)
|> list.flatten

let assert Ok(_) =
Expand Down

0 comments on commit db64c62

Please sign in to comment.