diff --git a/.env b/.env new file mode 100644 index 000000000..83632568c --- /dev/null +++ b/.env @@ -0,0 +1 @@ +DATABASE_URL=postgres://admin:password@localhost/fabricate diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 000000000..7fb4bfd3a --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,11 @@ + + + + + postgresql + true + org.postgresql.Driver + jdbc:postgresql://localhost:5432/postgres + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 000000000..6df4889b0 --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c674092b0..4b1d7e4c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,7 +92,7 @@ dependencies = [ "percent-encoding", "pin-project", "rand", - "regex", + "regex 1.3.7", "serde", "serde_json", "serde_urlencoded", @@ -120,7 +120,7 @@ dependencies = [ "bytestring", "http", "log", - "regex", + "regex 1.3.7", "serde", ] @@ -260,7 +260,7 @@ dependencies = [ "mime", "net2", "pin-project", - "regex", + "regex 1.3.7", "serde", "serde_json", "serde_urlencoded", @@ -285,6 +285,15 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" +[[package]] +name = "aho-corasick" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" +dependencies = [ + "memchr", +] + [[package]] name = "aho-corasick" version = "0.7.10" @@ -500,6 +509,29 @@ dependencies = [ "syn", ] +[[package]] +name = "diesel" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d7ca63eb2efea87a7f56a283acc49e2ce4b2bd54adf7465dc1d81fef13d8fc" +dependencies = [ + "bitflags", + "byteorder", + "diesel_derives", + "pq-sys", +] + +[[package]] +name = "diesel_derives" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "digest" version = "0.8.1" @@ -509,6 +541,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dotenv" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "400b347fe65ccfbd8f545c9d9a75d04b0caf23fec49aaa838a9a05398f94c019" +dependencies = [ + "regex 0.2.11", +] + [[package]] name = "dtoa" version = "0.4.5" @@ -549,6 +590,8 @@ dependencies = [ "actix-files", "actix-rt", "actix-web", + "diesel", + "dotenv", "handlebars", "meilisearch-sdk", "serde", @@ -1203,6 +1246,15 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +[[package]] +name = "pq-sys" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac25eee5a0582f45a67e837e350d784e7003bd29a5f460796772061ca49ffda" +dependencies = [ + "vcpkg", +] + [[package]] name = "proc-macro-hack" version = "0.5.15" @@ -1286,16 +1338,38 @@ version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +[[package]] +name = "regex" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" +dependencies = [ + "aho-corasick 0.6.10", + "memchr", + "regex-syntax 0.5.6", + "thread_local 0.3.6", + "utf8-ranges", +] + [[package]] name = "regex" version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.10", "memchr", - "regex-syntax", - "thread_local", + "regex-syntax 0.6.17", + "thread_local 1.0.1", +] + +[[package]] +name = "regex-syntax" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" +dependencies = [ + "ucd-util", ] [[package]] @@ -1459,6 +1533,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +dependencies = [ + "lazy_static", +] + [[package]] name = "thread_local" version = "1.0.1" @@ -1587,6 +1670,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "ucd-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85f514e095d348c279b1e5cd76795082cf15bd59b93207832abe0b1d8fed236" + [[package]] name = "unicase" version = "2.6.0" @@ -1643,6 +1732,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3df3561629a8bb4c57e5a2e4c43348d9e29c7c29d9b1c4c1f47166deca8f37ed" +[[package]] +name = "utf8-ranges" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba" + [[package]] name = "v_escape" version = "0.7.4" @@ -1674,6 +1769,12 @@ dependencies = [ "v_escape", ] +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" + [[package]] name = "version_check" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 473513ee0..dcfc13b7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,5 @@ serde_derive = "1.0.107" serde = {version="1.0", features=["derive"]} meilisearch-sdk = "0.1.1" actix-files = "0.2.1" +diesel = { version = "1.0.0", features = ["postgres"] } +dotenv = "0.9.0" diff --git a/diesel.toml b/diesel.toml new file mode 100644 index 000000000..92267c829 --- /dev/null +++ b/diesel.toml @@ -0,0 +1,5 @@ +# For documentation on how to configure this file, +# see diesel.rs/guides/configuring-diesel-cli + +[print_schema] +file = "src/schema.rs" diff --git a/migrations/.gitkeep b/migrations/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/migrations/00000000000000_diesel_initial_setup/down.sql b/migrations/00000000000000_diesel_initial_setup/down.sql new file mode 100644 index 000000000..a9f526091 --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/down.sql @@ -0,0 +1,6 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + +DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass); +DROP FUNCTION IF EXISTS diesel_set_updated_at(); diff --git a/migrations/00000000000000_diesel_initial_setup/up.sql b/migrations/00000000000000_diesel_initial_setup/up.sql new file mode 100644 index 000000000..d68895b1a --- /dev/null +++ b/migrations/00000000000000_diesel_initial_setup/up.sql @@ -0,0 +1,36 @@ +-- This file was automatically created by Diesel to setup helper functions +-- and other internal bookkeeping. This file is safe to edit, any future +-- changes will be added to existing projects as new migrations. + + + + +-- Sets up a trigger for the given table to automatically set a column called +-- `updated_at` whenever the row is modified (unless `updated_at` was included +-- in the modified columns) +-- +-- # Example +-- +-- ```sql +-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW()); +-- +-- SELECT diesel_manage_updated_at('users'); +-- ``` +CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$ +BEGIN + EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s + FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl); +END; +$$ LANGUAGE plpgsql; + +CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$ +BEGIN + IF ( + NEW IS DISTINCT FROM OLD AND + NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at + ) THEN + NEW.updated_at := current_timestamp; + END IF; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; diff --git a/migrations/2020-05-15-055106_create_mods/down.sql b/migrations/2020-05-15-055106_create_mods/down.sql new file mode 100644 index 000000000..f060b72fb --- /dev/null +++ b/migrations/2020-05-15-055106_create_mods/down.sql @@ -0,0 +1 @@ +DROP TABLE mods \ No newline at end of file diff --git a/migrations/2020-05-15-055106_create_mods/up.sql b/migrations/2020-05-15-055106_create_mods/up.sql new file mode 100644 index 000000000..e1609e55e --- /dev/null +++ b/migrations/2020-05-15-055106_create_mods/up.sql @@ -0,0 +1,11 @@ +CREATE TABLE mods ( + id SERIAL PRIMARY KEY, + title VARCHAR NOT NULL, + description VARCHAR NOT NULL, + datePublished DATE NOT NULL, + author VARCHAR NOT NULL, + downloads INTEGER NOT NULL DEFAULT 0, + categories TEXT[] NOT NULL, + body_path VARCHAR NOT NULL, + icon_path VARCHAR NOT NULL +) \ No newline at end of file diff --git a/migrations/2020-05-15-055207_create_versions/down.sql b/migrations/2020-05-15-055207_create_versions/down.sql new file mode 100644 index 000000000..7a3f850b7 --- /dev/null +++ b/migrations/2020-05-15-055207_create_versions/down.sql @@ -0,0 +1 @@ +DROP TABLE versions \ No newline at end of file diff --git a/migrations/2020-05-15-055207_create_versions/up.sql b/migrations/2020-05-15-055207_create_versions/up.sql new file mode 100644 index 000000000..5db90b30a --- /dev/null +++ b/migrations/2020-05-15-055207_create_versions/up.sql @@ -0,0 +1,12 @@ +CREATE TABLE versions ( + id SERIAL PRIMARY KEY, + mod_id SERIAL NOT NULL, + title VARCHAR NOT NULL, + changelog_path VARCHAR NOT NULL, + files_path TEXT[] NOT NULL, + date_published DATE NOT NULL, + author VARCHAR NOT NULL, + downloads INTEGER NOT NULL DEFAULT 0, + dependencies TEXT[] NOT NULL, + game_versions TEXT[] NOT NULL +) \ No newline at end of file diff --git a/src/database/database.rs b/src/database/database.rs new file mode 100644 index 000000000..6625fcfc3 --- /dev/null +++ b/src/database/database.rs @@ -0,0 +1,11 @@ +use diesel::prelude::*; +use diesel::pg::PgConnection; +use dotenv::dotenv; +use std::env; + +pub fn connect() -> PgConnection{ + dotenv.ok(); + + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set!"); + PgConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url)) +} \ No newline at end of file diff --git a/src/database/mod.rs b/src/database/mod.rs new file mode 100644 index 000000000..f9674f876 --- /dev/null +++ b/src/database/mod.rs @@ -0,0 +1,6 @@ +mod database; +mod models; + +pub use database::connect; +pub use models::Mod; +pub use models::Version; \ No newline at end of file diff --git a/src/database/models.rs b/src/database/models.rs new file mode 100644 index 000000000..13d1a9f88 --- /dev/null +++ b/src/database/models.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; + +use crate::schema::mods; + +#[derive(Queryable)] +pub struct Mod { + pub id: i32, + pub title: String, + pub description: String, + pub published: String, + pub author: String, + pub downloads: i32, + pub categories: Vec, + pub body_path: String, + pub icon_path: String +} + +#[derive(Queryable)] +pub struct Version { + pub id: i32, + pub mod_id: i32, + pub title: String, + pub changelog_path: String, + pub files_path: Vec, + pub date_published: String, + pub author: String, + pub downloads: i32, + pub dependencies: Vec, + pub game_versions: Vec +} + diff --git a/src/helpers/contains.rs b/src/helpers/contains.rs new file mode 100644 index 000000000..cca5ce293 --- /dev/null +++ b/src/helpers/contains.rs @@ -0,0 +1,18 @@ +use handlebars::*; + +#[derive(Clone, Copy)] +pub struct ContainsHelper; + +impl HelperDef for ContainsHelper { + fn call<'reg: 'rc, 'rc>(&self, h: &Helper<'reg, 'rc>, r: &'reg Handlebars<'_>, ctx: &'rc Context, rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output) -> HelperResult { + let array = h.param(0).map(|v| serde_json::from_value::>(v.value().clone()).unwrap()).ok_or(RenderError::new("Parameter not found!"))?; + let value = h.param(1).map(|v| v.value().as_str().unwrap()).ok_or(RenderError::new("Parameter not found!"))?; + + let tmpl = if array.contains(&String::from(value)) { h.template() } else { h.inverse() }; + + match tmpl { + Some(ref t) => t.render(r, ctx, rc, out), + None => Ok(()), + } + } +} \ No newline at end of file diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs new file mode 100644 index 000000000..d02c7c607 --- /dev/null +++ b/src/helpers/mod.rs @@ -0,0 +1,3 @@ +mod contains; + +pub use contains::ContainsHelper; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 439028ca1..4e42ea76d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,179 +1,43 @@ #[macro_use] extern crate serde_json; +#[macro_use] +extern crate diesel; + use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post}; use handlebars::*; use meilisearch_sdk::{document::*, indexes::*, client::*, search::*}; use serde::{Serialize, Deserialize}; use actix_files as fs; -#[derive(Clone, Copy)] -struct ContainsHelper; - -impl HelperDef for ContainsHelper { - fn call<'reg: 'rc, 'rc>(&self, h: &Helper<'reg, 'rc>, r: &'reg Handlebars<'_>, ctx: &'rc Context, rc: &mut RenderContext<'reg, 'rc>, out: &mut dyn Output) -> HelperResult { - let array = h.param(0).map(|v| serde_json::from_value::>(v.value().clone()).unwrap()).ok_or(RenderError::new("Parameter not found!"))?; - let value = h.param(1).map(|v| v.value().as_str().unwrap()).ok_or(RenderError::new("Parameter not found!"))?; - - let tmpl = if array.contains(&String::from(value)) { h.template() } else { h.inverse() }; - - match tmpl { - Some(ref t) => t.render(r, ctx, rc, out), - None => Ok(()), - } - } -} - -#[derive(Serialize, Deserialize, Debug)] -struct Mod { - mod_id: usize, - title: String, - description: String, - keywords: Vec, - versions: Vec, -} - -impl Document for Mod { - type UIDType = usize; - - fn get_uid(&self) -> &Self::UIDType { - &self.mod_id - } -} - - -#[derive(Deserialize)] -pub struct SearchRequest { - q: Option, - f: Option, - v: Option, -} - -#[post("search")] -async fn search_post(web::Query(info): web::Query, hb: Data>) -> HttpResponse { - let results = search(web::Query(info)); - - let data = json!({ - "results": results, - }); - - let body = hb.render("search_results", &data).unwrap(); - - HttpResponse::Ok().body(body) -} - -#[get("search")] -async fn search_get(web::Query(info): web::Query, hb: Data>) -> HttpResponse { - let results = search(web::Query(info)); - - let data = json!({ - "results": results, - }); - - let body = hb.render("search", &data).unwrap(); - - HttpResponse::Ok().body(body) -} - -fn search(web::Query(info): web::Query) -> Vec { - let client = Client::new("http://localhost:7700", ""); - - let mut search_query = "".to_string(); - let mut filters = "".to_string(); - - - if let Some(q) = info.q { - search_query = q; - } - - if let Some(f) = info.f { - filters = f; - } - - if let Some(v) = info.v { - if filters.is_empty() { - filters = v; - } - else { - filters = format!("({}) AND {}", filters, v); - } - } - - let mut query = Query::new(&search_query).with_limit(10); - - if !filters.is_empty() { - query = Query::new(&search_query).with_limit(10).with_filters(&filters); - } - - client.get_index("mods").unwrap().search::(&query).unwrap().hits -} - -#[get("/")] -async fn index(hb: web::Data>) -> HttpResponse { - let data = json!({ - "name": "Handlebars" - }); - let body = hb.render("index", &data).unwrap(); - - HttpResponse::Ok().body(body) -} +mod schema; +mod routes; +mod helpers; +mod database; #[actix_rt::main] async fn main() -> std::io::Result<()> { //Handlebars let mut handlebars = Handlebars::new(); - handlebars.register_helper("contains", Box::new(ContainsHelper)); + handlebars.register_helper("contains", Box::new(helpers::ContainsHelper)); handlebars .register_templates_directory(".hbs", "./templates") .unwrap(); let handlebars_ref = web::Data::new(handlebars); - //Search - - let client = Client::new("http://localhost:7700", ""); - let mut mods = client.get_or_create("mods").unwrap(); - - mods.add_documents(vec![ - Mod { - mod_id: 0, - title: String::from("Magic Mod"), - description: String::from("An illustrious magic mod for magical wizards"), - keywords: vec![String::from("fabric"), String::from("magic"), String::from("library")], - versions: vec![String::from("1.15.2"), String::from("1.15.1"), String::from("1.15")], - }, - Mod { - mod_id: 1, - title: String::from("Tech Mod"), - description: String::from("An technological mod for complete NERDS"), - keywords: vec![String::from("fabric"), String::from("utility"), String::from("technology")], - versions: vec![String::from("1.14.1"), String::from("1.15.1"), String::from("1.15")], - }, - Mod { - mod_id: 2, - title: String::from("Gamer Mod"), - description: String::from("A gamer mod to roleplay as if you were an epic gamer person."), - keywords: vec![String::from("cursed"), String::from("adventure"), String::from("forge")], - versions: vec![String::from("20w20a"), String::from("1.15.1"), String::from("1.15")], - }, - Mod { - mod_id: 3, - title: String::from("Adventure Mod"), - description: String::from("An epic gamer adventure mod for epic adventure gamers"), - keywords: vec![String::from("decoration"), String::from("utility"), String::from("worldgen")], - versions: vec![String::from("1.12.2"), String::from("1.15.1"), String::from("1.15")] - }, - ], Some("mod_id")).unwrap(); + let database = database::connect(); + routes::index_mods(database); //Init App HttpServer::new(move || { App::new() .app_data(handlebars_ref.clone()) .service(fs::Files::new("/static", "./static").show_files_listing()) - .service(index) - .service(search_get) - .service(search_post) + .service(routes::index_get) + .service(routes::search_post) + .service(routes::search_get) }) .bind("127.0.0.1:8000")? .run() diff --git a/src/routes/index.rs b/src/routes/index.rs new file mode 100644 index 000000000..2b13d0968 --- /dev/null +++ b/src/routes/index.rs @@ -0,0 +1,12 @@ +use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post}; +use handlebars::*; + +#[get("/")] +pub async fn index_get(hb: web::Data>) -> HttpResponse { + let data = json!({ + "name": "Handlebars" + }); + let body = hb.render("index", &data).unwrap(); + + HttpResponse::Ok().body(body) +} \ No newline at end of file diff --git a/src/routes/mod.rs b/src/routes/mod.rs new file mode 100644 index 000000000..67e9b83f4 --- /dev/null +++ b/src/routes/mod.rs @@ -0,0 +1,8 @@ +mod search; +mod index; + +pub use self::search::search_get; +pub use self::search::search_post; +pub use self::search::index_mods; + +pub use self::index::index_get; \ No newline at end of file diff --git a/src/routes/search.rs b/src/routes/search.rs new file mode 100644 index 000000000..495e51c39 --- /dev/null +++ b/src/routes/search.rs @@ -0,0 +1,125 @@ +extern crate diesel; + +use actix_web::{web, web::Data, App, HttpRequest, HttpResponse, HttpServer, Responder, get, post}; +use handlebars::*; +use meilisearch_sdk::{document::*, indexes::*, client::*, search::*}; +use serde::{Serialize, Deserialize}; + +use crate::database::*; +use diesel::prelude::*; +use std::ptr::eq; + +#[derive(Serialize, Deserialize, Debug)] +struct SearchMod { + mod_id: i32, + title: String, + description: String, + keywords: Vec, + versions: Vec, +} + +impl Document for SearchMod { + type UIDType = i32; + + fn get_uid(&self) -> &Self::UIDType { + &self.mod_id + } +} + +#[derive(Deserialize)] +pub struct SearchRequest { + q: Option, + f: Option, + v: Option, +} + +#[post("search")] +pub async fn search_post(web::Query(info): web::Query, hb: Data>) -> HttpResponse { + let results = search(web::Query(info)); + + let data = json!({ + "results": results, + }); + + let body = hb.render("search_results", &data).unwrap(); + + HttpResponse::Ok().body(body) +} + +#[get("search")] +pub async fn search_get(web::Query(info): web::Query, hb: Data>) -> HttpResponse { + let results = search(web::Query(info)); + + let data = json!({ + "results": results, + }); + + let body = hb.render("search", &data).unwrap(); + + HttpResponse::Ok().body(body) +} + +fn search(web::Query(info): web::Query) -> Vec { + let client = Client::new("http://localhost:7700", ""); + + let mut search_query = "".to_string(); + let mut filters = "".to_string(); + + + if let Some(q) = info.q { + search_query = q; + } + + if let Some(f) = info.f { + filters = f; + } + + if let Some(v) = info.v { + if filters.is_empty() { + filters = v; + } + else { + filters = format!("({}) AND {}", filters, v); + } + } + + let mut query = Query::new(&search_query).with_limit(10); + + if !filters.is_empty() { + query = Query::new(&search_query).with_limit(10).with_filters(&filters); + } + + client.get_index("mods").unwrap().search::(&query).unwrap().hits +} + +pub fn index_mods(conn : PgConnection) { + use crate::schema::mods::dsl::*; + use crate::schema::versions::dsl::*; + + let client = Client::new("http://localhost:7700", ""); + let mut mods_index = client.get_or_create("mods").unwrap(); + + let results = mods.load::(&conn).expect("Error loading mods!"); + let mut docs_to_add = vec![]; + + for result in results { + let versions = versions.filter(mod_id.eq(result.id)).load::(&conn).expect("Error loading versions!"); + + let mut mod_versions = vec![]; + + for version in versions { + mod_versions.append(version.game_versions()) + } + + docs_to_add.push(SearchMod { + mod_id: result.id, + title: result.title, + description: result.description, + keywords: result.categories, + versions: vec![] + }); + } + + mods_index.add_documents(docs_to_add, Some("mod_id")); + +} \ No newline at end of file diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 000000000..b74a7ca58 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,33 @@ +table! { + mods (id) { + id -> Int4, + title -> Varchar, + description -> Varchar, + datepublished -> Date, + author -> Varchar, + downloads -> Int4, + categories -> Array, + body_path -> Varchar, + icon_path -> Varchar, + } +} + +table! { + versions (id) { + id -> Int4, + mod_id -> Int4, + title -> Varchar, + changelog_path -> Varchar, + files_path -> Array, + date_published -> Date, + author -> Varchar, + downloads -> Int4, + dependencies -> Array, + game_versions -> Array, + } +} + +allow_tables_to_appear_in_same_query!( + mods, + versions, +);