Exemple #1
0
    def post(self):
        """
        Create a new ingredient.
        :return: Ingredient you created.
        """
        i = IngredientFactory.raw_to_obj(api.payload)
        i.refresh()
        IngredientFactory.insert_obj(obj=i)
        IngredientIndexer.index(i)

        # Invalidate cache
        IngredientScanCache.invalidate()
        IngredientTreeCache.invalidate()

        return ObjectSerializer.serialize(i, 'dict'), 201
Exemple #2
0
    def delete(self, slug):
        """
        Delete a single ingredient from the database.
        :param slug:
        :return:
        """
        i = IngredientFactory.produce_obj(id=slug)
        IngredientFactory.delete_obj(obj=i)

        # Invalidate caches and de-index.
        IngredientScanCache.invalidate()
        IngredientTreeCache.invalidate()
        IngredientIndexer.delete(i)

        return None, 204
Exemple #3
0
    def produce_obj(cls, id, expand=False):
        i = super().produce_obj(id=id)
        if expand:
            tree = IngredientTreeCache.retrieve()
            i.expand(tree)

        return i
Exemple #4
0
    def delete(self):
        """
        Delete all ingredients from the database. There be dragons here.
        :return: Number of items deleted.
        """
        objects = IngredientFactory.produce_all_objs()
        for i in objects:
            IngredientFactory.delete_obj(obj=i, commit=False)

        IngredientIndexer.empty()

        current_session.commit()
        IngredientScanCache.invalidate()
        IngredientTreeCache.invalidate()

        return len(objects), 204
Exemple #5
0
    def obj_to_index(cls, obj, format='dict'):
        base_recipe = ObjectSerializer.serialize(obj, format)
        base_recipe.update({'alpha': obj.alpha})

        tree = IngredientTreeCache.retrieve()

        specs = base_recipe.pop('specs')

        searchable_recipes = {}
        for spec in specs:
            # Holy F**k this took too long to figure out
            # https://thispointer.com/python-how-to-copy-a-dictionary-shallow-copy-vs-deep-copy/
            searchable = copy.deepcopy(base_recipe)
            searchable['spec'] = spec
            searchable_id = '%s::%s' % (searchable['slug'], spec['slug'])
            searchable_recipes[searchable_id] = searchable

            # This count is achievable with a filter query in ES.
            # https://stackoverflow.com/questions/58659527/elastic-search-update-specific-nested-object
            # { filter: { script: { script: { source: "doc['spec.components.slug'].value.length() == 3" } } }
            # But it seemed to return some weird results too. Also required fielddata enabled on
            # the index. Also need to refactor the searchquer builder to deal with a deep parameter. This is
            # just easier.
            #
            # Maybe someday this will also bring back the notion of "countable" ingredients (ie, exclude bitters).
            # Given the complexity around that (requires parent to lookup, also ZK list of slugs to exclude)
            # it's not quite worth it right now.
            searchable['spec']['component_count'] = len(spec['components'])

            # https://stackoverflow.com/questions/14071038/add-an-element-in-each-dictionary-of-a-list-list-comprehension
            for component in spec['components']:
                # the Slug() is needed for the TDFv3 name->slug conversion.
                component.update({'parents': tree.parents(Slug(component['slug']))})

        return [cls._index(meta={'id': key}, **value) for key, value in searchable_recipes.items()]
Exemple #6
0
 def get(self):
     """
     Get the entire ingredient tree from cache. No marshaling model
     is documented due to recursion problems.
     :return: Dict
     """
     ingredient_tree = IngredientTreeCache.retrieve()
     return json.loads(ingredient_tree.to_json())
Exemple #7
0
 def get(self, slug):
     """
     Return relevant information needed to substitute this ingredient.
     :param slug:
     :return: Dict
     """
     ingredient_tree = IngredientTreeCache.retrieve()
     return ingredient_tree.substitutions(slug)
Exemple #8
0
 def get(self, slug):
     """
     Return the subtree of this ingredient from the main tree.
     No api.marshal_with() due to recursion.
     :param slug:
     :return: Dict
     """
     ingredient_tree = IngredientTreeCache.retrieve()
     return json.loads(ingredient_tree.subtree(slug).to_json(with_data=True))
Exemple #9
0
    def resolve(cls, inventory, cocktail, spec_slug=None):
        """
        Process a Recipe resolution request. This request could be for all specs of a cocktail
        or just one.
        :param inventory: Inventory to resolve against.
        :param cocktail: Cocktail object to resolve.
        :param spec_slug: Optional Slug of the spec to resolve (None means do all of them)
        :return: List of SpecResolutionSummary objects.
        """
        results = []

        # We retrieve the tree here and expand the inventory so that there isn't potential
        # inconsistency between retrieving the tree now vs later. It does mean we have to
        # pass it around to various functions.
        tree = IngredientTreeCache.retrieve()
        inventory.expand(tree=tree)

        LogService.info("Cocktail %s has specs: %s" %
                        (cocktail.slug, [spec.slug
                                         for spec in cocktail.specs]))
        for spec in cocktail.specs:
            # Skip any specs that the user didn't ask for with the spec_slug
            # parameter.
            if spec_slug and spec.slug != spec_slug:
                LogService.info(
                    "Skipping spec %s because you didn't want it." % spec.slug)
                continue

            # Parse the spec
            results.append(
                cls._resolve_spec(inventory=inventory,
                                  cocktail=cocktail,
                                  spec=spec,
                                  tree=tree))

        # Return the list of results.
        return results
Exemple #10
0
    def resolve(cls, inventory, cocktail, spec_slug=None):
        results = []

        tree = IngredientTreeCache.retrieve()
        inventory.expand(tree=tree)

        Log.info("Cocktail specs: %s" % [spec.slug for spec in cocktail.specs])
        for spec in cocktail.specs:
            # Skip any specs that the user didn't ask for with the spec_slug
            # parameter.
            if spec_slug and spec.slug != spec_slug:
                Log.info("Skipping slug %s because you didn't want it." %
                         spec.slug)
                continue

            # Parse the spec
            results.append(
                cls._resolve_spec(inventory=inventory,
                                  cocktail=cocktail,
                                  spec=spec,
                                  tree=tree))

        # Return the list of results.
        return results
Exemple #11
0
 def collect(cls):
     tree = IngredientTreeCache.retrieve()
     return len(tree)