Skip to content

Commit 5279159

Browse files
committed
feat: home page development started
1 parent 7500ed4 commit 5279159

46 files changed

Lines changed: 615 additions & 213 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/src/scraper/build_dataset.rs

Lines changed: 180 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use rusqlite::Connection;
1+
use rusqlite::{params, Connection};
22
use std::fs::{self, create_dir_all, File};
33

44
use crate::scraper::{
@@ -13,63 +13,198 @@ pub async fn fetch_all_products() -> Result<(), Box<dyn std::error::Error>> {
1313
// Metro supermarket
1414
let metro_products = fetch_metro_products().await;
1515
let metro_file = File::create("src/scraper/results/metro.json")?;
16-
let Metro = Supermarket {
16+
17+
let metro = Supermarket {
1718
supermarket_name: "Metro".to_string(),
1819
products: metro_products,
1920
};
2021

21-
serde_json::to_writer_pretty(metro_file, &Metro)?;
22-
println!("Saved {} products from metro", Metro.products.len());
22+
serde_json::to_writer_pretty(metro_file, &metro)?;
23+
24+
println!("Saved {} products from metro", metro.products.len());
2325

2426
Ok(())
2527
}
2628

2729
pub fn build_database() -> Result<(), Box<dyn std::error::Error>> {
2830
let supermarkets = vec!["metro"];
29-
let conn = Connection::open("main.db")?;
31+
32+
let mut conn = Connection::open("main.db")?;
33+
34+
conn.execute("PRAGMA foreign_keys = ON;", [])?;
35+
36+
//
37+
// Static tables
38+
//
3039

3140
conn.execute(
3241
"
3342
CREATE TABLE IF NOT EXISTS supermarkets (
34-
id TEXT PRIMARY KEY,
35-
name TEXT NOT NULL
43+
id TEXT PRIMARY KEY,
44+
name TEXT NOT NULL
3645
)
37-
",
46+
",
3847
[],
3948
)?;
4049

4150
conn.execute(
4251
"
4352
CREATE TABLE IF NOT EXISTS products (
44-
id TEXT PRIMARY KEY,
45-
name TEXT NOT NULL,
46-
source INTEGER NOT NULL,
47-
brand TEXT,
48-
category TEXT,
49-
weight REAL,
50-
proteins REAL,
51-
fats REAL,
52-
carbs REAL,
53-
calories REAL,
54-
FOREIGN KEY (source) REFERENCES supermarkets (id)
53+
id TEXT PRIMARY KEY,
54+
55+
name TEXT NOT NULL,
56+
57+
source TEXT NOT NULL,
58+
59+
brand TEXT,
60+
61+
source_category TEXT,
62+
63+
serving_size REAL,
64+
65+
proteins_per_100g REAL,
66+
67+
fats_per_100g REAL,
68+
69+
carbs_per_100g REAL,
70+
71+
calories_per_100g REAL,
72+
73+
version INTEGER NOT NULL DEFAULT 1,
74+
75+
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
76+
77+
FOREIGN KEY (source)
78+
REFERENCES supermarkets(id)
5579
)
56-
",
80+
",
5781
[],
5882
)?;
5983

60-
let mut stmt_supermarket = conn.prepare(
84+
//
85+
// User tables
86+
//
87+
88+
conn.execute(
6189
"
62-
INSERT INTO supermarkets
63-
(id, name)
90+
CREATE TABLE IF NOT EXISTS food_entries (
91+
id TEXT PRIMARY KEY,
92+
93+
logged_at TEXT NOT NULL,
94+
95+
logged_day TEXT NOT NULL,
96+
97+
meal_type TEXT NOT NULL,
98+
99+
product_id TEXT NOT NULL,
100+
101+
grams REAL NOT NULL,
102+
103+
FOREIGN KEY (product_id)
104+
REFERENCES products(id)
105+
)
106+
",
107+
[],
108+
)?;
109+
110+
conn.execute(
111+
"
112+
CREATE TABLE IF NOT EXISTS weight_entries (
113+
id TEXT PRIMARY KEY,
114+
115+
logged_at TEXT NOT NULL,
116+
117+
weight REAL NOT NULL
118+
)
119+
",
120+
[],
121+
)?;
122+
123+
conn.execute(
124+
"
125+
CREATE TABLE IF NOT EXISTS favorite_products (
126+
product_id TEXT PRIMARY KEY,
127+
128+
FOREIGN KEY (product_id)
129+
REFERENCES products(id)
130+
)
131+
",
132+
[],
133+
)?;
134+
135+
conn.execute(
136+
"
137+
CREATE TABLE IF NOT EXISTS meal_templates (
138+
id TEXT PRIMARY KEY,
139+
140+
name TEXT NOT NULL
141+
)
142+
",
143+
[],
144+
)?;
145+
146+
conn.execute(
147+
"
148+
CREATE TABLE IF NOT EXISTS meal_template_items (
149+
meal_template_id TEXT NOT NULL,
150+
151+
product_id TEXT NOT NULL,
152+
153+
grams REAL NOT NULL,
154+
155+
PRIMARY KEY (
156+
meal_template_id,
157+
product_id
158+
),
159+
160+
FOREIGN KEY (meal_template_id)
161+
REFERENCES meal_templates(id),
162+
163+
FOREIGN KEY (product_id)
164+
REFERENCES products(id)
165+
)
166+
",
167+
[],
168+
)?;
169+
170+
let tx = conn.transaction()?;
171+
172+
let mut stmt_supermarket = tx.prepare(
173+
"
174+
INSERT OR IGNORE INTO supermarkets (
175+
id,
176+
name
177+
)
64178
VALUES (?1, ?2)
65179
",
66180
)?;
67181

68-
let mut stmt_product = conn.prepare(
182+
let mut stmt_product = tx.prepare(
69183
"
70-
INSERT OR IGNORE INTO products
71-
(id, name, source, brand, category, weight, proteins, fats, carbs, calories)
72-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)
184+
INSERT OR IGNORE INTO products (
185+
id,
186+
name,
187+
source,
188+
brand,
189+
source_category,
190+
serving_size,
191+
proteins_per_100g,
192+
fats_per_100g,
193+
carbs_per_100g,
194+
calories_per_100g
195+
)
196+
VALUES (
197+
?1,
198+
?2,
199+
?3,
200+
?4,
201+
?5,
202+
?6,
203+
?7,
204+
?8,
205+
?9,
206+
?10
207+
)
73208
",
74209
)?;
75210

@@ -82,33 +217,36 @@ pub fn build_database() -> Result<(), Box<dyn std::error::Error>> {
82217

83218
let supermarket_id = generate_supermarket_id(&supermarket_struct.supermarket_name);
84219

85-
// first insert supermarket into it's table
86-
stmt_supermarket.execute([&supermarket_id, &supermarket_struct.supermarket_name])?;
220+
stmt_supermarket.execute(params![supermarket_id, supermarket_struct.supermarket_name])?;
87221

88222
for product in products {
89-
// then product itself
90223
let product_id = generate_product_id(
91224
&supermarket_id,
92225
&product.name,
93226
&product.brand.clone().unwrap_or_default(),
94-
&product.weight.unwrap_or(0.0),
227+
&product.serving_size.unwrap_or(0.0),
95228
);
96229

97-
stmt_product.execute([
98-
&product_id,
99-
&product.name,
100-
&supermarket_id.to_string(),
101-
&product.brand.unwrap_or_default(),
102-
&product.category,
103-
&product.weight.unwrap_or(0.0).to_string(),
104-
&product.nutrients.proteins.unwrap_or(0.0).to_string(),
105-
&product.nutrients.fats.unwrap_or(0.0).to_string(),
106-
&product.nutrients.carbohydrates.unwrap_or(0.0).to_string(),
107-
&product.nutrients.calories.unwrap_or(0.0).to_string(),
230+
stmt_product.execute(params![
231+
product_id,
232+
product.name,
233+
supermarket_id,
234+
product.brand.unwrap_or_default(),
235+
product.category,
236+
product.serving_size.unwrap_or(0.0),
237+
product.nutrients.proteins.unwrap_or(0.0),
238+
product.nutrients.fats.unwrap_or(0.0),
239+
product.nutrients.carbohydrates.unwrap_or(0.0),
240+
product.nutrients.calories.unwrap_or(0.0),
108241
])?;
109242
}
110243
}
111244

245+
drop(stmt_product);
246+
drop(stmt_supermarket);
247+
248+
tx.commit()?;
249+
112250
println!("Database initiated from json files!");
113251

114252
Ok(())

backend/src/scraper/models.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@ pub struct Attribute {
3030

3131
#[derive(Serialize, Deserialize)]
3232
pub struct Nutrients {
33-
pub proteins: Option<f32>,
34-
pub fats: Option<f32>,
35-
pub carbohydrates: Option<f32>,
36-
pub calories: Option<f32>,
33+
pub proteins: Option<f64>,
34+
pub fats: Option<f64>,
35+
pub carbohydrates: Option<f64>,
36+
pub calories: Option<f64>,
3737
}
3838

3939
#[derive(Serialize, Deserialize)]
4040
pub struct ParsedProduct {
4141
pub name: String,
4242
pub brand: Option<String>,
43-
pub weight: Option<f32>,
43+
pub serving_size: Option<f64>,
4444
pub category: String,
4545
pub nutrients: Nutrients,
4646
}

backend/src/scraper/parser.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub fn parse_product(
66
category: &str,
77
) -> ParsedProduct {
88
let mut brand = None;
9-
let mut weight = None;
9+
let mut serving_size = None;
1010

1111
let mut nutrients = Nutrients {
1212
proteins: None,
@@ -28,7 +28,7 @@ pub fn parse_product(
2828

2929
match name_attr.as_str() {
3030
"Бренд" => brand = Some(value),
31-
"Вес, объем" => weight = value.parse().ok(),
31+
"Вес, объем" => serving_size = value.parse().ok(),
3232
"Белки, г" => nutrients.proteins = value.parse().ok(),
3333
"Жиры, г" => nutrients.fats = value.parse().ok(),
3434
"Углеводы, г" => nutrients.carbohydrates = value.parse().ok(),
@@ -42,7 +42,7 @@ pub fn parse_product(
4242
ParsedProduct {
4343
name: name.unwrap_or_else(|| "unknown".to_string()),
4444
brand,
45-
weight,
45+
serving_size,
4646
category: category.to_string(),
4747
nutrients,
4848
}

backend/src/scraper/utils.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use hex::encode;
21
use sha2::{Digest, Sha256};
32

4-
pub fn generate_product_id(source: &str, name: &str, brand: &str, weight: &f32) -> String {
3+
pub fn generate_product_id(source: &str, name: &str, brand: &str, serving_size: &f64) -> String {
54
let input = format!(
65
"{}:{}:{}:{}",
76
source.to_lowercase(),
87
name.to_lowercase(),
98
brand.to_lowercase(),
10-
weight
9+
serving_size
1110
);
1211

1312
let mut hasher = Sha256::new();

mobile/.env

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
EXPO_PUBLIC_RESET_STORAGE=True

mobile/app.json

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,7 @@
4141
}
4242
}
4343
],
44-
"expo-sqlite",
45-
[
46-
"expo-font",
47-
{
48-
"fonts": ["./assets/fonts/Seenonim.otf"]
49-
}
50-
],
51-
[
52-
"expo-localization",
53-
{
54-
"supportedLocales": {
55-
"ios": ["ru"]
56-
}
57-
}
58-
]
44+
"expo-sqlite"
5945
],
6046
"experiments": {
6147
"typedRoutes": true,

mobile/app/(app)/_layout.tsx

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)