backend/model/entity.rs
1//! Contains all entities used in `PermaplanT`.
2//!
3//! The fill & error ratios in the file can be calculated and updated automatically
4//! via the script in /tools/update-fill-error-ratio/update-fill-error-ratio.py (usage in respective README)
5//!
6//! Latest script run was on 31.07.2026
7//! Git SHA of the scraper-data commit used: 87dc5b7e872727121233bf319af8f84e2feda4a7
8
9pub mod application_settings_impl;
10pub mod areas;
11pub mod areas_impl;
12pub mod base_layer_images;
13pub mod base_layer_images_impl;
14pub mod drawing_properties;
15pub mod drawing_properties_impl;
16pub mod drawings;
17pub mod drawings_impl;
18pub mod guided_tour_impl;
19pub mod layers;
20pub mod layers_impl;
21pub mod map_collaborator_impl;
22pub mod map_impl;
23pub mod plant_layer;
24pub mod plantings;
25pub mod plantings_impl;
26pub mod plants_impl;
27pub mod seed_impl;
28pub mod timeline;
29
30use chrono::NaiveDate;
31use chrono::NaiveDateTime;
32
33use diesel::AsChangeset;
34use diesel::QueryableByName;
35use diesel::{Identifiable, Insertable, Queryable};
36use postgis_diesel::types::Point;
37use postgis_diesel::types::Polygon;
38use uuid::Uuid;
39
40use crate::schema::{
41 application_settings, guided_tour_progress, guided_tour_states, map_collaborators, maps,
42 plants, seeds,
43};
44
45use super::r#enum::{
46 herbaceous_or_woody::HerbaceousOrWoody, life_cycle::LifeCycle,
47 light_requirement::LightRequirement, privacy_access_control::PrivacyAccessControl,
48 quality::Quality, quantity::Quantity, shade::Shade, soil_texture::SoilTextureEnum,
49 taxonomic_rank::TaxonomicRank, water_requirement::WaterRequirementEnum,
50};
51
52/// The `Plants` entity builds up an hierarchical structure, see `/doc/database/hierarchy.md`:
53///
54/// Use case for plant attributes is described in `/doc/usecases/assigned/plant_attributes.md`.
55///
56#[doc = include_str!("../../../doc/database/hierarchy.md")]
57///
58#[derive(Debug, Identifiable, Queryable, QueryableByName)]
59#[diesel(table_name = plants)]
60pub struct Plants {
61 /// *Used* at many places
62 /// - The internal id of the plant.
63 /// - *Database fill ratio:* 100.00%
64 pub id: i64,
65
66 /// *Used* at many places
67 /// - The unique name of the plant.
68 /// - The structure is described above (`doc/database/hierarchy.md`).
69 /// - *Database fill ratio:* 100.00%
70 /// - *Scraper fill ratio:* 100.00%
71 pub unique_name: String,
72
73 /// *Used* at many places
74 /// - The list of the common names of the plant in English.
75 /// - *Fetched from* `PracticalPlants` and Permapeople.
76 /// - *Database fill ratio:* 71.33%
77 /// - *Scraper fill ratio:* 71.33%
78 pub common_name_en: Option<Vec<Option<String>>>,
79
80 /// *Used* at many places
81 /// - The list of the common names of the plant in German.
82 /// - *Fetched from* Wikidata API if not present in any source datasets.
83 /// - *Database fill ratio:* 20.39%
84 /// - *Scraper fill ratio:* 20.39%
85 pub common_name_de: Option<Vec<Option<String>>>,
86
87 // /// - The edible use of the plant, answering: Which food type can be produced from this plant, e.g. oil?
88 // /// - Interesting for search functionality.
89 // /// - *Fetched from* Permapeople as `edible_uses` and merged with Reinsaat.
90 /// - *Not used*
91 /// - *Scraper fill ratio:* 5.12%
92 // pub edible_uses_en: Option<String>,
93
94 // /// - *Fetched from* PracticalPlants as `medicinal_uses` and merged with Permapeople.
95 /// - *Not used*
96 /// - *Scraper fill ratio:* 0.71%
97 //pub medicinal_uses: Option<String>,
98
99 // /// - Only for references.
100 // /// - *Fetched from* PracticalPlants)
101 /// - *Not used*
102 /// - *Scraper fill ratio:* 26.72%
103 // pub material_uses_and_functions: Option<String>,
104
105 // /// - Only for references.
106 // /// - *Fetched from* PracticalPlants)
107 /// - *Not used*
108 /// - *Scraper fill ratio:* 50.06%
109 // pub botanic: Option<String>,
110
111 // /// - Only informational.
112 // /// - *Fetched from* PracticalPlants
113 // /// - Plants are not only used for food but also for other uses, e.g. fiber to produce paper.
114 /// - *Not used*
115 /// - *Scraper fill ratio:* 0.57%
116 // pub material_uses: Option<String>,
117 //
118 /// - *Used* for search ranking (diversity) and to be displayed in plant attributes.
119 /// - ecological and environmental function of the plant, especially nitrogen fixer is relevant for `PermaplanT`.
120 /// - *Fetched from* `PracticalPlants`)
121 /// - *Database fill ratio:* 12.46%
122 /// - *Scraper fill ratio:* 12.46%
123 pub functions: Option<String>,
124
125 // /// - Use `hardiness_zone` instead.
126 // /// - indication of the heat range a plant endures.
127 // /// - *Fetched from* `PracticalPlants`.
128 /// - *Not used*
129 /// - *Scraper fill ratio:* 0.03%
130 // pub heat_zone: Option<i16>,
131 //
132 /// - Shade tolerance of the plant, to be used together with `light_requirement`.
133 /// - *Used* in shade layer.
134 /// - *For example* a plant that has "no shade", should get a warning if placed in a shade.
135 /// - No shade: full sun exposure
136 /// - Light shade: moderately shaded throughout the day
137 /// - Partial shade: about 3-6 hours of direct sunlight
138 /// - Permanent shade: less than 3 hours of direct sunlight
139 /// - Shade indicates the shade tolerance. Plants obviously grow better with better light conditions.
140 /// - Warnings should only show if a plant is moved into a too dark spot.
141 /// No warning should be shown when moved into a lighter spot.
142 /// - *Fetched from* `PracticalPlants`.
143 /// - *Database fill ratio:* 58.24%
144 /// - *Scraper fill ratio:* 58.24%
145 /// - *Error ratio:* 0.01%
146 pub shade: Option<Shade>,
147
148 // /// - Currently unused (maybe later used in pH layer).
149 // /// - *See* explanation in `/doc/architecture/context.md`
150 // /// - Soil PH can be tested by the user with simple means (e.g. litmus).
151 // /// - *Fetched from* `PracticalPlants` and Permapeople (merged between Permapeople and `PracticalPlants`).
152 /// - *Not used*
153 /// - *Scraper fill ratio:* 0.54%
154 // pub soil_ph: Option<Vec<Option<SoilPh>>>,
155 //
156 /// - *See* explanation in `/doc/architecture/context.md`
157 /// - *Used* in soil layer.
158 /// - *Fetched from* `PracticalPlants` and Permapeople (merged with `soil_type` of Permapeople).
159 /// - *Database fill ratio:* 77.75%
160 /// - *Scraper fill ratio:* 77.75%
161 /// - *Error ratio:* 0.00%
162 pub soil_texture: Option<Vec<Option<SoilTextureEnum>>>,
163
164 // /// - *NOT used* in hydrology layer
165 // /// as it has poor quality and no additional data compared to water_requirement
166 // /// - *Fetched from* PracticalPlants
167 // /// - wet = drowned, (often) flooded or in general very moist, e.g. swamp
168 // /// - moist = humid, can hold some water, e.g. flat bed with humus
169 // /// - well drained = dry, low capacity to hold water, e.g. sandhill.
170 /// - *Scraper fill ratio:* 29.81%
171 // pub soil_water_retention: Option<Vec<Option<SoilWaterRetention>>>,
172
173 // /// - Only informational.
174 // /// - *Fetched from* PracticalPlants
175 // /// - gives information about environmental conditions, such as drought or wind tolerance
176 /// - *Not used*
177 /// - *Scraper fill ratio:* 12.26%
178 //pub environmental_tolerances: Option<Vec<Option<String>>>,
179
180 // /// - *Fetched from* PracticalPlants
181 /// - *Not used*
182 /// - *Scraper fill ratio:* 0.18%
183 //pub native_geographical_range: Option<String>,
184
185 // /// - *Fetched from* `PracticalPlants`
186 /// - *Not used*
187 /// - *Scraper fill ratio:* 0.11%
188 //pub native_environment: Option<String>,
189
190 // /// - Interesting for search functionality.
191 // /// - *Fetched from* `PracticalPlants`
192 // /// - informs about the (vertical) layer, that the plant usually inhabits, e.g. soil surface or canopy
193 /// - *Not used*
194 /// - *Scraper fill ratio:* 12.69%
195 // pub ecosystem_niche: Option<String>,
196
197 // /// - Only informational.
198 // /// - deciduous = plants loose leaves in winter.
199 // /// - evergreen = Plants don't throw leaves (e.g. pine tree).
200 // /// - Not applicable for annual plants.
201 // /// - *Fetched from* `PracticalPlants` and merged with `leaves` of Permapeople.
202 /// - *Not used*
203 /// - *Scraper fill ratio:* 23.44%
204 // pub deciduous_or_evergreen: Option<DeciduousOrEvergreen>,
205
206 /// - *Used* Displayed in the plant attributes.
207 /// - Only informational.
208 /// - Fetched from `PracticalPlants`
209 /// - informs about the plant physiology
210 /// - woody = grows woody parts
211 /// - herbaceous = doesn't grow wood, shoots remain soft/green.
212 /// - *Database fill ratio:* 22.47%
213 /// - *Scraper fill ratio:* 22.47%
214 /// - *Error ratio:* 0.00%
215 pub herbaceous_or_woody: Option<HerbaceousOrWoody>,
216
217 /// - *Used* in search and attribute
218 /// - Determines life span of the plant.
219 /// - *Fetched from* `PracticalPlants` and Permapeople (merged with `life_cycle` of Permapeople).
220 /// - *Database fill ratio:* 61.72%
221 /// - *Scraper fill ratio:* 61.72%
222 /// - *Error ratio:* 0.00%
223 pub life_cycle: Option<Vec<Option<LifeCycle>>>,
224
225 // /// - Only informational.
226 // /// - *Fetched from* `PracticalPlants` and Permapeople (merged with `growth` of Permapeople).
227 /// - *Not used*
228 /// - *Scraper fill ratio:* 23.55%
229 // pub growth_rate: Option<Vec<Option<GrowthRate>>>,
230
231 /// - *Used only informational, is in rw attribute
232 /// - *Fetched from* `PracticalPlants` as `mature_size_height` and merged with Permapeople.
233 /// - informs about the maximum height that the plant gains in cm
234 /// - *Database fill ratio:* 71.89%
235 /// - *Scraper fill ratio:* 71.89%
236 pub height: Option<i32>,
237
238 // /// - Determines how large the plant can grow in diameter.
239 // /// - Other plants should get a warning if planted within this area.
240 // /// - *TODO:* replaced with spread, will keep this for now for information
241 // /// - *Fetched from* `PracticalPlants` as `mature_size_width` and merged with Permapeople.
242 /// - *Not used*
243 /// - *Scraper fill ratio:* 17.43%
244 //pub width: Option<String>,
245
246 // /// - Only informational.
247 // /// - *Fetched from* `PracticalPlants`
248 /// - *Not used*
249 /// - *Scraper fill ratio:* 14.32%
250 // pub fertility: Option<Vec<Option<Fertility>>>,
251
252 // /// - Only informational.
253 // /// - *Fetched from* PracticalPlants
254 /// - *Not used*
255 /// - *Scraper fill ratio:* 0.35%
256 //pub flower_colour: Option<String>,
257
258 // /// - Only informational.
259 // /// - *Fetched from* PracticalPlants
260 // /// - a plant can contain flowers of two different sexes, male or female (monoecious), a plant can contain only flowers of one specific sex and therefore needs at least another plant of the other sex to reproduce (dioecious) or can contain flowers that have both the sexes within the same flower (hermaphrodite).
261 /// - *Not used*
262 /// - *Scraper fill ratio:* 49.28%
263 /// - *Error ratio:* 0.00%
264 // pub flower_type: Option<FlowerType>,
265
266 /// - Is readonly in attribute
267 /// - The creation date of the entry (actual time).
268 /// - Only for administration.
269 /// - *Database fill ratio:* 100.00%
270 /// - *Scraper fill ratio:* 70.75%
271 /// - *Error ratio:* 0.00%
272 pub created_at: NaiveDateTime,
273
274 /// - Is readonly in attribute
275 /// - The last update date of the entry (actual time).
276 /// - Only for administration.
277 /// - *Database fill ratio:* 100.00%
278 /// - *Scraper fill ratio:* 70.75%
279 /// - *Error ratio:* 0.00%
280 pub updated_at: NaiveDateTime,
281
282 /// - *Used* so that an icon can be shown in the search results. Also displayed in the plant attributes.
283 /// - Will be used in watering layer.
284 /// - Fetched from `PracticalPlants` and merged with `has_drought_tolerance` of Permapeople.
285 /// - *Database fill ratio:* 53.25%
286 /// - *Scraper fill ratio:* 53.25%
287 /// - *Error ratio:* 0.00%
288 pub has_drought_tolerance: Option<bool>,
289
290 // /// - *Fetched from* `PracticalPlants`.
291 /// - *Not used*
292 /// - *Scraper fill ratio:* 7.46%
293 /// - *Error ratio:* 0.00%
294 // pub tolerates_wind: Option<bool>,
295
296 // /// - The list of the references of the plant.
297 // /// - `references` items link to these items.
298 // /// - Only informational.
299 /// - *Not used*
300 /// - *Scraper fill ratio:* 45.94%
301 // pub plant_references: Option<Vec<Option<String>>>,
302
303 // /// - Boolean value indicating whether the plant is a tree.
304 // /// - Plants with `is_tree == true` can be used in the tree layer.
305 // /// - In plants layer all plants can be used.
306 // /// - *Initial value* is to `True` if herbaceous_or_woody (woody) and life_cycle (perennial)
307 /// - *Not used*
308 /// - *Scraper fill ratio:* 0.08%
309 /// - *Error ratio:* 0.00%
310 // pub is_tree: Option<bool>,
311
312 // /// - Only informational.
313 // /// - *Initial value* is to `light feeder` if "Nutritionally poor soil" in `environmental_tolerances` is present.
314 /// - *Not used*
315 /// - *Scraper fill ratio:* 0.03%
316 /// - *Error ratio:* 0.00%
317 // pub nutrition_demand: Option<NutritionDemand>,
318
319 // /// - Number value between -1..6 (-1 should be printed as 00)
320 /// - *Not used*
321 // /// - *Fill ratio:* 0%
322 // pub preferable_permaculture_zone: Option<i16>,
323
324 // /// - When article was modified last time.
325 // /// - Only for administration.
326 // /// - Date value fetched from `PracticalPlants` page showing the last modification date of the plant.
327 /// - *Not used*
328 /// - *Scraper fill ratio:* 50.19%
329 /// - *Error ratio:* 0.00%
330 // pub article_last_modified_at: Option<NaiveDateTime>,
331
332 /// - *Used* To diplay an icon in the search results.
333 /// - USDA Hardiness Zone (without subranges).
334 /// - Important information.
335 /// - Fetched from `PracticalPlants` and Permapeople (merged with `usda_hardiness_zone` of Permapeople).
336 /// - *Database fill ratio:* 58.05%
337 /// - *Scraper fill ratio:* 58.05%
338 pub hardiness_zone: Option<String>,
339
340 /// - Shade tolerance of the plant, to be used together with shade.
341 /// - *Used* in shade layer.
342 /// - *For example* a plant that has "Full sun", should get a warning if placed in a shade.
343 /// - **Fetched from*** `PracticalPlants` and Permapeople (merged with `sun` of `PracticalPlants`)
344 /// - Full sun: full sun exposure
345 /// - Partial sun/shade: about 3-6 hours of direct sunlight or moderately shaded throughout the day
346 /// - Full shade: less than 3 hours of direct sunlight or almost no sunlight/no direct sunlight
347 /// - *Database fill ratio:* 77.90%
348 /// - *Scraper fill ratio:* 77.90%
349 /// - *Error ratio:* 0.00%
350 pub light_requirement: Option<Vec<Option<LightRequirement>>>,
351
352 /// - *Used* in hydrology layer.
353 /// - *Fetched from* `PracticalPlants` and Permapeople (merged with `water` of `PracticalPlants`).
354 /// - water = completely aquatic;
355 /// - wet = drowned, (often) flooded or in general very moist, e.g. swamp;
356 /// - moist = humid, regular water supply, e.g. flat bed with humus;
357 /// - well drained = dry, little water input.
358 /// - *Database fill ratio:* 77.87%
359 /// - *Scraper fill ratio:* 77.87%
360 /// - *Error ratio:* 0.00%
361 pub water_requirement: Option<Vec<Option<WaterRequirementEnum>>>,
362
363 // /// - Only informational.
364 // /// - *Fetched from* Permapeople (renamed from `propagation`)
365 // /// - How to reproduce a plant: cuttings = cut pieces of wood; layering = let low branches reach the soil to root; Seed - direct sow = sow directly the seeds; division = split the rhizomes (roots) into pieces; Spores = plant reproduces via spores (e.g. ferns, funghi); seed - transplant = raise indoors from seed and transplant to outdoors later
366 /// - *Not used*
367 /// - *Scraper fill ratio:* 0.73%
368 // pub propagation_method: Option<Vec<Option<PropagationMethod>>>,
369
370 // /// - Only informational.
371 // /// - May be used in search functionality (low priority).
372 // /// - *Fetched from* Permapeople.
373 /// - *Not used*
374 /// - *Scraper fill ratio:* 27.54%
375 // pub alternate_name: Option<String>,
376
377 // /// - Only informational.
378 // /// - *Fetched from* Permapeople.
379 /// - *Not used*
380 /// - *Scraper fill ratio:* 0.02%
381 //pub diseases: Option<String>,
382
383 /// - *Used* so that an icon can be shown in the search results. Also displayed in the plant attributes.
384 /// - Important information.
385 /// - *Fetched from* Permapeople.
386 /// - *Database fill ratio:* 54.96%
387 /// - *Scraper fill ratio:* 54.96%
388 /// - *Error ratio:* 0.00%
389 pub edible: Option<bool>,
390
391 /// - Only informational.
392 /// - *Used* Displayed in the plant attributes.
393 /// - *Fetched from* Permapeople.
394 /// - which organ of the plant can be eaten, e.g. root, leaves.
395 /// - *Database fill ratio:* 56.54%
396 /// - *Scraper fill ratio:* 56.54%
397 pub edible_parts: Option<Vec<Option<String>>>,
398
399 // /// - Only informational.
400 // /// - *Fetched from* Permapeople.
401 // /// - Reinsaat: `Keimtemperatur` should be copied to `germination_temperature`
402 // /// - Germination means that all conditions are right for a seed to start growing. Temperature is one essential factor.
403 /// - *Not used*
404 /// - *Scraper fill ratio:* 1.60%
405 //pub germination_temperature: Option<String>,
406
407 // /// - *Fetched from* Permapeople.
408 /// - *Not used*
409 /// - *Scraper fill ratio:* 29.11%
410 //pub introduced_into: Option<String>,
411
412 // /// - Only informational.
413 // /// - *Fetched from* Permapeople as \`layer\` and renamed.
414 // /// - Habitus describes the shape of a plant.
415 /// - *Not used*
416 /// - *Scraper fill ratio:* 37.92%
417 //pub habitus: Option<String>,
418
419 // /// - *Fetched from* Permapeople.
420 /// - *Not used*
421 /// - *Scraper fill ratio:* 0.07%
422 //pub medicinal_parts: Option<String>,
423
424 // /// - Only informational.
425 // /// - *Fetched from* Permapeople.
426 /// - *Not used*
427 /// - *Scraper fill ratio:* 63.80%
428 //pub native_to: Option<String>,
429
430 // /// - *Fetched from* Permapeople.
431 /// - *Not used*
432 /// - *Scraper fill ratio:* 68.32%
433 //pub plants_for_a_future: Option<String>,
434
435 // /// - *Fetched from* Permapeople.
436 /// - *Not used*
437 /// - *Scraper fill ratio:* 64.98%
438 //pub plants_of_the_world_online_link: Option<String>,
439
440 // /// - *Fetched from* Permapeople.
441 /// - *Not used*
442 /// - *Scraper fill ratio:* 11.43%
443 //pub plants_of_the_world_online_link_synonym: Option<String>,
444
445 // /// - Only informational.
446 // /// - *Fetched from* PracticalPlants as `pollinators` and merged with `pollination` of Permapeople.
447 // /// - Pollination is the process that the pollen (male part) gets united with the pistil (female part), e.g. via bees, wind.
448 /// - *Not used*
449 /// - *Scraper fill ratio:* 38.02%
450 //pub pollination: Option<String>,
451
452 // /// - Only informational.
453 // /// - *Fetched from* Permapeople.
454 /// - *Not used*
455 /// - *Scraper fill ratio:* 0.11%
456 //pub propagation_transplanting_en: Option<String>,
457
458 // /// - Nearly empty.
459 // /// - *Fetched from* Permapeople.
460 /// - *Not used*
461 /// - *Scraper fill ratio:* 0.01%
462 //pub resistance: Option<String>,
463
464 // /// - Only informational.
465 // /// - *Fetched from* Permapeople.
466 // /// - Root type describes the shape of the roots.
467 /// - *Not used*
468 /// - *Scraper fill ratio:* 0.19%
469 //pub root_type: Option<String>,
470
471 // /// - Only informational.
472 // /// - *Fetched from* Permapeople as `seed_planting_depth` and renamed.
473 // /// - Reinsaat: `Sowing depth` should be copied to `seed_planting_depth_en`
474 // /// - When sowing each plant has a specific value how deep the seeds should be covered with soil.
475 /// - *Not used*
476 /// - *Scraper fill ratio:* 0.06%
477 //pub seed_planting_depth_en: Option<String>,
478
479 // /// - Only informational.
480 // /// - *Fetched from* Permapeople.
481 // /// - expected average life span (in years) of a seed of a certain specie.
482 /// - *Not used*
483 /// - *Scraper fill ratio:* 0.51%
484 //pub seed_viability: Option<String>,
485
486 // /// - The final part of the URL of the plant on the Permapeople website.
487 // /// - This field can be potentially used to construct the `external_url` field traversing through all the parents given by `parent_id`.
488 // /// - *Fetched from* Permapeople.
489 /// - *Not used*
490 /// - *Scraper fill ratio:* 70.75%
491 //pub slug: Option<String>,
492
493 /// - **Used**
494 /// - How far a plant spreads (The 'width' of a plant) in cm
495 /// - *Fetched from* Permapeople.
496 /// - *Database fill ratio:* 78.33%
497 /// - *Scraper fill ratio:* 78.33%
498 pub spread: Option<i32>,
499
500 // /// - *Fetched from* Permapeople.
501 /// - *Not used*
502 /// - *Scraper fill ratio:* 1.69%
503 //pub utility: Option<String>,
504
505 /// - *Used* so that an icon can be shown in the search results. Also displayed in the plant attributes.
506 /// - Important information.
507 /// - *Fetched from* Permapeople.
508 /// - specific warnings for eather human, animal or environmental well-being, e.g. toxic, invasive.
509 /// - *Database fill ratio:* 8.69%
510 /// - *Scraper fill ratio:* 8.69%
511 pub warning: Option<String>,
512
513 // /// - *Fetched from* Permapeople.
514 /// - *Not used*
515 /// - *Scraper fill ratio:* 0.05%
516 //pub when_to_plant_cuttings_en: Option<String>,
517
518 // /// - *Fetched from* Permapeople.
519 /// - *Not used*
520 /// - *Scraper fill ratio:* 0.06%
521 //pub when_to_plant_division_en: Option<String>,
522
523 // /// - *Fetched from* Permapeople.
524 /// - *Not used*
525 /// - *Scraper fill ratio:* 0.15%
526 //pub when_to_plant_transplant_en: Option<String>,
527
528 // /// - Only informational.
529 // /// - *Fetched from* Permapeople.
530 /// - *Not used*
531 /// - *Scraper fill ratio:* 0.18%
532 //pub when_to_sow_indoors_en: Option<String>,
533
534 // /// - Only informational.
535 // /// - *Fetched from* Permapeople as `when_to_sow_outdoors` and renamed.
536 // /// - Reinsaat: `Sowing` or `Direct Sowing` or `Sowing outdoors` or `Sowing Direct Outdoors` should be copied to `sowing_outdoors_en`
537 /// - *Not used*
538 /// - *Scraper fill ratio:* 0.27%
539 //pub sowing_outdoors_en: Option<String>,
540
541 // /// - Only informational.
542 // /// - *Fetched from* Permapeople.
543 /// - *Not used*
544 /// - *Scraper fill ratio:* 0.44%
545 //pub when_to_start_indoors_weeks: Option<String>,
546
547 // /// - Only informational.
548 // /// - *Fetched from* Permapeople.
549 /// - *Not used*
550 /// - *Scraper fill ratio:* 0.09%
551 //pub when_to_start_outdoors_weeks: Option<String>,
552
553 // /// - Only informational.
554 // /// - *Fetched from* Permapeople.
555 // /// - Stratification is the process that a seed must go through to get triggered for germination, e.g. by a certain threshold of minus degrees.
556 /// - *Not used*
557 /// - *Scraper fill ratio:* 0.02%
558 //pub cold_stratification_temperature: Option<String>,
559
560 // /// - Only informational.
561 // /// - *Fetched from* Permapeople.
562 // /// - Suggested change
563 // /// - *Fetched from* Permapeople.
564 // /// - Stratification is the process that a seed must go through to get triggered for germination, e.g. by a certain amount of time under cold temperatures.
565 /// - *Not used*
566 /// - *Scraper fill ratio:* 0.04%
567 //pub cold_stratification_time: Option<String>,
568
569 // /// - Only informational.
570 // /// - *Fetched from* Permapeople.
571 // /// - Reinsaat: `1st harvest` should be copied to `days_to_harvest`
572 /// - *Not used*
573 /// - *Scraper fill ratio:* 0.73%
574 //pub days_to_harvest: Option<String>,
575
576 // /// - Needed for occupied space and in attributes
577 // /// - *TODO:* should be number and then be used for calender
578 //pub life_cycle_days: Option<int>,
579
580 // /// - *Fetched from* Permapeople.
581 /// - *Not used*
582 /// - *Scraper fill ratio:* 0.15%
583 //pub habitat: Option<String>,
584
585 // /// - One number means it is spacing between plants and rows. Two numbers means first is spacing between plants, second between rows.
586 // /// - Only informational.
587 // /// - *Fetched from* Permapeople as `spacing` and from Reinsaat as `Distances` and renamed.
588 // /// - Reinsaat: `Distances` or `Spacing` should be copied to `spacing_en`
589 /// - *Not used*
590 /// - *Scraper fill ratio:* 0.53%
591 //pub spacing_en: Option<String>,
592
593 // /// - *Fetched from* Permapeople as `wikipedia` and renamed.
594 /// - *Not used*
595 /// - *Scraper fill ratio:* 37.11%
596 //pub wikipedia_url: Option<String>,
597
598 // /// - Only informational.
599 // /// - *Fetched from* Permapeople.
600 /// - *Not used*
601 /// - *Scraper fill ratio:* 0.20%
602 //pub days_to_maturity: Option<String>,
603
604 // /// - Nearly empty.
605 // /// - *Fetched from* Permapeople.
606 /// - *Not used*
607 /// - *Scraper fill ratio:* 0.02%
608 //pub pests: Option<String>,
609
610 /// - Only for administration.
611 /// - The version of the entry.
612 /// - To be incremented after every relevant change.
613 /// - *Fetched from* Permapeople.
614 /// - *Database fill ratio:* 70.75%
615 /// - *Scraper fill ratio:* 70.75%
616 pub version: Option<i16>,
617
618 // /// - Only informational.
619 // /// - *Fetched from* Permapeople.
620 // /// - Germination time describes the time (days, weeks, months) that a seed needs to germinate given the right conditions.
621 /// - *Not used*
622 /// - *Scraper fill ratio:* 0.41%
623 //pub germination_time: Option<String>,
624
625 // /// - The description of the entry.
626 // /// - *Fetched from* Permapeople.
627 /// - *Not used*
628 /// - *Scraper fill ratio:* 3.73%
629 //pub description: Option<String>,
630
631 // /// - TODO: (not yet in database) add to attributes
632 // /// - Short important information to shown.
633 //pub info: Option<String>,
634
635 // /// - *Fetched from* permapeople id of the parent entry pointing to the `external_id` column.
636 /// - *Not used*
637 /// - *Scraper fill ratio:* 1.54%
638 //pub parent_id: Option<String>,
639
640 // /// - Enum value indicating the source of the entry.
641 /// - *Not used*
642 /// - *Scraper fill ratio:* 79.14%
643 // pub external_source: Option<ExternalSource>,
644
645 // /// - The external id of the entry used in combination with the `external_source` column.
646 /// - *Not used*
647 /// - *Scraper fill ratio:* 70.75%
648 //pub external_id: Option<String>,
649
650 // /// - The external URL provided by the origin source.
651 /// - *Not used*
652 /// - *Scraper fill ratio:* 7.55%
653 //pub external_url: Option<String>,
654
655 // /// - Only informational.
656 // /// - *Fetched from* PracticalPlants as `root_zone_tendency` and merged with root_depth of Permapeople.
657 // /// - Root depth can be considered when planning polycultures, e.g. combining shallow roots with deep roots.
658 /// - *Not used*
659 /// - *Scraper fill ratio:* 0.14%
660 //pub root_depth: Option<String>,
661
662 // /// - The article number `Artikelnummer` of the plant in the Reinsaat database.
663 /// - *Not used*
664 /// - *Scraper fill ratio:* 6.05%
665 //pub external_article_number: Option<String>,
666
667 // /// - `Portionsinhalt` should be called `external_portion_content`
668 // /// - *Fetched from* Reinsaat.
669 /// - *Not used*
670 /// - *Scraper fill ratio:* 5.67%
671 //pub external_portion_content: Option<String>,
672
673 // /// - Only informational.
674 // /// - *Fetched from* Reinsaat as \`Direktsaat\` and renamed.
675 // /// - `Direktsaat` or `Aussaat` should be called `sowing_outdoors_de`
676 /// - *Not used*
677 /// - *Scraper fill ratio:* 0.82%
678 //pub sowing_outdoors_de: Option<String>,
679
680 /// - *Used* Displayed in the plant attributes.
681 /// - String array of numbers representing a time period.
682 /// - The year is divided into 24 periods of half a month each.
683 /// - *For example* "\[8,9,10\]" means from the 2nd half of April to the 2nd half of May incl.
684 /// - *Fetched from* Reinsaat
685 /// - `Aussaat/ Pflanzung Freiland` should be called `sowing_outdoors`
686 /// - *Database fill ratio:* 5.63%
687 /// - *Scraper fill ratio:* 5.63%
688 pub sowing_outdoors: Option<Vec<Option<i16>>>,
689
690 /// - *Used* Displayed in the plant attributes.
691 /// - String array of numbers representing a time period.
692 /// - The year is divided into 24 periods of half a month each.
693 /// - *For example* "\[8,9,10\]" means from the 2nd half of April to the 2nd half of May incl.
694 /// - `Ernte` should be called `harvest_time`
695 /// - *Fetched from* Reinsaat
696 /// - *Database fill ratio:* 4.97%
697 /// - *Scraper fill ratio:* 4.97%
698 pub harvest_time: Option<Vec<Option<i16>>>,
699
700 /*
701 /// - Only informational.
702 /// - *Fetched from* Reinsaat.
703 /// - `Abstände` should be called `spacing_de`
704 /// - *Not used*
705 /// - *Scraper fill ratio:* 2.37%
706 //pub spacing_de: Option<String>,
707
708 /// - Only informational.
709 /// - *Fetched from* Reinsaat.
710 /// - *Not used*
711 /// - `Saatgutbedarf` should be called `required_quantity_of_seeds_de`
712 /// - *Scraper fill ratio:* 1.29%
713 //pub required_quantity_of_seeds_de: Option<String>,
714
715 /// - Only informational.
716 /// - *Fetched from* Reinsaat.
717 /// - `Required quantity of seeds` should be called `required_quantity_of_seeds_en`
718 /// - *Not used*
719 /// - *Scraper fill ratio:* 2.76%
720 //pub required_quantity_of_seeds_en: Option<String>,
721
722 /// - Only informational.
723 /// - *Fetched from* Reinsaat.
724 /// - `Saattiefe` should be called `seed_planting_depth_de`
725 /// - When sowing, each plant has a specific value how deep the seeds should be covered with soil.
726 /// - *Not used*
727 /// - *Scraper fill ratio:* 2.22%
728 //pub seed_planting_depth_de: Option<String>,
729
730 /// - German version of thousand grain weight (German: Tausendkornmasse)
731 /// - Only informational.
732 /// - *Fetched from* Reinsaat.
733 /// - Called `Tausendkornmasse` in Reinsaat
734 /// - *Not used*
735 /// - *Scraper fill ratio:* 2.12%
736 //pub seed_weight_1000_de: Option<String>,
737
738 /// - English version of thousand grain weight (German: Tausendkornmasse)
739 /// - Only informational.
740 /// - *Fetched from* Reinsaat.
741 /// - Called `Thousand seeds mass` in Reinsaat
742 /// - *Not used*
743 /// - *Scraper fill ratio:* 2.17%
744 //pub seed_weight_1000_en: Option<String>,
745
746 /// - Number for thousand grain weight (German: Tausendkornmasse)
747 /// - used in `doc/usecases/buy_seeds.md` to calculate seed weight based on number of plants.
748 /// - *Fetched from* Permapeople as `1000_seed_weight_g` and renamed.
749 /// - *TODO:* merge with data from reinsaat: `Tausendkorngewicht (TKG)` should be copied to `seed_weight` (remove ` g`)
750 /// - *Not used*
751 /// - *Scraper fill ratio:* 2.89%
752 /// - *Error ratio:* 0.00%
753 // pub seed_weight_1000: Option<f64>,
754
755 /// - Only informational.
756 /// - *Fetched from* Reinsaat.
757 /// - `Suitable for professional cultivation` should be called `machine_cultivation_possible`
758 /// - *Not used*
759 /// - *Scraper fill ratio:* 7.55%
760 /// - *Error ratio:* 0.00%
761 //pub machine_cultivation_possible: Option<bool>,
762
763 /// - *Fetched from* Reinsaat.
764 /// - could be used for plant search and informational.
765 /// - `subcategory` from Reinsaat should be copied to `edible_uses_de` and `edible_uses_en` respectively (DE and EN version)
766 /// - *Not used*
767 /// - *Scraper fill ratio:* 5.10%
768 //pub edible_uses_de: Option<String>,
769 */
770 /// - Hierarchy fields
771 /// - Either *Fetched from* `PracticalPlants` and Permapeople
772 /// - Or determined from the unique name
773 /// - Or set by scraper overrides
774 /// - *Database fill ratio:* 100.00%
775 /// - *Scraper fill ratio:* 100.00%
776 /// - *Error ratio:* 0.00%
777 pub rank: TaxonomicRank,
778 pub family: Option<i64>,
779 pub genus: Option<i64>,
780 pub species: Option<i64>,
781 pub variety: Option<i64>,
782
783 /// - The path to the icon of the plant.
784 /// - *Database fill ratio:* 2.13%
785 /// - *Scraper fill ratio:* 2.13%
786 pub icon_path: Option<String>,
787}
788
789/// The `PlantsAndFamily` entity used for a self join.
790#[derive(Queryable)]
791pub struct PlantsAndFamily {
792 /// The plants entity
793 pub plant: Plants,
794 /// The plants family name
795 pub family_name: Option<String>,
796}
797/// The `Seed` entity.
798#[derive(Identifiable, Queryable)]
799#[diesel(table_name = seeds)]
800pub struct Seed {
801 /// The record id of the seed.
802 pub id: i64,
803 /// An additional name for the seed.
804 pub name: String,
805 /// When the seeds were harvested.
806 pub harvest_year: i16,
807 /// When the seeds should be used by.
808 pub use_by: Option<NaiveDate>,
809 /// Where the seeds came from.
810 pub origin: Option<String>,
811 /// What the seeds taste like.
812 pub taste: Option<String>,
813 /// The yield of the seeds.
814 pub yield_: Option<String>,
815 /// How many seeds there are.
816 pub quantity: Quantity,
817 /// The quality of the seeds.
818 pub quality: Option<Quality>,
819 /// How much the seeds cost.
820 pub price: Option<i16>,
821 /// How many generations the seeds have been grown.
822 pub generation: Option<i16>,
823 /// Notes about the seeds.
824 pub notes: Option<String>,
825 /// The id of the plant this seed belongs to.
826 pub plant_id: i64,
827 /// The id of the creator of the seed.
828 pub created_by: Uuid,
829 /// Timestamp indicating when the seed was archived.
830 /// Empty if the seed was not archived.
831 pub archived_at: Option<NaiveDateTime>,
832}
833
834/// The `NewSeed` entity.
835#[allow(clippy::missing_docs_in_private_items)] // TODO: See #97.
836#[derive(Insertable)]
837#[diesel(table_name = seeds)]
838pub struct NewSeed {
839 pub name: String,
840 pub plant_id: i64,
841 pub harvest_year: i16,
842 pub use_by: Option<NaiveDate>,
843 pub origin: Option<String>,
844 pub taste: Option<String>,
845 pub yield_: Option<String>,
846 pub quantity: Quantity,
847 pub quality: Option<Quality>,
848 pub price: Option<i16>,
849 pub generation: Option<i16>,
850 pub notes: Option<String>,
851 pub created_by: Uuid,
852}
853
854/// The `Map` entity.
855#[derive(Identifiable, Queryable)]
856#[diesel(table_name = maps)]
857pub struct Map {
858 /// The id of the map.
859 pub id: i64,
860 /// The name of the map.
861 pub name: String,
862 /// The date the map is supposed to be deleted.
863 pub deletion_date: Option<NaiveDate>,
864 /// The date the last time the map view was opened by any user.
865 pub last_visit: Option<NaiveDate>,
866 /// A flag indicating if this map is marked for deletion.
867 pub is_inactive: bool,
868 /// The zoom factor of the map.
869 pub zoom_factor: i16,
870 /// An enum indicating if this map is private or not.
871 pub privacy: PrivacyAccessControl,
872 /// The description of the map.
873 pub description: Option<String>,
874 /// The location of the map as a latitude/longitude point.
875 pub location: Option<Point>,
876 /// The id of the creator of the map.
877 pub created_by: Uuid,
878 /// The geometry of the map.
879 pub geometry: Polygon<Point>,
880 /// When the map was created.
881 pub created_at: NaiveDateTime,
882 /// When a map was last modified, e.g., by modifying plantings.
883 pub modified_at: NaiveDateTime,
884 /// By whom the map was last modified.
885 pub modified_by: Uuid,
886}
887
888/// The `NewMap` entity.
889#[derive(Insertable)]
890#[diesel(table_name = maps)]
891pub struct NewMap {
892 /// The name of the map.
893 pub name: String,
894 /// For a new map the same as `created_by`.
895 pub deletion_date: Option<NaiveDate>,
896 /// The date the last time the map view was opened by any user.
897 pub last_visit: Option<NaiveDate>,
898 /// A flag indicating if this map is marked for deletion.
899 pub is_inactive: bool,
900 /// The zoom factor of the map.
901 pub zoom_factor: i16,
902 /// An enum indicating if this map is private or not.
903 pub privacy: PrivacyAccessControl,
904 /// The description of the map.
905 pub description: Option<String>,
906 /// The location of the map as a latitude/longitude point.
907 pub location: Option<Point>,
908 /// The id of the creator of the map.
909 pub created_by: Uuid,
910 /// The geometry of the map.
911 pub geometry: Polygon<Point>,
912 /// The user who last modified the planting.
913 pub modified_by: Uuid,
914}
915
916/// The `UpdateMap` entity.
917#[derive(AsChangeset)]
918#[diesel(table_name = maps)]
919pub struct UpdateMap {
920 /// The name of the map.
921 pub name: Option<String>,
922 /// An enum indicating if this map is private or not.
923 pub privacy: Option<PrivacyAccessControl>,
924 /// The description of the map.
925 pub description: Option<String>,
926 /// The location of the map as a latitude/longitude point.
927 pub location: Option<Point>,
928}
929
930/// The `UpdateMapGeometry` entity.
931#[derive(AsChangeset)]
932#[diesel(table_name = maps)]
933pub struct UpdateMapGeometry {
934 /// New Map Bounds
935 pub geometry: Polygon<Point>,
936}
937
938/// The `GuidedTourProgress` entity.
939#[derive(Identifiable, Queryable)]
940#[diesel(primary_key(user_id, step_key), table_name = guided_tour_progress)]
941pub struct GuidedTourProgress {
942 /// ID of the user who completed the tour step
943 pub user_id: Uuid,
944 /// Human readable id of the step the user completed
945 pub step_key: String,
946 /// Time of completion
947 pub completed_at: NaiveDateTime,
948}
949
950/// Insertable for `guided_tour_progress` (`completed_at` uses DB default).
951#[derive(Insertable)]
952#[diesel(table_name = guided_tour_progress)]
953pub struct NewGuidedTourProgress {
954 /// ID of the user who is completing the step
955 pub user_id: Uuid,
956 /// Human readable id of the step the user is completing
957 pub step_key: String,
958}
959
960/// The `GuidedTourState` entity.
961#[derive(Insertable, Identifiable, Queryable)]
962#[diesel(primary_key(user_id), table_name = guided_tour_states)]
963pub struct GuidedTourState {
964 /// ID of the user
965 pub user_id: Uuid,
966 /// When the tour was paused
967 pub paused_at: Option<NaiveDateTime>,
968 /// How often the user has paused the tour already
969 pub pause_count: i32,
970}
971
972/// The `ApplicationSetting` entity.
973#[derive(Identifiable, Queryable)]
974#[diesel(primary_key(id), table_name = application_settings)]
975pub struct ApplicationSetting {
976 /// The id of the setting
977 pub id: i32,
978 /// The unique key of the setting
979 pub key: String,
980 /// The value of the setting
981 pub value: String,
982}
983
984/// The [`MapCollaborator`] entity.
985#[derive(Insertable, Identifiable, Queryable)]
986#[diesel(primary_key(map_id, user_id), table_name = map_collaborators)]
987pub struct MapCollaborator {
988 pub map_id: i64,
989 pub user_id: Uuid,
990 pub created_at: NaiveDateTime,
991}