1- use rusqlite:: Connection ;
1+ use rusqlite:: { params , Connection } ;
22use std:: fs:: { self , create_dir_all, File } ;
33
44use 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
2729pub 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 ( ( ) )
0 commit comments