Ejemplo n.º 1
0
class WineTasting(BaseModel):
    consumption_type = ndb.StringProperty()
    consumption_location = ndb.StringProperty()
    consumption_location_name = ndb.StringProperty()
    date = ndb.DateProperty()
    rating = ndb.IntegerProperty()
    flawed = ndb.BooleanProperty(default=False)
    note = ndb.StringProperty()

    def config(self, data):
        self.apply([
            "consumption_type", "consumption_location",
            "consumption_location_name", "date", "rating", "flawed", "note"
        ], data)

    def create(self, data):
        self.config(data)
        key = self.put()
        return key

    def modify(self, data):
        self.config(data)
        key = self.put()
        return key

    def delete(self):
        self.key.delete()
Ejemplo n.º 2
0
class Event(BaseModel):
    """
    User <X> has created model <Key> at time <Z>
    """
    user = ndb.StringProperty(required=True, indexed=False)
    action = ndb.StringProperty(required=True, choices=actions)
    model = ndb.KeyProperty(required=True)
    model_type = ndb.StringProperty(required=True)
    time = ndb.DateTimeProperty(auto_now_add=True)

    @staticmethod
    def add_event(event, user, model_type, model):
        e = Event()
        e.action = event
        e.user = user
        e.model = model
        e.model_type = model_type
        return e.put()

    @staticmethod
    def create(user, model_type, model):
        Event.add_event("CREATE", user, model_type, model)

    @staticmethod
    def update(user, model_type, model):
        Event.add_event("UPDATE", user, model_type, model)

    @staticmethod
    def delete(user, model_type, model):
        Event.add_event("DELETE", user, model_type, model)
Ejemplo n.º 3
0
class UserWine(BaseModel):
    user = ndb.KeyProperty()
    drink_after = ndb.DateProperty()
    drink_before = ndb.DateProperty()
    tags = ndb.StringProperty(repeated=True)  # list of tags

    def config(self, data):
        self.apply(["drink_before", "drink_after"], data)
        if 'user' in data:
            self.user = data['user'].key
            del data['user']

        if 'tags' in data:
            tags = json.loads(data['tags'])
            if type(tags) != list:
                tags = [tags]
            self.tags = list(set(self.tags + tags))
            del data['tags']

    def create(self, data):
        self.config(data)
        key = self.put()
        return key

    def modify(self, data):
        self.config(data)
        key = self.put()
        return key

    def delete(self):
        self.key.delete()
Ejemplo n.º 4
0
class WineBottle(BaseModel):
    # Parent: wine
    wine = ndb.KeyProperty()
    bottle_size = ndb.StringProperty()
    purchase_date = ndb.DateProperty()
    purchase_location = ndb.StringProperty()
    storage_location1 = ndb.StringProperty()
    storage_location2 = ndb.StringProperty()
    cost = ndb.IntegerProperty()  # Stored as number of cents
    consumed = ndb.BooleanProperty(default=False)
    consumed_date = ndb.DateProperty()

    json = ndb.JsonProperty(indexed=False)

    def config(self, data):
        self.apply(['bottle_size', 'purchase_date', 'purchase_location', 'storage_location1',
                    'storage_location2', 'consumed', 'consumed_date'], data)
        
        if 'cost' in data and data['cost'] != '':
            self.cost = int(float(data['cost']) * 100)
            del data['cost']

        json = BaseModel.tidy_up_the_post_object(data)
        self.json = json

        key = self.put()
        return key

    def create(self, data):
        self.config(data)
        key = self.put()
        return key

    def modify(self, data):
        self.config(data)
        key = self.put()
        return key

    def delete(self):
        self.key.delete()
Ejemplo n.º 5
0
class WineCellar(BaseModel):
    name = ndb.StringProperty()

    def create(self, data):
        self.apply(["name"], data)
        key = self.put()
        return key

    def modify(self, data):
        self.apply(["name"], data)
        key = self.put()
        return key

    def delete(self):
        self.key.delete()
