From 8f54a6609f3f2f1f903557ddf813e0e8aaee51bf Mon Sep 17 00:00:00 2001 From: Mike Christensen Date: Thu, 27 Aug 2026 17:17:55 -0700 Subject: [PATCH] Standardize shopping ingredients table naming --- README.md | 13 +++++++++++ src/Core/NLP/IngredientNode.cs | 4 ++-- src/DB/DatabaseExporter.cs | 2 +- src/DB/DatabaseImporter.cs | 2 +- src/DB/Models/Ingredients.cs | 4 ++-- src/DB/Models/NlpDefaultPairings.cs | 6 ++--- src/UnitTests/DatabaseMappings.cs | 33 +++++++++++++++++++++++++++ src/UnitTests/TestIngredientLoader.cs | 2 +- src/UnitTests/UnitTests.csproj | 2 ++ 9 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 src/UnitTests/DatabaseMappings.cs diff --git a/README.md b/README.md index a86966e..3c51593 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,19 @@ dotnet test src/UnitTests/UnitTests.csproj --configuration Release --no-build -- The build includes `KitchenPC.Core`, `KitchenPC.DB`, and the unit tests. +Database Schema Naming +==== + +The PostgreSQL persistence adapter uses `shoppingingredients` as the physical table name for the +ingredient catalog. This legacy name is retained for compatibility with the KitchenPC website. +Public domain types and provisioning data continue to use the simpler `Ingredient` and +`Ingredients` terminology; those names describe application data rather than database tables. + +`DBContext.InitializeStore()` recreates the KitchenPC schema and deletes existing KitchenPC data. +Use it only with a new database or when replacing all existing data is intentional. See the +[KitchenPC Samples repository](https://github.com/KitchenPC/Samples) for a PostgreSQL initializer +and a small sample dataset. + Packages and Releases ==== diff --git a/src/Core/NLP/IngredientNode.cs b/src/Core/NLP/IngredientNode.cs index 1e41563..a736f41 100644 --- a/src/Core/NLP/IngredientNode.cs +++ b/src/Core/NLP/IngredientNode.cs @@ -31,12 +31,12 @@ public IngredientNode Parent public UnitType ConversionType { get { return (parent == null) ? convtype : parent.convtype; } - } //Default conversion type for this ingredient (from ShoppingIngredients) + } //Default conversion type for this ingredient (from the shoppingingredients table) public Weight UnitWeight { get { return (parent == null) ? unitweight : parent.unitweight; } - } //How much a single unit weighs (from ShoppingIngredients) + } //How much a single unit weighs (from the shoppingingredients table) public IngredientNode( Guid id, diff --git a/src/DB/DatabaseExporter.cs b/src/DB/DatabaseExporter.cs index 7cee784..d0f1d23 100644 --- a/src/DB/DatabaseExporter.cs +++ b/src/DB/DatabaseExporter.cs @@ -101,7 +101,7 @@ public Ingredients[] Ingredients() }) .ToArray(); - logger.DebugFormat("Read {0} row(s) from Ingredients.", list.Count()); + logger.DebugFormat("Read {0} row(s) from shoppingingredients.", list.Count()); return list; } diff --git a/src/DB/DatabaseImporter.cs b/src/DB/DatabaseImporter.cs index 03b3740..1c4f73e 100644 --- a/src/DB/DatabaseImporter.cs +++ b/src/DB/DatabaseImporter.cs @@ -39,7 +39,7 @@ public void Import(IEnumerable data) session.Save(dbRow, row.IngredientId); } - logger.DebugFormat("Created {0} row(s) in Ingredients", d.Count()); + logger.DebugFormat("Created {0} row(s) in shoppingingredients", d.Count()); transaction.Commit(); session.Flush(); } diff --git a/src/DB/Models/Ingredients.cs b/src/DB/Models/Ingredients.cs index 188dcdd..b16dfca 100644 --- a/src/DB/Models/Ingredients.cs +++ b/src/DB/Models/Ingredients.cs @@ -39,7 +39,7 @@ public class IngredientsMap : ClassMap { public IngredientsMap() { - Table("ShoppingIngredients"); + Table("shoppingingredients"); Id(x => x.IngredientId).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty); @@ -53,7 +53,7 @@ public IngredientsMap() .Not.Nullable() .Length(200) .Unique() - .Index("IDX_Ingredients_DisplayName"); + .Index("idx_shoppingingredients_displayname"); Map(x => x.UsdaDesc).Length(200); HasMany(x => x.Forms).KeyColumn("IngredientId"); diff --git a/src/DB/Models/NlpDefaultPairings.cs b/src/DB/Models/NlpDefaultPairings.cs index 09d6784..8aa1be6 100644 --- a/src/DB/Models/NlpDefaultPairings.cs +++ b/src/DB/Models/NlpDefaultPairings.cs @@ -14,11 +14,11 @@ public class NlpDefaultPairings public class NlpDefaultPairingsMap : ClassMap { - // TODO: KitchenPC doesn't have this data in a normalized manner, so we use the shoppingingredientsfornlp view to create it on the fly - // Website could create a new adapter that can load this view, or the base adapter can be configurable so we can map to a certain view and columns + // This table stores the default weight, volume, and unit forms used by ingredient parsing. + // The original KitchenPC website populated the same shape through a database view. public NlpDefaultPairingsMap() { - Table("shoppingingredientsfornlp"); // TODO: Make this configurable and less KitchenPC database specific + Table("shoppingingredientsfornlp"); Id(x => x.DefaultPairingId, "DefaultPairingId") .GeneratedBy.GuidComb() .UnsavedValue(Guid.Empty); diff --git a/src/UnitTests/DatabaseMappings.cs b/src/UnitTests/DatabaseMappings.cs new file mode 100644 index 0000000..9f2431d --- /dev/null +++ b/src/UnitTests/DatabaseMappings.cs @@ -0,0 +1,33 @@ +using System.Linq; +using FluentNHibernate.Cfg; +using KitchenPC.DB.Models; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace KitchenPC.UnitTests; + +[TestClass] +public class DatabaseMappings +{ + [TestMethod] + public void IngredientTablesUseCanonicalNames() + { + var configuration = Fluently + .Configure() + .Mappings(mappings => + mappings.FluentMappings.Add().Add() + ) + .BuildConfiguration(); + + var ingredientTable = configuration.GetClassMapping(typeof(Ingredients)).Table.Name; + var defaultPairingsTable = configuration + .GetClassMapping(typeof(NlpDefaultPairings)) + .Table.Name; + + Assert.AreEqual("shoppingingredients", ingredientTable); + Assert.AreEqual("shoppingingredientsfornlp", defaultPairingsTable); + Assert.IsFalse( + configuration.ClassMappings.Any(mapping => mapping.Table.Name == "ingredients"), + "No persistence model should map to the legacy ingredients table." + ); + } +} diff --git a/src/UnitTests/TestIngredientLoader.cs b/src/UnitTests/TestIngredientLoader.cs index 3a53939..e49e1ab 100644 --- a/src/UnitTests/TestIngredientLoader.cs +++ b/src/UnitTests/TestIngredientLoader.cs @@ -93,7 +93,7 @@ public IEnumerable LoadSynonyms() ); //Add in some test ingredients, but this will eventually come from a massive Synonyms database - //DB will first load ShoppingIngredients and create root nodes for all of those, with default form data, then will load IngredientSynonyms for all aliases + //DB will first load shoppingingredients and create root nodes for all of those, with default form data, then will load IngredientSynonyms for all aliases //TODO: Maybe there is a way to have ingredient nodes contain a singular and plural description so we don't need aliases for all the singulars IngredientNode[] ings = { diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index ccd0263..450c4ef 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -11,6 +11,7 @@ + @@ -18,6 +19,7 @@ +