(import-macros {: map : reduce} :lib.macro) (tset package :path (.. package.path ";./vendor/lpeglj/?.lua")) (local fennel (require :vendor.fennel)) (local array (require :lib.array)) (local cache (require :lib.cache)) (local {: must} (require :lib.utils)) (local artoftea (require :parser.artoftea)) (local chaekshop (require :parser.chaekshop)) (local clubcha (require :parser.clubcha)) (local daochai (require :parser.daochai)) (local gorkovchay (require :parser.gorkovchay)) (local ipuer (require :parser.ipuer)) (local kolokolnikovchai (require :parser.kolokolnikovchai)) (local moychay (require :parser.moychay)) (local ozchai (require :parser.ozchai)) (local suhexuan (require :parser.suhexuan)) (local tea108 (require :parser.tea108)) (local yoceramics (require :parser.yoceramics)) (local teaworkshop (require :parser.teaworkshop)) (when _G.unpack (tset table :unpack _G.unpack)) (local db (must (luna.db.open "file:var/db.sqlite?_journal=WAL&_sync=NORMAL&_txlock=immediate"))) (must (luna.db.exec db " PRAGMA foreign_keys=ON; PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL; CREATE VIRTUAL TABLE IF NOT EXISTS search USING fts5(title, fid, `table`); CREATE TABLE IF NOT EXISTS products( url TEXT NOT NULL PRIMARY KEY, site TEXT NOT NULL, title TEXT NOT NULL, description TEXT NOT NULL, year INT NOT NULL, image TEXT NOT NULL, price REAL NOT NULL, weight REAL NOT NULL, volume REAL NOT NULL, price_per REAL NOT NULL, archived BOOL NOT NULL, creation_time DATETIME NOT NULL ); CREATE TABLE IF NOT EXISTS product_tags( product TEXT NOT NULL REFERENCES products(url), tag DATETIME NOT NULL REFERENCES tags(title) ); CREATE UNIQUE INDEX IF NOT EXISTS product_tags_idx ON product_tags(product, tag); CREATE TABLE IF NOT EXISTS tags( title TEXT NOT NULL PRIMARY KEY, creation_time DATETIME NOT NULL ); CREATE TABLE IF NOT EXISTS metrics( fingerprint TEXT NOT NULL, url TEXT NOT NULL, creation_time DATETIME NOT NULL ); CREATE TABLE IF NOT EXISTS cache( key TEXT NOT NULL PRIMARY KEY, value TEXT );" [])) (fn now [] (os.date "%Y-%m-%d %H:%M:%S")) (fn store-tags [tx tags] (when (< 0 (# tags)) (local sql (.. "INSERT OR IGNORE INTO tags VALUES " (array.join (map (fn [_ _] "(?, ?)") tags) ", "))) (local vars (reduce (fn [_ tag rest] (array.concat rest [tag (now)])) tags [])) (must (luna.db.exec-tx tx sql vars)))) (fn store-product-tags [tx products] (when (< 0 (# products)) ;; flatten product tags (local tags (reduce (fn [_ product res] (array.concat res (map (fn [_ tag] [product.url tag]) product.tags))) products [])) (local sql (.. "INSERT OR IGNORE INTO product_tags VALUES " (array.join (map (fn [_ _] "(?, ?)") tags) ", "))) (local vars (reduce (fn [_ tags rest] (array.concat rest tags)) tags [])) (must (luna.db.exec-tx tx sql vars)))) (fn store-products [tx products] (local sql (.. "INSERT OR REPLACE INTO products" "(url, site, title, description, year, image, price, weight, volume, price_per, archived, creation_time)" " VALUES " (array.join (map (fn [_ _] "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") products) ", "))) (local creation-time (now)) (local vars (reduce (fn [_ product rest] (array.concat rest [(or product.url "") (or product.site "") (or product.title "") (or product.description "") (or product.year 0) (or product.image "") (or product.price 0) (or product.weight 0) (or product.volume 0) (or product.price-per 0) (or product.archived false) creation-time])) products [])) (must (luna.db.exec-tx tx sql vars)) ;; store tags (store-tags tx (array.unique (array.flatten (map (fn [_ v] v.tags) products)))) (store-product-tags tx products) ;; archive previous products (local site (. products 1 :site)) (when site (must (luna.db.exec-tx tx "UPDATE products SET archived = true WHERE site = ? AND creation_time < ?" [site creation-time])))) (fn populate-search-table [db] (local tx (must (luna.db.begin db))) (must (luna.db.exec-tx tx "DELETE FROM search" [])) (must (luna.db.exec-tx tx "INSERT INTO search SELECT title, url, 'products' FROM products;" [])) (must (luna.db.commit tx))) (each [_ parser (pairs [yoceramics daochai gorkovchay moychay ozchai suhexuan ipuer artoftea clubcha chaekshop kolokolnikovchai tea108 teaworkshop])] (local products (parser.products)) (when (< 0 (# products)) ;; replace with with-tx (local tx (must (luna.db.begin db))) (local (ok? err) (pcall store-products tx products)) (must (luna.db.commit tx)) (when (not ok?) (print (string.format "Error fetching %s:\n%s" parser.title err))))) (cache.clear db "page:") (populate-search-table db)