Ejemplo n.º 6
0
class User(BaseModel):
    name = ndb.StringProperty()
    guser = ndb.UserProperty()
    email = ndb.StringProperty()
    cellar = ndb.KeyProperty()

    def create(self, data):
        logging.info("adding: " + data['email'])
        self.apply(['name', 'email', 'guser'], data)
        key = self.put()
        return key

    def delete(self):
        self.key.delete()

    @staticmethod
    def get_current_user():
        guser = users.get_current_user()
        if guser is None:
            raise Exception("Not Authenticated")
        qry = User.query(User.guser == guser)
        results = qry.fetch(1)
        if len(results) <= 0:  # create the user
            user = User()
            user.create({
                'guser': guser,
                'name': guser.nickname(),
                'email': guser.email()
            })
            return user
        else:
            return results[0]

    @staticmethod
    def has_access(cellar_key):
        return User.get_current_user().cellar == cellar_key
Ejemplo n.º 7
0
class Wine(BaseModel):
    # Parent: Winery
    year = ndb.IntegerProperty()
    name = ndb.StringProperty()
    winetype = ndb.StringProperty(required=True, choices=wine_types.types)
    varietal = ndb.StringProperty()
    upc = ndb.StringProperty()

    @property
    def has_year(self):
        return 'year' in self

    @property
    def has_name(self):
        return 'name' in self

    @property
    def has_winetype(self):
        return 'winetype' in self

    @property
    def has_varietal(self):
        return 'varietal' in self

    @property
    def has_upc(self):
        return 'upc' in self

    verified = ndb.BooleanProperty(default=False)
    verified_by = ndb.StringProperty()

    @property
    def has_verified(self):
        return 'verified' in self

    @property
    def has_verified_by(self):
        return 'verified_by' in self

    json = ndb.JsonProperty(indexed=False)

    # JSON properties encompass the bits that might want to be tracked
    # but are too fiddly to keep track of regularly, like
    # bud_break, veraison, oak_regime, barrel_age, harvest_date,
    # bottling_date, alcohol_content, winemaker_notes, vineyard_notes...

    def has_json(self):
        return 'json' in self

    def create(self, post, winery):
        """

        >>> v = Winery()
        >>> v_key = v.create({'name':'Winery'})
        >>> w = Wine(parent=v_key)
        >>> post = {}
        >>> post['name'] = 'Red Character'
        >>> post['varietal'] = 'Blend'
        >>> post['winetype'] = 'Red'
        >>> post['upc'] = '1234567890'
        >>> post['blend'] = ['Merlot', 'Cabernet Franc']
        >>> post['token'] = "stub-uuid"
        >>> w_key = w.create(post, v)

        >>> w.name
        'Red Character'
        >>> w.varietal
        'Blend'
        >>> w.winetype
        'Red'
        >>> w.to_dict()['json']['blend']
        ['Merlot', 'Cabernet Franc']
        >>> w.verified
        True
        >>> w.verified_by
        'Winery'

        """
        name = None
        if 'name' in post:
            name = post['name']
            self.name = name
            del post['name']

        year = None
        if 'year' in post:
            year = int(post['year'])
            self.year = year
            del post['year']

        winetype = None
        if 'winetype' in post:
            winetype = post['winetype']
            if not winetype in wine_types.types:
                raise ValueError("Invalid Wine Type: " + str(winetype))
            else:
                self.winetype = winetype
                del post['winetype']

        varietal = None
        if 'varietal' in post:
            varietal = post['varietal']
            self.varietal = varietal
            del post['varietal']

        upc = None
        if 'upc' in post:
            upc = post['upc']
            del post['upc']

        if not winetype:
            raise ValueError("You must provide a winetype")

        if not name and not year and not varietal and not upc:
            raise ValueError("You must provide a name, year, " +
                             " varietal, or upc.")

        token = None
        if 'token' in post:
            token = post['token']
            self.verify(token, winery)
            del post['token']

        json = BaseModel.tidy_up_the_post_object(post)
        self.json = json

        key = self.put()
        return key

    def modify(self, post, winery):
        """
        >>> v = Winery()
        >>> v_key = v.create({"name":"Winery"})
        >>> w = Wine(parent=v_key)
        >>> w_key = w.create({"winetype":"Red", "year":"2010"}, v)

        The base case.
        >>> w.modify({"name":"Red Character", "terroir":"Good"}, v)
        >>> w.to_dict()["name"]
        'Red Character'

        >>> w.to_dict()["json"]["terroir"]
        'Good'

        >>> w2 = Wine(parent=v_key)
        >>> w2.modify({"winetype":"White", "year":"2011"}, v)
        >>> w2.to_dict()["winetype"]
        'White'

        >>> w2.to_dict()["year"]
        2011

        >>> w.modify({"varietal":"Blend"}, v)
        >>> w.to_dict()["varietal"]
        'Blend'

        >>> w.modify({"upc":"123456789"}, v)
        >>> w.to_dict()["upc"]
        '123456789'

        You can't replace a field.
        >>> w.modify({"winetype":"White"}, v)
        Traceback (most recent call last):
        ...
        YouNeedATokenForThat...

        >>> w.modify({"terroir": "at danger lake!"}, v)
        Traceback (most recent call last):
        ...
        YouNeedATokenForThat...

        Should be fine if you update a thing with itself.
        >>> w.modify({"winetype":"Red"}, v)
        >>> w.modify({"terroir":"Good"}, v)

        You can update whatever you like if you have a token.
        >>> w.modify({"winetype":"White", "token":"stub-uuid"}, v)
        >>> w.to_dict()["winetype"]
        'White'

        """
        def field_edit_error(fieldname):
            return YouNeedATokenForThat(("You can't edit fields that already" +
                                         " exist: %s" % fieldname))

        can_edit_fields = False
        if 'token' in post:
            token = post['token']
            can_edit_fields = self.verify(token, winery)
            del post['token']

        def can_edit_field(field_name):
            if field_name in post:
                if not field_name in self:
                    return True
                if post[field_name] == str(self.to_dict()[field_name]):
                    return True
                if can_edit_fields:
                    return True
                raise field_edit_error(field_name)
            else:
                return False

        name = None
        if can_edit_field('name'):
            name = post['name']
            self.name = name
            del post['name']

        year = None
        if can_edit_field('year'):
            year = int(post['year'])
            self.year = year
            del post['year']

        winetype = None
        if can_edit_field('winetype'):
            winetype = post['winetype']
            if not winetype in wine_types.types:
                raise ValueError("Invalid Wine Type: " + str(winetype))
            else:
                self.winetype = winetype
                del post['winetype']

        varietal = None
        if can_edit_field('varietal'):
            varietal = post['varietal']
            self.varietal = varietal
            del post['varietal']

        upc = None
        if can_edit_field('upc'):
            upc = post['upc']
            self.upc = upc
            del post['upc']

        json = BaseModel.tidy_up_the_post_object(post)
        if 'json' in self.to_dict():
            new_json = self.to_dict()['json']
            for key, value in json.iteritems():
                if key in new_json and can_edit_fields:
                    new_json[key] = value
                if not (key in new_json):
                    new_json[key] = value
                if key in new_json and new_json[key] == value:
                    pass
                else:
                    raise field_edit_error(key)
            self.json = new_json
        else:
            self.json = json

        key = self.put()
        return None

    def calculate_rank(self):
        rank = 0
        if self.has_verified:
            rank += 24
        if self.has_year:
            rank += 2
        if self.has_name:
            rank += 2
        if self.has_winetype:
            rank += 2
        if self.has_varietal:
            rank += 4
        if self.has_upc:
            rank += 8
        if self.has_json:
            for key in self.to_dict()['json']:
                rank += 1
        return rank

    def verify(self, token=None, winery=None):
        """
        Sets self.verified and self.verified_by,
        True if the token is valid
        False if not
        """
        if not token:
            return False
        if winery and token == winery.private_token:
            self.verified = True
            self.verified_by = "Winery"
            return True
        return False

    def update(self, winery):
        # get all wines for this winery
        wines = Wine.winery_query(winery)
        # remove the wine we just edited
        wines = [wine for wine in wines if self.key.id() != wine.key.id()]
        # add the wine we just edited
        wines.append(self)

        # recalculate the winery rank
        winery.update(wines)
        winery.put()

        # recreate search indexes for every wine under the winery
        #   with the new winery rank as their search index.
        for wine in wines:
            wine.create_search_index(winery)

    def create_search_index(self, winery):
        """
        create a search index for this wine
        """
        if not self.key:
            raise Exception("Can't update without a key.")

        index = search.Index(name="wines")

        searchkey = str(self.key.id())
        # search rank is winery rank + individual rank
        rank = winery.to_dict()['rank'] + self.calculate_rank()

        fields = []

        if self.has_year:
            year = self.to_dict()['year']
            fields.append(search.NumberField(name='year', value=year))

        if self.has_name:
            name = self.to_dict()['name']
            partial_name = BaseModel.partial_search_string(name)
            fields.append(search.TextField(name='name', value=name))
            fields.append(
                search.TextField(name='partial_name', value=partial_name))

        winery_name = winery.to_dict()['name']
        partial_winery_name = BaseModel.partial_search_string(winery_name)
        fields.append(search.TextField(name='winery', value=winery_name))
        fields.append(
            search.TextField(name='partial_winery', value=partial_winery_name))

        if self.has_winetype:
            winetype = self.to_dict()['winetype']
            fields.append(search.AtomField(name='winetype', value=winetype))

        if self.has_varietal:
            varietal = self.to_dict()['varietal']
            partial_varietal = BaseModel.partial_search_string(varietal)
            fields.append(search.TextField(name='varietal', value=varietal))
            fields.append(
                search.TextField(name='partial_varietal',
                                 value=partial_varietal))

        if self.has_upc:
            upc = self.to_dict()['upc']
            fields.append(search.TextField(name='upc', value=upc))

        fields.append(
            search.AtomField(name='verified', value=str(self.has_verified)))

        fields.append(search.TextField(name='id', value=str(self.key.id())))
        fields.append(
            search.TextField(name='winery_id', value=str(winery.key.id())))

        fields.append(search.NumberField(name='rank', value=rank))

        searchdoc = search.Document(doc_id=searchkey, fields=fields, rank=rank)

        index.put(searchdoc)
        return None

    @staticmethod
    def winery_query(winery):
        qry = Wine.query(ancestor=winery.key)
        results = qry.fetch(MAX_RESULTS)
        return [x for x in results]
