├── .gitignore ├── cnf.db ├── cnf ├── FOOD GROUP.xlsx ├── FOOD NAME.xlsx ├── FOOD SOURCE.xlsx ├── MEASURE NAME.xlsx ├── YIELD AMOUNT.xlsx ├── YIELD NAME.xlsx ├── NUTRIENT NAME.xlsx ├── NUTRIENT SOURCE.xlsx ├── REFUSE AMOUNT.xlsx ├── REFUSE NAME.xlsx ├── CONVERSION FACTOR.xlsx ├── NUTRIENT AMOUNT.xlsx ├── CNF 2015 users_guide EN.pdf ├── CNF 2015 users_guide FR.pdf ├── CNF 2015 Database structure EN .pdf └── CNF 2015 database structure FR .pdf ├── .gitattributes ├── Cargo.toml ├── Cargo.lock └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /cnf.db: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0165e758902779d9954db278688b0c7923894b93871ba4bcd66fcb7b0d00cf25 3 | size 2125824 4 | -------------------------------------------------------------------------------- /cnf/FOOD GROUP.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:55c7c2bb504d255ce15a94a3874a96e5442bb9d8662cf825bf4e725accc8d8a3 3 | size 10745 4 | -------------------------------------------------------------------------------- /cnf/FOOD NAME.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:c885906985ea12724213c7b80eb0618f92a6772788f8881d01ee99feb287a2ba 3 | size 489997 4 | -------------------------------------------------------------------------------- /cnf/FOOD SOURCE.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:63ffdcfc5aa2e1d3c736267f03b721bae36f0370debe37b08c3776ec582010ad 3 | size 9826 4 | -------------------------------------------------------------------------------- /cnf/MEASURE NAME.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a37b0a9dd3f45eeab4acf00d8b382c62ad52a11c136435532878da5e01cf84f8 3 | size 52194 4 | -------------------------------------------------------------------------------- /cnf/YIELD AMOUNT.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:1cec02b1e524a85c08bcb5df34123b3dd42a55060b3e42a331e88339d5f3378a 3 | size 58256 4 | -------------------------------------------------------------------------------- /cnf/YIELD NAME.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:429cfb17b38fcc90b459162cec6f9732dc6a8d0214258e6614b386d616bc1c87 3 | size 2972609 4 | -------------------------------------------------------------------------------- /cnf/NUTRIENT NAME.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:2470a5cf78b3f5716f103e43e60047f3045d32fd248e29814e7c6b0a749f68c3 3 | size 19180 4 | -------------------------------------------------------------------------------- /cnf/NUTRIENT SOURCE.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:0c13f2c09cfb8703ed6b8561bd5fe8c23c646660538bcfd4eb086899b4db75dd 3 | size 11060 4 | -------------------------------------------------------------------------------- /cnf/REFUSE AMOUNT.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a12f6084d30c4014ad26d08fe911f8a586af428823afa47876e800280b53b329 3 | size 195122 4 | -------------------------------------------------------------------------------- /cnf/REFUSE NAME.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:a4dbe787fbd3d470027d6b50137dafde353c1a9de478570e803f90519ed56c36 3 | size 2976099 4 | -------------------------------------------------------------------------------- /cnf/CONVERSION FACTOR.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:9d5540d8cd4529b01a07b9212cc00514bfc972e4cc04203c4f7b5170cadf4d5e 3 | size 667382 4 | -------------------------------------------------------------------------------- /cnf/NUTRIENT AMOUNT.xlsx: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:b40522a13b018116d8f6f3bec30ae97cda102eec1fae9b0385aa4bee79bcdac1 3 | size 21400432 4 | -------------------------------------------------------------------------------- /cnf/CNF 2015 users_guide EN.pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:263ffec67da58b3a87f2eabd39336543c826af0867b7f6e5d2d8f9d88f7a88d4 3 | size 1665394 4 | -------------------------------------------------------------------------------- /cnf/CNF 2015 users_guide FR.pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:bae0c85e116a037ac0fd12d45e0cbfbd2ffcd450af7780879c115648f9d14d3a 3 | size 1637393 4 | -------------------------------------------------------------------------------- /cnf/CNF 2015 Database structure EN .pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7fede9bc8c8c9e2ab4574906681ed051fd633b9e53dcd399692465e9476eead1 3 | size 893270 4 | -------------------------------------------------------------------------------- /cnf/CNF 2015 database structure FR .pdf: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:76ef2ccf73dd8684cb2672a40c22126aff749954f063ce4a125fac5c45019e7a 3 | size 972920 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pdf filter=lfs diff=lfs merge=lfs -text 2 | *.db filter=lfs diff=lfs merge=lfs -text 3 | *.csv filter=lfs diff=lfs merge=lfs -text 4 | *.xlsx filter=lfs diff=lfs merge=lfs -text 5 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gen-chubster-food-db-cnf-2015" 3 | version = "1.0.0" 4 | authors = ["Kenton Hamaluik "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | rusqlite = { version = "0.21", features = ["bundled"] } 9 | indicatif = "0.13" 10 | calamine = "0.16" 11 | memmap = "0.7" 12 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "adler32" 5 | version = "1.0.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" 8 | 9 | [[package]] 10 | name = "atty" 11 | version = "0.2.14" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 14 | dependencies = [ 15 | "hermit-abi", 16 | "libc", 17 | "winapi", 18 | ] 19 | 20 | [[package]] 21 | name = "bitflags" 22 | version = "1.2.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 25 | 26 | [[package]] 27 | name = "byteorder" 28 | version = "1.3.2" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 31 | 32 | [[package]] 33 | name = "calamine" 34 | version = "0.16.1" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "abc39da027ec520445e6e526f105170b424ca68ea9e53553d3e6a29df41713ba" 37 | dependencies = [ 38 | "byteorder", 39 | "codepage", 40 | "encoding_rs", 41 | "log", 42 | "quick-xml", 43 | "serde", 44 | "zip", 45 | ] 46 | 47 | [[package]] 48 | name = "cc" 49 | version = "1.0.50" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" 52 | 53 | [[package]] 54 | name = "cfg-if" 55 | version = "0.1.10" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 58 | 59 | [[package]] 60 | name = "clicolors-control" 61 | version = "1.0.1" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 64 | dependencies = [ 65 | "atty", 66 | "lazy_static", 67 | "libc", 68 | "winapi", 69 | ] 70 | 71 | [[package]] 72 | name = "codepage" 73 | version = "0.1.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "8b0e9222c0cdf2c6ac27d73f664f9520266fa911c3106329d359f8861cb8bde9" 76 | dependencies = [ 77 | "encoding_rs", 78 | ] 79 | 80 | [[package]] 81 | name = "console" 82 | version = "0.9.1" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "f5d540c2d34ac9dd0deb5f3b5f54c36c79efa78f6b3ad19106a554d07a7b5d9f" 85 | dependencies = [ 86 | "clicolors-control", 87 | "encode_unicode", 88 | "lazy_static", 89 | "libc", 90 | "regex", 91 | "termios", 92 | "unicode-width", 93 | "winapi", 94 | ] 95 | 96 | [[package]] 97 | name = "crc32fast" 98 | version = "1.2.0" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 101 | dependencies = [ 102 | "cfg-if", 103 | ] 104 | 105 | [[package]] 106 | name = "encode_unicode" 107 | version = "0.3.6" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 110 | 111 | [[package]] 112 | name = "encoding_rs" 113 | version = "0.8.22" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" 116 | dependencies = [ 117 | "cfg-if", 118 | ] 119 | 120 | [[package]] 121 | name = "fallible-iterator" 122 | version = "0.2.0" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" 125 | 126 | [[package]] 127 | name = "fallible-streaming-iterator" 128 | version = "0.1.9" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" 131 | 132 | [[package]] 133 | name = "flate2" 134 | version = "1.0.13" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" 137 | dependencies = [ 138 | "cfg-if", 139 | "crc32fast", 140 | "libc", 141 | "miniz_oxide", 142 | ] 143 | 144 | [[package]] 145 | name = "gen-chubster-food-db-cnf-2015" 146 | version = "1.0.0" 147 | dependencies = [ 148 | "calamine", 149 | "indicatif", 150 | "memmap", 151 | "rusqlite", 152 | ] 153 | 154 | [[package]] 155 | name = "hermit-abi" 156 | version = "0.1.6" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" 159 | dependencies = [ 160 | "libc", 161 | ] 162 | 163 | [[package]] 164 | name = "indicatif" 165 | version = "0.13.0" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "8572bccfb0665e70b7faf44ee28841b8e0823450cd4ad562a76b5a3c4bf48487" 168 | dependencies = [ 169 | "console", 170 | "lazy_static", 171 | "number_prefix", 172 | "regex", 173 | ] 174 | 175 | [[package]] 176 | name = "lazy_static" 177 | version = "1.4.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 180 | 181 | [[package]] 182 | name = "libc" 183 | version = "0.2.66" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 186 | 187 | [[package]] 188 | name = "libsqlite3-sys" 189 | version = "0.17.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "266eb8c361198e8d1f682bc974e5d9e2ae90049fb1943890904d11dad7d4a77d" 192 | dependencies = [ 193 | "cc", 194 | "pkg-config", 195 | "vcpkg", 196 | ] 197 | 198 | [[package]] 199 | name = "linked-hash-map" 200 | version = "0.5.2" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 203 | 204 | [[package]] 205 | name = "log" 206 | version = "0.4.8" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 209 | dependencies = [ 210 | "cfg-if", 211 | ] 212 | 213 | [[package]] 214 | name = "lru-cache" 215 | version = "0.1.2" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" 218 | dependencies = [ 219 | "linked-hash-map", 220 | ] 221 | 222 | [[package]] 223 | name = "memchr" 224 | version = "2.3.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" 227 | 228 | [[package]] 229 | name = "memmap" 230 | version = "0.7.0" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" 233 | dependencies = [ 234 | "libc", 235 | "winapi", 236 | ] 237 | 238 | [[package]] 239 | name = "miniz_oxide" 240 | version = "0.3.5" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625" 243 | dependencies = [ 244 | "adler32", 245 | ] 246 | 247 | [[package]] 248 | name = "number_prefix" 249 | version = "0.3.0" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a" 252 | 253 | [[package]] 254 | name = "pkg-config" 255 | version = "0.3.17" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" 258 | 259 | [[package]] 260 | name = "podio" 261 | version = "0.1.6" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" 264 | 265 | [[package]] 266 | name = "quick-xml" 267 | version = "0.17.2" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "fe1e430bdcf30c9fdc25053b9c459bb1a4672af4617b6c783d7d91dc17c6bbb0" 270 | dependencies = [ 271 | "encoding_rs", 272 | "memchr", 273 | ] 274 | 275 | [[package]] 276 | name = "redox_syscall" 277 | version = "0.1.56" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 280 | 281 | [[package]] 282 | name = "regex" 283 | version = "1.3.3" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" 286 | dependencies = [ 287 | "regex-syntax", 288 | ] 289 | 290 | [[package]] 291 | name = "regex-syntax" 292 | version = "0.6.13" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" 295 | 296 | [[package]] 297 | name = "rusqlite" 298 | version = "0.21.0" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "64a656821bb6317a84b257737b7934f79c0dbb7eb694710475908280ebad3e64" 301 | dependencies = [ 302 | "bitflags", 303 | "fallible-iterator", 304 | "fallible-streaming-iterator", 305 | "libsqlite3-sys", 306 | "lru-cache", 307 | "memchr", 308 | "time", 309 | ] 310 | 311 | [[package]] 312 | name = "serde" 313 | version = "1.0.104" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" 316 | 317 | [[package]] 318 | name = "termios" 319 | version = "0.3.1" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 322 | dependencies = [ 323 | "libc", 324 | ] 325 | 326 | [[package]] 327 | name = "time" 328 | version = "0.1.42" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 331 | dependencies = [ 332 | "libc", 333 | "redox_syscall", 334 | "winapi", 335 | ] 336 | 337 | [[package]] 338 | name = "unicode-width" 339 | version = "0.1.7" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 342 | 343 | [[package]] 344 | name = "vcpkg" 345 | version = "0.2.8" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" 348 | 349 | [[package]] 350 | name = "winapi" 351 | version = "0.3.8" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 354 | dependencies = [ 355 | "winapi-i686-pc-windows-gnu", 356 | "winapi-x86_64-pc-windows-gnu", 357 | ] 358 | 359 | [[package]] 360 | name = "winapi-i686-pc-windows-gnu" 361 | version = "0.4.0" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 364 | 365 | [[package]] 366 | name = "winapi-x86_64-pc-windows-gnu" 367 | version = "0.4.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 370 | 371 | [[package]] 372 | name = "zip" 373 | version = "0.5.4" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "e41ff37ba788e2169b19fa70253b70cb53d9f2db9fb9aea9bcfc5047e02c3bae" 376 | dependencies = [ 377 | "crc32fast", 378 | "flate2", 379 | "podio", 380 | ] 381 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use calamine::{Reader, Xlsx}; 2 | use rusqlite::{params}; 3 | use std::fs::File; 4 | use std::io::Cursor; 5 | 6 | const ENERGY_ID: i64 = 208; 7 | const FAT_TOTAL_ID: i64 = 204; 8 | const FAT_SATURATED_ID: i64 = 606; 9 | const FAT_POLY_ID: i64 = 646; 10 | const FAT_MONO_ID: i64 = 645; 11 | const FAT_TRANS_ID: i64 = 605; 12 | const CHOLESTEROL_ID: i64 = 601; 13 | const SODIUM_ID: i64 = 307; 14 | const CARBS_ID: i64 = 205; 15 | const FIBER_ID: i64 = 291; 16 | const SUGARS_ID: i64 = 269; 17 | const PROTEIN_ID: i64 = 203; 18 | const CALCIUM_ID: i64 = 301; 19 | const POTASSIUM_ID: i64 = 306; 20 | const IRON_ID: i64 = 303; 21 | const ALCOHOL_ID: i64 = 221; 22 | const CAFFEINE_ID: i64 = 262; 23 | 24 | fn main() { 25 | // start our database that we can work off of 26 | println!("opening in-mem DB representation.."); 27 | let mem_con = rusqlite::Connection::open_in_memory().expect("can open sqlite in memory"); 28 | mem_con 29 | .execute_batch( 30 | r#" 31 | begin; 32 | create table nutrients( 33 | food_id integer not null, 34 | nutrient_id integer not null, 35 | nutrient_value real not null 36 | ); 37 | create index nutrients_food_id on nutrients(food_id); 38 | commit; 39 | "#, 40 | ) 41 | .expect("can initialize tables"); 42 | 43 | // load up our foods 44 | let mut food_ids: Vec<(i64, String)> = Vec::with_capacity(5000); 45 | println!("loading food names & ids..."); 46 | { 47 | let foods_file = File::open("cnf/FOOD NAME.xlsx").expect("can open FOOD NAME.xlsx"); 48 | let foods_file = 49 | unsafe { memmap::Mmap::map(&foods_file).expect("can memmap FOOD NAME.xlsx") }; 50 | let mut foods = Xlsx::new(Cursor::new(&foods_file[..])).expect("can load FOOD NAME.xlsx"); 51 | let worksheet_name = foods.sheet_names()[0].to_owned(); 52 | let range = foods 53 | .worksheet_range(&worksheet_name) 54 | .expect("valid sheet") 55 | .expect("can open FOOD NAME worksheet"); 56 | 57 | for row in range.rows().skip(1) { 58 | let id: f64 = row[0].get_float().expect("float food id"); 59 | let id: i64 = id as i64; 60 | let description = row[4].get_string().expect("string food description"); 61 | food_ids.push((id, description.to_owned())); 62 | } 63 | } 64 | 65 | // load up our nutrients 66 | println!("loading nutrient values..."); 67 | { 68 | let nutrients_file = 69 | File::open("cnf/NUTRIENT AMOUNT.xlsx").expect("can open NUTRIENT AMOUNT.xlsx"); 70 | let nutrients_file = 71 | unsafe { memmap::Mmap::map(&nutrients_file).expect("can memmap NUTRIENT AMOUNT.xlsx") }; 72 | let mut nutrients = 73 | Xlsx::new(Cursor::new(&nutrients_file[..])).expect("can load NUTRIENT AMOUNT.xlsx"); 74 | let worksheet_name = nutrients.sheet_names()[0].to_owned(); 75 | let range = nutrients 76 | .worksheet_range(&worksheet_name) 77 | .expect("valid sheet") 78 | .expect("can open NUTRIENT AMOUNT worksheet"); 79 | 80 | let mut stmt = mem_con 81 | .prepare_cached( 82 | "insert into nutrients(food_id, nutrient_id, nutrient_value) values(?, ?, ?)", 83 | ) 84 | .expect("valid insert query"); 85 | for row in range.rows().skip(1) { 86 | let food_id: f64 = row[0].get_float().expect("float food id"); 87 | let food_id: i64 = food_id as i64; 88 | 89 | let nutrient_id: f64 = row[1].get_float().expect("float nutrient id"); 90 | let nutrient_id: i64 = nutrient_id as i64; 91 | 92 | let nutrient_value: f64 = row[2].get_float().expect("float nutrient value"); 93 | stmt.execute(params![food_id, nutrient_id, nutrient_value]) 94 | .expect("can insert nutrient"); 95 | } 96 | } 97 | 98 | // open the output database 99 | println!("opening output database..."); 100 | if std::path::Path::new("cnf.db").exists() { 101 | std::fs::remove_file("cnf.db").expect("can delete existing cnf.db file"); 102 | } 103 | let db = rusqlite::Connection::open("cnf.db").expect("can create cnf.db"); 104 | db.execute_batch( 105 | r#" 106 | begin; 107 | PRAGMA foreign_keys = ON; 108 | create table foods( 109 | id integer not null primary key autoincrement, 110 | name text not null, 111 | energy real default null, -- kCal / 100g 112 | fat_total real default null, -- g / 100g 113 | fat_saturated real default null, -- g / 100g 114 | fat_transaturated real default null, -- g / 100g 115 | fat_polyunsaturated real default null, -- g / 100g 116 | fat_monounsaturated real default null, -- g / 100g 117 | cholesterol real default null, -- mg / 100g 118 | sodium real default null, -- mg / 100g 119 | carbohydrates real default null, -- g / 100g 120 | fiber real default null, -- g / 100g 121 | sugars real default null, -- g / 100g 122 | protein real default null, -- g / 100g 123 | calcium real default null, -- mg / 100g 124 | potassium real default null, -- mg / 100g 125 | iron real default null, -- mg / 100g 126 | alcohol real default null, -- g / 100g 127 | caffeine real default null -- mg / 100g 128 | ); 129 | create index food_name on foods(name); 130 | create table measurements( 131 | id integer not null primary key autoincrement, 132 | description text not null 133 | ); 134 | create table conversions( 135 | food_id integer not null, 136 | measurement_id integer not null, 137 | conversion_factor real not null, -- 1 measure * conversion_factor = 100g 138 | unique(food_id, measurement_id), 139 | foreign key(food_id) references foods(id), 140 | foreign key(measurement_id) references measurements(id) 141 | ); 142 | create index conversions_food_id on conversions(food_id); 143 | commit; 144 | "#, 145 | ) 146 | .expect("can initialize chubster tables"); 147 | 148 | // load up our measurements 149 | println!("loading measurement values..."); 150 | { 151 | let measurements_file = 152 | File::open("cnf/MEASURE NAME.xlsx").expect("can open MEASURE NAME.xlsx"); 153 | let measurements_file = 154 | unsafe { memmap::Mmap::map(&measurements_file).expect("can memmap MEASURE NAME.xlsx") }; 155 | let mut measurements = 156 | Xlsx::new(Cursor::new(&measurements_file[..])).expect("can load MEASURE NAME.xlsx"); 157 | let worksheet_name = measurements.sheet_names()[0].to_owned(); 158 | let range = measurements 159 | .worksheet_range(&worksheet_name) 160 | .expect("valid sheet") 161 | .expect("can open MEASURE NAME worksheet"); 162 | 163 | let mut stmt = db 164 | .prepare_cached( 165 | "insert into measurements(id, description) values(?, ?)", 166 | ) 167 | .expect("valid insert query"); 168 | for row in range.rows().skip(1) { 169 | let measurement_id: f64 = row[0].get_float().expect("float measurement id"); 170 | let measurement_id: i64 = measurement_id as i64; 171 | 172 | let description: &str = row[1].get_string().expect("string measurement value"); 173 | stmt.execute(params![measurement_id, description]) 174 | .expect("can insert measurement"); 175 | } 176 | } 177 | 178 | // start going through the foods 179 | println!("processing foods..."); 180 | { 181 | let pb = indicatif::ProgressBar::new(food_ids.len() as u64); 182 | pb.set_style(indicatif::ProgressStyle::default_bar() 183 | .template("{pos:>7}/{len:7} {wide_bar} [{elapsed_precise}] ({eta_precise})")); 184 | let mut nutrient_stmt = mem_con 185 | .prepare_cached("select nutrient_id, nutrient_value from nutrients where food_id=?") 186 | .expect("valid select query"); 187 | let mut insert_food_stmt = db 188 | .prepare_cached("insert into foods(id, name, energy, fat_total, fat_saturated, fat_transaturated, fat_polyunsaturated, fat_monounsaturated, cholesterol, sodium, carbohydrates, fiber, sugars, protein, calcium, potassium, iron, alcohol, caffeine) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)") 189 | .expect("valid insert query"); 190 | for (food_id, food_description) in food_ids.iter() { 191 | // get all the nutrients 192 | let nutrients = nutrient_stmt 193 | .query_map(params![food_id], |row| { 194 | let nutient_id: i64 = row.get(0)?; 195 | let nutrient_value: f64 = row.get(1)?; 196 | Ok((nutient_id, nutrient_value)) 197 | }) 198 | .expect("can execute select query"); 199 | 200 | let mut energy: Option = None; 201 | let mut fat_total: Option = None; 202 | let mut fat_saturated: Option = None; 203 | let mut fat_poly: Option = None; 204 | let mut fat_mono: Option = None; 205 | let mut fat_trans: Option = None; 206 | let mut cholesterol: Option = None; 207 | let mut sodium: Option = None; 208 | let mut carbs: Option = None; 209 | let mut fiber: Option = None; 210 | let mut sugars: Option = None; 211 | let mut protein: Option = None; 212 | let mut calcium: Option = None; 213 | let mut potassium: Option = None; 214 | let mut iron: Option = None; 215 | let mut alcohol: Option = None; 216 | let mut caffeine: Option = None; 217 | for nutrient in nutrients { 218 | let nutrient = nutrient.expect("valid nutrient result"); 219 | match nutrient.0 { 220 | ENERGY_ID => energy = Some(nutrient.1), 221 | FAT_TOTAL_ID => fat_total = Some(nutrient.1), 222 | FAT_SATURATED_ID => fat_saturated = Some(nutrient.1), 223 | FAT_POLY_ID => fat_poly = Some(nutrient.1), 224 | FAT_MONO_ID => fat_mono = Some(nutrient.1), 225 | FAT_TRANS_ID => fat_trans = Some(nutrient.1), 226 | CHOLESTEROL_ID => cholesterol = Some(nutrient.1), 227 | SODIUM_ID => sodium = Some(nutrient.1), 228 | CARBS_ID => carbs = Some(nutrient.1), 229 | FIBER_ID => fiber = Some(nutrient.1), 230 | SUGARS_ID => sugars = Some(nutrient.1), 231 | PROTEIN_ID => protein = Some(nutrient.1), 232 | CALCIUM_ID => calcium = Some(nutrient.1), 233 | POTASSIUM_ID => potassium = Some(nutrient.1), 234 | IRON_ID => iron = Some(nutrient.1), 235 | ALCOHOL_ID => alcohol = Some(nutrient.1), 236 | CAFFEINE_ID => caffeine = Some(nutrient.1), 237 | _ => {} // skip nutrients we don't care about 238 | } 239 | } 240 | 241 | insert_food_stmt.execute(params![food_id, food_description, energy, fat_total, fat_saturated, fat_trans, fat_poly, fat_mono, cholesterol, sodium, carbs, fiber, sugars, protein, calcium, potassium, iron, alcohol, caffeine]).expect("can insert food"); 242 | 243 | pb.inc(1); 244 | } 245 | pb.finish_with_message("done"); 246 | } 247 | 248 | // load up our conversions 249 | println!("loading conversion values..."); 250 | { 251 | let conversions_file = 252 | File::open("cnf/CONVERSION FACTOR.xlsx").expect("can open CONVERSION FACTOR.xlsx"); 253 | let conversions_file = 254 | unsafe { memmap::Mmap::map(&conversions_file).expect("can memmap CONVERSION FACTOR.xlsx") }; 255 | let mut conversions = 256 | Xlsx::new(Cursor::new(&conversions_file[..])).expect("can load CONVERSION FACTOR.xlsx"); 257 | let worksheet_name = conversions.sheet_names()[0].to_owned(); 258 | let range = conversions 259 | .worksheet_range(&worksheet_name) 260 | .expect("valid sheet") 261 | .expect("can open CONVERSION FACTOR worksheet"); 262 | 263 | let mut stmt = db 264 | .prepare_cached( 265 | "insert into conversions(food_id, measurement_id, conversion_factor) values(?, ?, ?)", 266 | ) 267 | .expect("valid insert query"); 268 | for row in range.rows().skip(1) { 269 | let food_id: f64 = row[0].get_float().expect("float food_id"); 270 | let food_id: i64 = food_id as i64; 271 | 272 | let measurement_id: f64 = row[1].get_float().expect("float measurement_id"); 273 | let measurement_id: i64 = measurement_id as i64; 274 | 275 | let conversion_factor: f64 = row[2].get_float().expect("float conversion_factor"); 276 | 277 | if let Err(e) = stmt.execute(params![food_id, measurement_id, conversion_factor]) { 278 | let food_count: i64 = db.query_row("select count(*) from foods where id=?", params![food_id], |row| row.get(0)).expect("can query food id count"); 279 | let measurement_count: i64 = db.query_row("select count(*) from measurements where id=?", params![measurement_id], |row| row.get(0)).expect("can query measurement id count"); 280 | 281 | eprintln!("WARNING: failed to insert conversion for food_id: {} (found {} matching rows), measurement_id: {} (found {} matching rows)\n{:?}", food_id, food_count, measurement_id, measurement_count, e); 282 | } 283 | } 284 | } 285 | 286 | // NOTE: all nutrition values in the foods table are per 100g 287 | // To get all common measurements and conversions for a given food id, you can 288 | // join on the measurements and conversions tables. For example: 289 | // 290 | // ```sql 291 | // select description, conversion_factor from conversions inner join measurements on measurements.id=conversions.measurement_id where food_id=? 292 | // ``` 293 | 294 | drop(mem_con); 295 | drop(db); 296 | println!("database saved to `cnf.db`!"); 297 | } 298 | --------------------------------------------------------------------------------