Preparing search index...

    RecipeDatabase - Singleton class for managing recipe data storage and operations

    This class provides a comprehensive interface for managing recipes, ingredients, tags, and shopping lists using SQLite database. It implements the singleton pattern to ensure a single database instance throughout the application lifecycle.

    Key Features:

    • Recipe CRUD operations with ingredient and tag relationships
    • Fuzzy search capabilities using FuzzySearch utility
    • Shopping list generation from recipes
    • Quantity scaling for different serving sizes
    • Similar recipe detection
    • Local caching for improved performance
    const db = RecipeDatabase.getInstance();
    await db.init();

    const recipe = await db.addRecipe({
    title: "Chocolate Cake",
    ingredients: [...],
    tags: [...]
    });
    Index

    Constructors

    Properties

    Methods

    getInstance scaleRecipeToPersons closeAndReset init isDatabaseEmpty addIngredient addTag addMultipleIngredients addMultipleTags addRecipe addMultipleRecipes editRecipe editIngredient editTag searchRandomlyTags getRandomIngredientsByType getRandomTags deleteRecipe deleteIngredient deleteTag get_recipes isRecipeExist get_ingredients get_tags add_recipes add_ingredient add_tags remove_recipe remove_ingredient remove_tag update_recipe update_multiple_recipes update_ingredient update_tag find_recipe find_ingredient find_tag get_menu isRecipeInMenu addRecipeToMenu toggleMenuItemCooked removeFromMenu clearMenu get_purchasedIngredients setPurchased clearPurchasedIngredients scaleAndUpdateRecipe findSimilarRecipes findSimilarTags findSimilarIngredients findSimilarIngredientsBatch findSimilarTagsBatch getImportedSourceUrls getSeenUrls markUrlsAsSeen removeFromSeenHistory getAllPurchasedIngredients encodePurchasedIngredient reset constructUpdateRecipeStructure constructUpdateIngredientStructure constructUpdateTagStructure openDatabase deleteDatabase verifyTagsExist verifyIngredientsExist constructSearchRecipeStructure constructSearchIngredientStructure constructSearchTagStructure encodeRecipe prepareRecipeImage decodeRecipe decodeArrayOfRecipe encodeIngredient decodeIngredientFromRecipe encodeIngredientForDb encodeTagForDb decodeIngredient decodeArrayOfIngredients decodeSeason encodeTagForRecipe decodeTagFromRecipe decodeTag decodeArrayOfTags encodeNutrition decodeNutrition decodePreparation getAllRecipes getAllTags getAllIngredients getAllMenu encodeMenu decodeMenu decodeArrayOfMenu areIngredientsSimilar migrateAddSourceColumns migrateWildcardSeasons getAllImportHistory decodeImportHistory encodeImportHistory

    Constructors

    Properties

    "#instance": RecipeDatabase
    _databaseName: string
    _dbConnection: SQLiteDatabase
    _recipesTable: TableManipulation
    _ingredientsTable: TableManipulation
    _tagsTable: TableManipulation
    _importHistoryTable: TableManipulation
    _menuTable: TableManipulation
    _purchasedIngredientsTable: TableManipulation
    _recipes: recipeTableElement[]
    _ingredients: ingredientTableElement[]
    _importHistory: importHistoryTableElement[]
    _purchasedIngredients: Map<string, boolean>

    Methods

    • Scales a recipe's ingredient quantities to a different number of persons

      Creates a new recipe object with ingredient quantities adjusted proportionally for the target number of persons. If the recipe doesn't have a valid person count or already matches the target, returns the recipe unchanged.

      Parameters

      • recipe: recipeTableElement

        The recipe to scale

      • targetPersons: number

        The target number of persons to scale for

      Returns recipeTableElement

      New recipe object with scaled ingredient quantities

      const originalRecipe = {
      title: "Pasta",
      persons: 4,
      ingredients: [{ name: "Pasta", quantity: "400", unit: "g" }]
      };

      const scaledRecipe = RecipeDatabase.scaleRecipeToPersons(originalRecipe, 2);
      // scaledRecipe.persons === 2
      // scaledRecipe.ingredients[0].quantity === "200"
    • Closes the database connection and resets all internal state

      Use this method in test teardown (afterEach) to properly cleanup database resources between tests.

      Returns Promise<void>

      Promise that resolves when cleanup is complete

    • Initializes the database by creating tables and loading data into local cache

      This method must be called before using any other database operations. It creates the necessary tables if they don't exist and loads all data into memory for faster access.

      Returns Promise<void>

      Promise that resolves when initialization is complete

      const db = RecipeDatabase.getInstance();
      await db.init();
      console.log('Database ready for use');
    • Checks if the database is empty

      Determines whether the database contains any data by checking if all three main tables (recipes, ingredients, and tags) are empty. This is useful for preventing duplicate data insertion during app initialization.

      Returns boolean

      True if all main tables are empty, false if any table contains data

      const db = RecipeDatabase.getInstance();
      await db.init();

      if (db.isDatabaseEmpty()) {
      console.log('Database is empty, loading initial data...');
      await db.addMultipleRecipes(initialRecipes);
      }
    • Adds a new ingredient to the database

      Parameters

      Returns Promise<ingredientTableElement>

      Promise resolving to the added ingredient with database ID

      Error if ingredient insertion or retrieval fails

      const ingredient = await db.addIngredient({
      name: "Flour",
      unit: "cups",
      type: ingredientType.grain,
      season: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
      });
      console.log(`Ingredient added with ID: ${ingredient.id}`);
    • Adds multiple ingredients to the database in a single batch operation

      Performs a batch insert for improved performance when adding multiple ingredients. Uses a database transaction to ensure atomicity and efficiency.

      Parameters

      Returns Promise<void>

      await db.addMultipleIngredients([
      {
      name: "Flour",
      unit: "cups",
      type: ingredientType.grain,
      season: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
      },
      {
      name: "Sugar",
      unit: "cups",
      type: ingredientType.sweetener,
      season: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
      }
      ]);
    • Adds multiple tags to the database in a single batch operation

      Performs a batch insert for improved performance when adding multiple tags. Uses a database transaction to ensure atomicity and efficiency.

      Parameters

      Returns Promise<void>

      await db.addMultipleTags([
      { name: "Dessert" },
      { name: "Quick & Easy" },
      { name: "Vegetarian" }
      ]);
    • Adds a new recipe to the database

      This method verifies that all ingredients and tags exist in the database, adding them automatically if they don't exist.

      Parameters

      Returns Promise<void>

      Promise that resolves when the recipe is added

      await db.addRecipe({
      title: "Chocolate Cake",
      description: "Delicious chocolate cake",
      ingredients: [
      { name: "Flour", quantity: "2 cups", unit: "cups", type: "grain" }
      ],
      tags: [{ name: "Dessert" }],
      persons: 8,
      time: 45,
      preparation: ["Mix ingredients", "Bake for 30 minutes"]
      });
    • Checks if a recipe is already in the menu

      Parameters

      • recipeId: number

        The recipe ID to check

      Returns boolean

      True if recipe is in menu, false otherwise

    • Adds a recipe to the menu and regenerates the shopping list

      If the recipe is already in the menu, increments its count. Otherwise, it adds the recipe to the menu table with count = 1.

      Parameters

      Returns Promise<void>

    • Toggles the cooked status of a menu item

      Parameters

      • menuId: number

        The menu item ID to toggle

      Returns Promise<boolean>

      True if successful, false otherwise

    • Decrements the count of a menu item, removing it if count reaches 0

      Parameters

      • menuId: number

        The menu item ID to decrement/remove

      Returns Promise<boolean>

      True if successful, false otherwise

    • Returns the map of purchased ingredient states Key is ingredient name, value is whether it's purchased

      Returns Map<string, boolean>

    • Sets the purchase state for an ingredient

      Parameters

      • ingredientName: string

        The ingredient name

      • purchased: boolean

        Whether the ingredient is purchased

      Returns Promise<void>

    • Clears all purchased ingredient states Called when the menu is cleared to start fresh

      Returns Promise<void>

    • Scales and updates a single recipe in the database

      Takes a pre-scaled recipe object and updates it in the database. This method is used for individual recipe updates during progressive scaling operations.

      Parameters

      • scaledRecipe: recipeTableElement

        The recipe object that has already been scaled to target persons

      Returns Promise<void>

      Error if recipe doesn't have an ID or update fails

      const recipe = db.get_recipes()[0];
      const scaledRecipe = RecipeDatabase.scaleRecipeToPersons(recipe, 4);
      await db.scaleAndUpdateRecipe(scaledRecipe);
    • Finds recipes with similar ingredients and quantities

      Uses ingredient comparison and fuzzy text matching to find recipes that share similar ingredients and cooking methods.

      Parameters

      Returns recipeTableElement[]

      Array of similar recipes

      const similar = db.findSimilarRecipes(myRecipe);
      console.log(`Found ${similar.length} similar recipes`);
    • Finds tags with similar names using fuzzy matching

      Parameters

      • tagName: string

        The tag name to search for

      Returns tagTableElement[]

      Array of similar tags, sorted by relevance

      const similarTags = db.findSimilarTags("dessrt"); // Finds "Dessert"
      
    • Finds ingredients with similar names using fuzzy matching

      Cleans ingredient names by removing parenthetical content and uses fuzzy search to find similar ingredients.

      Parameters

      • ingredientName: string

        The ingredient name to search for

      Returns ingredientTableElement[]

      Array of similar ingredients, sorted by relevance

      const similar = db.findSimilarIngredients("tomatoe"); // Finds "Tomato"
      
    • Finds similar ingredients for multiple names in a single operation

      More efficient than calling findSimilarIngredients multiple times as it processes all names in one pass.

      Parameters

      • ingredientNames: string[]

        Array of ingredient names to search for

      Returns Map<string, ingredientTableElement[]>

      Map of original names to arrays of similar ingredients

    • Finds similar tags for multiple names in a single operation

      More efficient than calling findSimilarTags multiple times as it processes all names in one pass.

      Parameters

      • tagNames: string[]

        Array of tag names to search for

      Returns Map<string, tagTableElement[]>

      Map of original names to arrays of similar tags

    • Gets all imported recipe source URLs for a specific provider

      Returns URLs of recipes that have been successfully imported from the given provider. These recipes should be hidden from future discovery.

      Parameters

      • providerId: string

        The provider identifier (e.g., 'hellofresh')

      Returns Set<string>

      Set of source URLs for imported recipes

    • Gets all seen-but-not-imported recipe URLs for a specific provider

      Returns URLs of recipes that were discovered but not imported. These recipes should be shown with a visual indicator.

      Parameters

      • providerId: string

        The provider identifier (e.g., 'hellofresh')

      Returns Set<string>

      Set of URLs for seen-but-not-imported recipes

    • Marks recipe URLs as seen for a specific provider

      Records that the user has seen these recipes during discovery. Only adds new entries for URLs not already tracked.

      Parameters

      • providerId: string

        The provider identifier (e.g., 'hellofresh')

      • urls: string[]

        Array of recipe URLs to mark as seen

      Returns Promise<void>

    • Removes recipe URLs from seen history for a specific provider

      Called after successful import to remove URLs from the "seen" list since they are now tracked as imported recipes.

      Parameters

      • providerId: string

        The provider identifier (e.g., 'hellofresh')

      • urls: string[]

        Array of recipe URLs to remove from seen history

      Returns Promise<void>

    • Loads all purchased ingredients from the database

      Returns Promise<Map<string, boolean>>

      Map of ingredient name to purchased state

    • Encodes a purchased ingredient element for database storage

      Parameters

      • element: { ingredientName: string; purchased: boolean }

      Returns Record<string, string | number>

    • Private

      Constructs a Map structure for updating recipe data in the database

      Converts an encoded recipe element into a Map structure suitable for database update operations, mapping column names to their corresponding values.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and recipe data as values

    • Private

      Constructs a Map structure for updating ingredient data in the database

      Converts an ingredient element into a Map structure suitable for database update operations, properly encoding seasonal data with separators.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and ingredient data as values

    • Private

      Constructs a Map structure for updating tag data in the database

      Converts a tag element into a Map structure suitable for database update operations.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and tag data as values

    • Private

      Opens a connection to the SQLite database

      Creates and establishes a connection to the SQLite database using the configured database name. Logs success/failure for debugging purposes.

      Returns Promise<void>

      Will log error if database connection fails

    • Private

      Completely removes the database file and resets the instance

      Closes the current database connection, deletes the database file from storage, and resets all internal data structures to their initial state.

      Returns Promise<void>

      Will log error if database deletion fails

    • Private

      Verifies that all tags exist in the database and returns them with database IDs

      Checks each tag against the local cache and returns the database versions. Throws an error listing all tags that are not found in the database.

      Parameters

      Returns tagTableElement[]

      Array of tags with database IDs

      Error if any tags are not found in the database, listing all missing tags

    • Private

      Verifies that all ingredients exist in the database and returns them with database IDs

      Checks each ingredient against the local cache and returns the database versions with recipe-specific quantities and optional usage notes. Throws an error listing all ingredients that are not found.

      Parameters

      Returns ingredientTableElement[]

      Array of ingredients with database IDs, recipe-specific quantities, and notes

      Error if any ingredients are not found in the database, listing all missing ingredients

    • Private

      Constructs a Map structure for searching recipes in the database

      Creates a search criteria Map using key recipe fields (title, description, image) for database query operations when searching without an ID.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and search values

    • Private

      Constructs a Map structure for searching ingredients in the database

      Creates a search criteria Map using key ingredient fields (name, unit, type) for database query operations when searching without an ID.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and search values

    • Private

      Constructs a Map structure for searching tags in the database

      Creates a search criteria Map using the tag name for database query operations when searching without an ID.

      Parameters

      Returns Map<string, string | number>

      Map with column names as keys and search values

    • Private

      Encodes a recipe object for database storage

      Converts a recipe from the application format to the database storage format, encoding all nested objects (tags, ingredients, preparation steps, nutrition) into string representations using appropriate separators.

      Parameters

      Returns encodedRecipeElement

      Encoded recipe element ready for database insertion/update

    • Private

      Prepares recipe image URI for database storage

      Handles temporary image URIs by saving them to permanent storage. If the image URI is already in permanent storage, returns it unchanged. This encapsulates all image preparation logic within the database layer.

      Parameters

      • imageUri: string

        The image URI from the recipe (temporary or permanent)

      • recipeTitle: string

        The recipe title used for filename generation

      Returns Promise<string>

      Promise resolving to the permanent image URI

    • Private

      Decodes a recipe from database storage format to application format

      Converts an encoded recipe element from the database into the full application format, decoding all nested data structures (ingredients, tags, preparation, nutrition) and resolving file paths and database references.

      Parameters

      Returns Promise<recipeTableElement>

      Promise resolving to fully decoded recipe object

    • Private

      Encodes an ingredient for storage within a recipe's ingredients list

      Converts an ingredient to a string representation containing the ingredient's database ID, quantity, and optional usage note. Used when storing ingredient references within recipe data.

      Format: "ID--quantity" or "ID--quantity%%note" if note is present. This allows the same ingredient to appear multiple times with different usage contexts (e.g., "olive oil" for sauce vs garnish).

      Parameters

      Returns string

      Encoded string, or empty string if ingredient not found in database

      // Without note
      encodeIngredient({id: 1, quantity: "200", ...}) // "1--200"

      // With note
      encodeIngredient({id: 1, quantity: "200", note: "For the sauce", ...}) // "1--200%%For the sauce"
    • Private

      Decodes ingredients from a recipe's encoded ingredient string

      Parses the encoded ingredient string from a recipe, looking up each ingredient by ID in the database and combining it with the recipe-specific quantities and optional usage notes. Also calculates the combined seasonal availability.

      Supports both old format (without notes) and new format (with notes):

      • Old: "1--250__2--100" (backward compatible)
      • New: "1--250%%For sauce__2--100%%For garnish"

      Parameters

      • encodedIngredient: string

        Encoded string containing ingredient IDs, quantities, and optional notes

      Returns Promise<[ingredientTableElement[], string[]]>

      Promise resolving to tuple of [decoded ingredients array, combined season array]

      // Old format (backward compatible)
      Input: "1--250__2--100"
      Output: [[ingredient1 with quantity 250, ingredient2 with quantity 100], ["5","6","7"]]

      // New format with notes
      Input: "1--200%%For sauce__1--100%%For garnish"
      Output: [[ingredient1 with quantity 200 and note "For sauce", ingredient1 with quantity 100 and note "For garnish"], ...]
    • Private

      Encodes a single ingredient for database storage

      Converts an ingredient element from application format into the encoded format required for database insertion. Joins seasonal data into a string representation using the encoding separator.

      Parameters

      Returns encodedIngredientElement

      Encoded ingredient ready for database storage

      Input: {id: 1, name: "Flour", unit: "g", type: "grain", season: ["1","2","3","12"]}
      Output: {"ID":1,"INGREDIENT":"Flour","UNIT":"g", "TYPE":"grain", "SEASON":"1__2__3__12"}
    • Private

      Decodes a single ingredient from database storage format

      Converts an encoded ingredient element from the database into the application format, parsing the seasonal data from its encoded string representation.

      Parameters

      Returns ingredientTableElement

      Decoded ingredient object in application format

      Input: {"ID":1,"INGREDIENT":"Flour","UNIT":"g", "TYPE":"grain", "SEASON":"1__2__3__12"}
      Output: {id: 1, name: "Flour", unit: "g", type: "grain", season: ["1","2","3","12"]}
    • Private

      Calculates the intersection of two seasonal availability arrays

      Combines seasonal data from multiple ingredients to determine when a recipe can be made using seasonal ingredients. Returns months that are common to both seasons.

      Parameters

      • previousSeason: string[]

        Previously calculated season array (accumulated from other ingredients)

      • ingredientSeason: string[]

        Season array from current ingredient

      Returns string[]

      Array of month strings that are available in both seasons

      Input: ["5","6","7","8"], ["6","7","8","9"]
      Output: ["6","7","8"]
    • Private

      Encodes a tag for storage within a recipe's tags list

      Converts a tag to its database ID string representation for storage within recipe data. Looks up the tag in the local cache if ID is missing.

      Parameters

      Returns string

      String representation of the tag's database ID, or error message if not found

    • Private

      Decodes tags from a recipe's encoded tag string

      Parses the encoded tag string from a recipe, looking up each tag by ID in the database to get the full tag information including names.

      Parameters

      • encodedTag: string

        Encoded string containing tag IDs separated by encoding separators

      Returns Promise<tagTableElement[]>

      Promise resolving to array of decoded tag objects

      Input: "1__2__5__3__4"
      Output: [{id: 1, name: "Italian"}, {id: 2, name: "Dinner"}, ...]
    • Private

      Decodes an array of tags from database storage format

      Processes multiple encoded tag elements from database queries, converting each one to the application format. Returns empty array if input is null, undefined, or empty.

      Parameters

      Returns tagTableElement[]

      Array of decoded tag objects in application format

    • Private

      Encodes nutrition information for database storage

      Converts a nutrition object to a string representation by joining all nutritional values with text separators for compact storage within recipe data.

      Parameters

      Returns string

      String representation of all nutrition values separated by text separators

    • Private

      Decodes nutrition information from database storage format

      Parses an encoded nutrition string back into a nutrition object. Returns undefined if the string is empty or has invalid format.

      Parameters

      • encodedNutrition: string

        Encoded string containing nutrition values separated by text separators

      Returns undefined | nutritionTableElement

      Decoded nutrition object or undefined if invalid/empty

      Input: "0--250--1046--15.0--8.0--25.0--12.0--2.5--6.0--0.8--100"
      Output: {id: undefined, energyKcal: 250, energyKj: 1046, fat: 15.0, ...}
    • Private

      Decodes preparation steps from database storage format

      Parses an encoded preparation string back into an array of preparation step objects. Each step can have both a title and description, or just a description.

      Parameters

      • encodedPreparation: string

        Encoded string containing preparation steps

      Returns preparationStepElement[]

      Array of preparation step objects with title and description

      Input: "Cook pasta--Boil water and add pasta__Mix sauce--Combine ingredients"
      Output: [{title: "Cook pasta", description: "Boil water and add pasta"}, {title: "Mix sauce", description: "Combine ingredients"}]
    • Private

      Retrieves all recipes from the database

      Fetches all recipe records from the database and decodes them into the application format for use in the local cache.

      Returns Promise<recipeTableElement[]>

      Promise resolving to array of all recipes in application format

    • Private

      Retrieves all tags from the database

      Fetches all tag records from the database and decodes them into the application format for use in the local cache.

      Returns Promise<tagTableElement[]>

      Promise resolving to array of all tags in application format

    • Private

      Retrieves all menu items from the database

      Fetches all menu records from the database and decodes them into the application format for use in the local cache.

      Returns Promise<menuTableElement[]>

      Promise resolving to array of all menu items in application format

    • Private

      Decodes an array of menu items from database storage format

      Processes multiple encoded menu elements from database queries, converting each one to the application format. Returns empty array if input is null, undefined, or empty.

      Parameters

      Returns menuTableElement[]

      Array of decoded menu items in application format

    • Private

      Compares two ingredient lists for similarity

      Determines if two ingredient lists are similar by comparing both ingredient names and quantities per person. Uses a 20% threshold for quantity differences. Used in the similar recipes feature to find recipes with comparable ingredients.

      Parameters

      Returns boolean

      True if ingredients lists are similar, false otherwise

      Two recipes with "flour: 2 cups per person" and "flour: 2.1 cups per person" would be similar
      Two recipes with "flour: 2 cups per person" and "flour: 3 cups per person" would not be similar (50% difference > 20% threshold)
    • Private

      Migrates the database to add source tracking columns if they don't exist

      This migration adds SOURCE_URL and SOURCE_PROVIDER columns to the recipes table to support bulk import tracking. Runs safely even if columns already exist.

      Returns Promise<void>

    • Private

      Migrates wildcard '*' season values to explicit month lists in the ingredients table.

      Converts SEASON = '*' to '1__2__3__4__5__6__7__8__9__10__11__12'. Idempotent — safe to run on every startup.

      TODO: Remove this migration once all users have updated past this version.

      Returns Promise<void>