Ejemplo n.º 8
0
class Winery(BaseModel):
    """
    Represents a single wine producer.
    """
    name = ndb.StringProperty(required=True)

    location = ndb.StringProperty(choices=regions.location_list)
    location_fuzzy = ndb.StringProperty()

    @property
    def has_location(self):
        return 'location' in self

    @property
    def has_location_fuzzy(self):
        return 'location_fuzzy' in self

    # these fields are calculated from location
    # and can't be set from the web interface
    country = ndb.StringProperty(choices=regions.countries)
    region = ndb.StringProperty(choices=regions.regions)
    subregion = ndb.StringProperty(choices=regions.subregions)

    @property
    def has_country(self):
        return 'country' in self

    @property
    def has_region(self):
        return 'region' in self

    @property
    def has_subregion(self):
        return 'subregion' in self

    #security stuff
    verified = ndb.BooleanProperty(default=False)
    verified_by = ndb.StringProperty()
    private_token = ndb.StringProperty(indexed=False)

    rank = ndb.IntegerProperty(required=True, default=0)

    @property
    def has_verified(self):
        return 'verified' in self

    @property
    def has_verified_by(self):
        return 'verified_by' in self

    json = ndb.JsonProperty(indexed=False)

    @property
    def has_json(self):
        return 'json' in self

    # website, phone_number

    def create(self, post):
        """
        Given a dict 'post' object containing winery-y fields,
        populate and put this Winery object, return the key.

        Throws a ValueError if no 'name' is included.
        >>> v_for_winery = Winery()
        >>> v_for_winery.create({})
        Traceback (most recent call last):
        ...
        ValueError: 'name' field is mandatory

        Basic use-case test.
        >>> location = 'Canada - British Columbia: Okanagan Valley'
        >>> post = {'name':'Super Winery', 'location':location }
        >>> v_for_winery = Winery()
        >>> database_key = v_for_winery.create(post)
        >>> v_for_winery.country
        u'Canada'
        >>> v_for_winery.region
        u'British Columbia'
        >>> v_for_winery.subregion
        u'Okanagan Valley'
        >>> database_key.id()
        'stub-key'

        If the location isn't in our list, it goes into location_fuzzy
        >>> location = 'Other'
        >>> post = {'name':'Super Winery 2', 'location':location}
        >>> v_for_winery = Winery()
        >>> database_key = v_for_winery.create(post)
        >>> v_for_winery.to_dict()
        {...'location_fuzzy': 'Other', ...}
        >>> v_for_winery.to_dict()['location_fuzzy']
        'Other'

        Winerys get a private token, which doesn't appear in to_dict()
        >>> v_for_winery.private_token
        'stub-uuid'
        >>> v_for_winery.to_dict()['private_token']
        Traceback (most recent call last):
        ...
        KeyError: 'private_token'

        Fields that we don't have database rows for go into the JSON.
        >>> post = {'name':'Super Winery 3', 'other_field':'glerg'}
        >>> v_for_winery = Winery()
        >>> database_key = v_for_winery.create(post)
        >>> v_for_winery.json
        {'other_field': 'glerg'}

        """
        if not 'name' in post:
            raise ValueError("'name' field is mandatory")
        name = post['name']
        self.name = name
        del post['name']

        if 'location' in post:
            location = post['location']
            self.set_location(location)
            del post['location']

        self.private_token = uuid.uuid4().hex

        # special: winerys + verifieds are magic
        if 'token' in post:
            self.verify(post['token'])
            del post['token']

        # having taken care of 'name' and 'location',
        # we wedge everything else into the JSON
        json = BaseModel.tidy_up_the_post_object(post)
        self.json = json

        self.rank = self.calculate_rank()

        key = self.put()
        return key

    def modify(self, post):
        """
        Given a dict 'post' object containing winery-y fields,
        update this object.

        Empty fields can always be updated. Fields cannot be overwritten
        without a valid winery or verifier token.

        If this object has been verified, no changes may occur without
        a valid winery or verifier token.

        Throws a YouNeedATokenForThat error if the user tries something
        he doesn't have access to without a token

        Let's create a Winery to update...
        >>> location = 'Canada - British Columbia: Okanagan Valley'
        >>> post = {'name':'Super Winery' }
        >>> post['location_fuzzy'] = 'Somewhere'
        >>> post['json_thing'] = 'blerg'
        >>> v = Winery()
        >>> v.location
        <truth.stubs.StringProperty ...>
        >>> database_key = v.create(post)

        And update the location:
        >>> new_post = {'location':location}
        >>> new_post['json_other_thing'] = 'blorg'
        >>> v.modify(new_post)
        >>> v.country
        u'Canada'
        >>> v.to_dict()['json']['json_other_thing']
        'blorg'

        Updates of existing fields should fail.
        >>> other_location = 'Canada - British Columbia: Similkameen Valley'
        >>> v.modify({'location':other_location})
        Traceback (most recent call last):
        ...
        YouNeedATokenForThat...

        Updates of json fields that already exist should fail.
        >>> v.modify({'json_other_thing':'beep boop'})
        Traceback (most recent call last):
        ...
        YouNeedATokenForThat...
        >>> v.to_dict()['json']['json_other_thing']
        'blorg'

        Updating a thing with itself should be fine.
        >>> v.modify({'name':'Super Winery'})
        >>> v.modify({'json_other_thing':'blorg'})
        >>> v.modify({'location':location})

        You can update whatever you want if you have a stub.
        >>> v.modify({'location':other_location, 'token':'stub-uuid'})
        >>> v.subregion
        u'Similkameen Valley'

        Once a token has touched something it can still be changed.
        >>> v.modify({'completely_new_field':'hurfdorf'})

        """
        def field_edit_error(fieldname):
            return YouNeedATokenForThat(("You can't edit fields that already" +
                                         " exist: %s" % fieldname))

        can_edit_fields = False
        if 'token' in post:
            can_edit_fields = self.verify(post['token'])
            del post['token']

        if 'name' in post and post['name'] != self.to_dict()['name']:
            if not can_edit_fields:
                raise field_edit_error('name')
            else:
                self.name = post['name']
            del post['name']

        # if new location == old location, fugeddaboutit
        if ('location' in post and self.has_location
                and post['location'] == self.to_dict()['location']):
            del post['location']

        if 'location' in post:
            location = post['location']
            # a proper location can trump a location_fuzzy
            if (not self.has_location and self.has_location_fuzzy
                    and location in regions.location_list):
                self.set_location(location)
                self.location_fuzzy = None
            # a more specific location can trump a less specific location
            # something trumps nothing
            elif (not self.has_location and not self.has_location_fuzzy):
                self.set_location(location)
            elif can_edit_fields:
                self.set_location(location)
            else:
                raise field_edit_error('location')
            del post['location']

        json = BaseModel.tidy_up_the_post_object(post)

        if self.has_json:
            new_json = self.to_dict()['json']
            for key, value in json.iteritems():
                if key in new_json and can_edit_fields:
                    new_json[key] = value
                if not (key in new_json):
                    new_json[key] = value
                if key in new_json and new_json[key] == value:
                    pass
                else:
                    raise field_edit_error(key)
            self.json = new_json
        else:
            self.json = json

        self.put()

    def verify(self, token=None):
        """
        If the token doesn't exist, return False
        If the token exists and belongs to the winery, return "True",
            and set self.verified and self.verified_by
        If the token exists and belongs to a verifier, return "True",
            and set self.verified and self.verified_by
        If the token exists but doesn't belong, return False

        >>> v = Winery()
        >>> v.create({'name':'Winery'})
        <truth.stubs.Key object...>
        >>> v.private_token
        'stub-uuid'
        >>> v.verify('butts')
        False
        >>> v.has_verified
        False
        >>> v.verify('stub-uuid')
        True
        >>> v.verified_by
        'Winery'

        """
        if not token:
            return False
        if token == self.private_token:
            self.verified = True
            self.verified_by = "Winery"
            return True
        return False

    def update(self, wines=[]):
        """
        Recalculate this object's rank,
        and
        create a search index for it.
        """
        if not self.key:
            raise Exception("Can't update without a key.")

        index = search.Index(name="wineries")

        searchkey = str(self.key.id())
        self.rank = self.calculate_rank(wines)

        location = ""
        if self.has_location:
            location = self.to_dict()['location']
        elif self.has_location_fuzzy:
            location = self.to_dict()['location_fuzzy']
        partial_location = BaseModel.partial_search_string(location)

        fields = []

        name = self.to_dict()['name']
        partial_name = BaseModel.partial_search_string(name)
        fields.append(search.TextField(name='name', value=name))
        fields.append(search.TextField(name='partial_name',
                                       value=partial_name))

        fields.append(search.TextField(name='location', value=location))
        fields.append(
            search.TextField(name='partial_location', value=partial_location))

        if self.has_country:
            country = self.to_dict()['country']
            fields.append(search.AtomField(name='country', value=country))

        if self.has_region:
            region = self.to_dict()['region']
            fields.append(search.AtomField(name='region', value=region))

        if self.has_subregion:
            subregion = self.to_dict()['subregion']
            fields.append(search.AtomField(name='subregion', value=subregion))

        fields.append(
            search.AtomField(name='verified', value=str(self.has_verified)))

        fields.append(search.NumberField(name='rank', value=self.rank))

        fields.append(search.TextField(name='id', value=str(self.key.id())))

        searchdoc = search.Document(doc_id=searchkey,
                                    fields=fields,
                                    rank=self.rank)

        index.put(searchdoc)
        return None

    def calculate_rank(self, wines=[]):
        """
        A potentially expensive operation, to try to quantify
        how much data this Winery object contains.
        More is better.
        """
        rank = 0
        if self.has_verified and self.has_verified_by:
            rank += 10000
        if self.has_country:
            rank += 50
        if self.has_region:
            rank += 100
        if self.has_subregion:
            rank += 200
        if not self.has_location and self.has_location_fuzzy:
            rank += 50

        if self.has_json:
            for key in self.to_dict()['json']:
                rank += 10

        for wine in wines:
            rank += wine.calculate_rank()

        return rank

    def to_dict(self):
        """
        Get the contents of this model as a dictionary.
        Never includes 'private_token'
        Tries to include 'key'
        """
        dict_ = copy.deepcopy(super(Winery, self).to_dict())
        if 'private_token' in dict_:
            del dict_['private_token']
        try:
            if self.key:
                dict_['key'] = self.key.id()
        except AttributeError:
            pass
        return dict_

    def set_location(self, location):
        """
        Given a location from the list of locations provided by
        regions.py (i.e. "Canada - British Columbia: Okanagan Valley")
        parse it into country, region, and subregion, and save
        those to the model.

        >>> v = Winery()
        >>> v.set_location("Canada - British Columbia: Okanagan Valley")
        >>> v.country
        u'Canada'
        >>> v.region
        u'British Columbia'
        >>> v.subregion
        u'Okanagan Valley'

        >>> v = Winery()
        >>> v.set_location("What is this I don't even")
        >>> v.country
        <truth.stubs.StringProperty instance at ...>
        >>> v.location_fuzzy
        "What is this I don't even"

        """
        if location not in regions.location_list:
            self.location_fuzzy = location
        else:
            country, region, subregion = regions.location_map[location]
            self.location = location
            if country:
                self.country = country
            if region:
                self.region = region
            if subregion:
                self.subregion = subregion

    @staticmethod
    def all_query():
        qry = Winery.query()
        results = qry.fetch(
            MAX_RESULTS,
            projection=[Winery.name, Winery.verified, Winery.location])
        return [x for x in results]

    @staticmethod
    def country_query(country):
        qry = Winery.query(Winery.country == country)
        results = qry.fetch(
            MAX_RESULTS,
            projection=[Winery.name, Winery.verified, Winery.location])
        return [x for x in results]

    @staticmethod
    def region_query(region):
        qry = Winery.query(Winery.region == region)
        results = qry.fetch(
            MAX_RESULTS,
            projection=[Winery.name, Winery.verified, Winery.location])
        return [x for x in results]

    @staticmethod
    def subregion_query(subregion):
        qry = Winery.query(Winery.subregion == subregion)
        results = qry.fetch(
            MAX_RESULTS,
            projection=[Winery.name, Winery.verified, Winery.location])
        return [x for x in results]

    @staticmethod
    def name_query(name):
        qry = Winery.query(Winery.name == name)
        results = qry.fetch(MAX_RESULTS,
                            projection=[Winery.verified, Winery.location])
        return [x for x in results]

    @staticmethod
    def verified_query(verified):
        qry = Winery.query(Winery.verified == verified)
        results = qry.fetch(MAX_RESULTS,
                            projection=[Winery.name, Winery.location])
        return [x for x in results]

    @staticmethod
    def verified_by_query(verified_by):
        qry = Winery.query(Winery.verified_by == verified_by)
        results = qry.fetch(MAX_RESULTS,
                            projection=[Winery.name, Winery.location])
        return [x for x in results]

    @staticmethod
    def location_query(location):
        qry = Winery.query(Winery.location == location)
        results = qry.fetch(MAX_RESULTS,
                            projection=[Winery.name, Winery.verified])
        return [x for x in results]

    @staticmethod
    def location_fuzzy_query(location):
        qry = Winery.query(Winery.location_fuzzy == location)
        results = qry.fetch(MAX_RESULTS,
                            projection=[Winery.name, Winery.verified])
        return [x for x in results]

    @staticmethod
    def all_fuzzy_locations():
        qry = Winery.query(Winery.location_fuzzy is not None)
        results = qry.fetch(MAX_RESULTS)
        return [x.location_fuzzy for x in results]

    @staticmethod
    def search(query):

        query = "partial_name = " + query

        winery_index = search.Index(name="wineries")
        winery_query = search.Query(query_string=query)
        winery_results = winery_index.search(winery_query)

        return [ndb.Key(Winery, int(x.doc_id)).get() for x in winery_results]