class User(Model, UserMixin):
        __metadata__ = {
            "_name": "users",
            'throughput': {
                'read': 1,
                'write': 1,
            },
            'global_indexes': [
                GlobalIndex.all('email-username', 'username').throughput(read=1, write=1),
                GlobalIndex.all('email-index', 'email').throughput(read=1, write=1)
            ],
        }

        id = Field(hash_key=True)
        active = Field(data_type=bool)

        # User authentication information
        username = Field()
        password = Field()

        # User email information
        email = Field()
        email_confirmed_at = Field(data_type=datetime)

        # User information
        first_name = Field()
        last_name = Field()

        def get_id(self):
            if self.id is None:
                self.id = str(uuid.uuid1())
            return self.id
Exemple #2
0
class PrimitiveWidget(Model):

    """ Model for testing python data types """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('gindex', 'string2', 'num'),
            GlobalIndex('gindex2', 'num2', 'binary'),
        ],
    }
    string = Field(data_type=six.binary_type, hash_key=True)
    string2 = Field(data_type=six.text_type)
    num = Field(data_type=int, coerce=True)
    num2 = Field(data_type=float)
    binary = Field(data_type=BINARY, coerce=True)
    myset = Field(data_type=set)
    data = Field(data_type=dict)
    friends = Field(data_type=list)
    created = Field(data_type=datetime)
    birthday = Field(data_type=date)
    wobbles = Field(data_type=bool)
    price = Field(data_type=Decimal)

    def __init__(self, **kwargs):
        kwargs.setdefault('string', 'abc')
        super(PrimitiveWidget, self).__init__(**kwargs)
Exemple #3
0
    def test_add_index_test_mode(self):
        """Simulates adding a global secondary index at a later time. However, with the test attribute selected, no
        change is actually made."""
        table = self.engine.dynamo.describe_table(
            WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace))
        self.assertEqual(len(table.global_indexes), 1)

        # Simulating adding an index later on.
        WidgetToAddIndex.meta_.global_indexes.append(
            GlobalIndex('gindex-2', 'string2', 'string'))
        WidgetToAddIndex.meta_.post_create()
        WidgetToAddIndex.meta_.validate_model()
        WidgetToAddIndex.meta_.post_validate()

        changed = self.engine.update_schema(test=True)
        self.assertListEqual(
            changed,
            [WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace)])

        table = self.engine.dynamo.describe_table(
            WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace))
        self.assertEqual(len(table.global_indexes), 1)

        try:
            self.engine.query(WidgetToAddIndex).index('gindex-2').filter(
                WidgetToAddIndex.string2 == 'test').all()
        except DynamoDBError:
            pass
        else:
            assert False, "An error was expected"
Exemple #4
0
    def test_add_index(self):
        """Simulates adding a global secondary index at a later time."""
        table = self.engine.dynamo.describe_table(
            WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace))
        self.assertEqual(len(table.global_indexes), 1)

        # Simulating adding an index later on.
        WidgetToAddIndex.meta_.global_indexes.append(
            GlobalIndex('gindex-2', 'string2', 'string'))
        WidgetToAddIndex.meta_.post_create()
        WidgetToAddIndex.meta_.validate_model()
        WidgetToAddIndex.meta_.post_validate()

        changed = self.engine.update_schema()
        self.assertListEqual(
            changed,
            [WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace)])

        table = self.engine.dynamo.describe_table(
            WidgetToAddIndex.meta_.ddb_tablename(self.engine.namespace))
        self.assertEqual(len(table.global_indexes), 2)

        one = WidgetToAddIndex("one-1", "one-2", 1)
        two = WidgetToAddIndex("one-2", "test", 2)

        self.engine.save(one)
        self.engine.save(two)

        result = self.engine.query(WidgetToAddIndex).index('gindex-2').filter(
            WidgetToAddIndex.string2 == 'test').all()

        self.assertEqual(len(result), 1)
        self.assertNotEqual(result[0], one)
        self.assertEqual(result[0], two)
Exemple #5
0
class EmailNotify(DyBase):

    __tablename__ = 'email_notify'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'email',
                            'date_created').throughput(read=1, write=1),
        ],
    }

    # Identification Data: email & password
    email = Field(data_type=STRING, nullable=False)
    type = Field(data_type=STRING, nullable=False)

    # New instance instantiation procedure
    def __init__(self, email, type):
        super(EmailNotify, self).__init__()
        self.email = email
        self.type = type

    def __repr__(self):
        return '<email %r>' % (self.email)
Exemple #6
0
class PublicHoliday(DyBase):

    __tablename__ = 'public_holiday'

    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id').throughput(read=1,
                                                               write=1),
        ],
    }
    created_by_id = Field(data_type=STRING, nullable=False)
    group_id = Field(data_type=STRING, nullable=False)
    holiday_date = Field(data_type=NUMBER, nullable=False)
    # full day or half day
    is_halfday = Field(data_type=NUMBER, nullable=False)

    # New instance instantiation procedure
    def __init__(self, created_by_id, group_id, date, is_halfday):
        super(PublicHoliday, self).__init__()
        self.created_by_id = created_by_id
        self.group_id = group_id
        self.holiday_date = date
        self.is_halfday = is_halfday

    def __repr__(self):
        return '<Date %r>' % (str(self.holiday_date))

    def __getitem__(self, key):
        return self.holiday_date
Exemple #7
0
class Rule(DyBase):

    __tablename__ = 'rule'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },

        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id', 'term_id').throughput(read=1, write=1),
        ],
    }

    # Identification Data: email & password
    group_id = Field(data_type=STRING, nullable=False)
    term_id = Field(data_type=STRING, nullable=False)
    definition = Field(data_type=STRING, nullable=False)

    # New instance instantiation procedure
    def __init__(self, group_id, term_id, definition):
        super(Rule, self).__init__()
        self.group_id     = group_id
        self.term_id = term_id
        self.definition    = definition

    def __repr__(self):
        return '<group %r>' % (self.group_id)
Exemple #8
0
class Group(DyBase):

    __tablename__ = 'group'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'domain').throughput(read=1, write=1),
        ],
    }
    # Identification Data: email & password
    name = Field(data_type=STRING)
    type_id = Field(data_type=NUMBER)
    domain = Field(data_type=STRING)
    default_term_id = Field(data_type=STRING, nullable=True)

    # New instance instantiation procedure
    def __init__(self, name, type_id, domain):
        super(Group, self).__init__()
        self.name = name
        self.type_id = type_id
        self.domain = domain

    def __repr__(self):
        return '<Group %r>' % (self.name)

    def __getitem__(self, key):
        return self.id
Exemple #9
0
class Member(DyBase):

    __tablename__ = 'group_member'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id').throughput(read=1,
                                                               write=1),
        ],
    }

    group_id = Field(data_type=STRING, nullable=False)
    user_id = Field(data_type=NUMBER, nullable=False)

    # New instance instantiation procedure
    def __init__(self, group_id, user_id):
        super(Member, self).__init__()
        self.group_id = group_id
        self.user_id = user_id

    def __repr__(self):
        return '<User_id %r>' % (self.user_id)
Exemple #10
0
class Term(DyBase):

    __tablename__ = 'term'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id').throughput(read=1, write=1),
        ],
    }
    group_id = Field(data_type=STRING, nullable=False)
    name = Field(data_type=STRING, nullable=False)
    start_date = Field(data_type=NUMBER, nullable=False)
    end_date = Field(data_type=NUMBER, nullable=False)
    family_spread = Field(data_type=STRING,  nullable=False)

    # New instance instantiation procedure
    def __init__(self, group_id, name, start_dt, end_dt, family_spread):
        super(Term, self).__init__()
        self.group_id     = group_id
        self.name    = name
        self.start_date  =start_dt
        self.end_date = end_dt
        self.family_spread = family_spread

    def __repr__(self):
        return '<term name %r>' % (self.name)
Exemple #11
0
class Post(Model):

    """ Test model with composite fields """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('score-index', 'c_all', 'score'),
        ]
    }
    hkey = Composite('userid', 'id', hash_key=True)
    userid = Field()
    id = Field()
    c_all = Composite('userid', 'id', 'about', 'text')
    score = Composite('likes', 'ts', 'deleted', data_type=NUMBER,
                      merge=lambda x, y, z: None if z else x + y)
    likes = Field(data_type=int, default=0)
    ts = Field(data_type=float, default=0)
    deleted = Field(data_type=bool, default=False)
    points = Field(data_type=Decimal, default=Decimal('0'))
    about = Field()
    text = Field()
    tags = Field(data_type=set)
    keywords = Composite('text', 'about', data_type=set,
                         merge=lambda t, a: t.split() + a.split(), coerce=True)

    def __init__(self, userid, id, ts, text='foo', about='bar'):
        super(Post, self).__init__(userid=userid, id=id, ts=ts, text=text,
                                   about=about)
Exemple #12
0
class Invite(DyBase):

    __tablename__ = 'invite'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id').throughput(read=1,
                                                               write=1),
        ],
    }

    email = Field(data_type=STRING, nullable=False)
    group_id = Field(data_type=STRING, nullable=False)
    invite_token = Field(data_type=STRING, nullable=True)

    # New instance instantiation procedure
    def __init__(self, email, group_id, invite_token):
        super(Invite, self).__init__()
        self.email = email
        self.group_id = group_id
        self.invite_token = invite_token

    def __repr__(self):
        return '<Email %r>' % (self.email)
Exemple #13
0
class Widget(Model):

    """ Model for testing default field values """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('gindex', 'string2', 'num'),
        ],
    }
    string = Field(hash_key=True)
    string2 = Field()
    num = Field(data_type=NUMBER)
    binary = Field(data_type=BINARY, coerce=True)
    str_set = Field(data_type=STRING_SET)
    num_set = Field(data_type=NUMBER_SET)
    bin_set = Field(data_type=BINARY_SET)
    data_dict = Field(data_type=dict)
    data_list = Field(data_type=list)
    bigdata = Field(data_type=CompressedDict)
    natural_num = Field(data_type=int, check=lambda x: x >= 0, default=1)
    check_num = Field(data_type=int,
                      check=(lambda x: x != 0, lambda x: x != 2))
    not_null = Field(data_type=int, nullable=False, default=0)
    not_null_natural = Field(data_type=int, check=lambda x: x != 1,
                             nullable=False, default=0)
    comp = Composite('str_set', data_type=int, merge=len)

    def __init__(self, **kwargs):
        kwargs.setdefault('string', 'abc')
        super(Widget, self).__init__(**kwargs)
Exemple #14
0
class Children(DyBase):

    __tablename__ = 'term_children'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },

        'global_indexes': [
            GlobalIndex.all('ts-index', 'term_id').throughput(read=1, write=1),
        ],
    }

    term_id = Field(data_type=STRING, nullable=False)
    child_count = Field(data_type=NUMBER, nullable=False)

    # New instance instantiation procedure
    def __init__(self, term_id, child_count):
        super(Children, self).__init__()
        self.term_id     = term_id
        self.child_count    = child_count

    def __repr__(self):
        return '<term id %r>' % (self.term_id)
Exemple #15
0
class Store(Model):

    """ Test model for indexes """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex.all('name-index', 'name', 'city'),
            GlobalIndex.keys('name-emp-index', 'name', 'num_employees'),
            GlobalIndex.include('name-profit-index', 'name', 'monthly_profit',
                                includes=['name', 'num_employees']),
        ],
    }
    city = Field(hash_key=True)
    name = Field(range_key=True)
    sq_feet = Field(data_type=int).all_index('size-index')
    num_employees = Field(data_type=int).keys_index('emp-index')
    monthly_profit = Field(data_type=float)\
        .include_index('profit-index', ['name', 'num_employees'])
Exemple #16
0
class User(DyBase):

    __tablename__ = 'user'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },
        'global_indexes': [
            GlobalIndex.all('ts-index1', 'email').throughput(read=1, write=1),
            GlobalIndex.all('ts-index', 'role').throughput(read=1, write=1),
        ],
    }

    # Identification Data: email & password
    name = Field(data_type=STRING, nullable=False)
    given_name = Field(data_type=STRING, nullable=False)
    family_name = Field(data_type=STRING, nullable=False)
    email = Field(data_type=STRING, nullable=False)
    password = Field(data_type=STRING, nullable=True)
    auth_token = Field(data_type=STRING, nullable=True)
    image_url = Field(data_type=STRING, nullable=True)

    # Authorisation Data: role & status
    role = Field(data_type=NUMBER, nullable=False, default=1)
    is_active = Field(data_type=NUMBER, nullable=False, default=True)

    # New instance instantiation procedure
    def __init__(self, name, givenName, familyName, email, password, token,
                 imageUrl):
        super(User, self).__init__()
        self.name = name
        self.given_name = givenName
        self.family_name = familyName
        self.email = email
        self.password = password
        self.auth_token = token
        self.image_url = imageUrl

    def __repr__(self):
        return '<User %r>' % (self.email)

    def __getitem__(self, key):
        return self.email
Exemple #17
0
class Post(Model):

    """ Model for testing composite queries """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('name-index', 'username', 'score'),
            GlobalIndex('ts-index', 'username', 'ts'),
            GlobalIndex('hash-index', 'total_uid')
        ],
    }
    uid = Composite('type', 'id', hash_key=True)
    type = Field()
    id = Field()
    score = Composite('ts', 'upvotes', range_key=True, data_type=NUMBER,
                      merge=score_merge)
    username = Field()
    ts = Field(data_type=NUMBER, default=0)
    upvotes = Field(data_type=NUMBER, default=0)
    total_uid = Composite('uid', 'username', merge=lambda x, y: x + ':' +
                          str(y))
Exemple #18
0
class DynamoPackage(Package, Model):
    """ Python package stored in DynamoDB """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('name-index', 'name'),
        ],
    }
    filename = Field(hash_key=True)
    name = Field()
    version = Field()
    last_modified = Field(data_type=datetime)
    data = Field(data_type=dict)
Exemple #19
0
class User(Model):

    """ Model for testing queries """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('name-index', 'name', 'score'),
        ],
    }
    id = Field(hash_key=True)
    name = Field(range_key=True)
    score = Field(data_type=NUMBER, index='score-index', default=0)
    str_set = Field(data_type=STRING_SET)
Exemple #20
0
class OAuth2DynamoToken(Model):
    """ Dynamo version of authlib.integrations.sqla_oauth2.OAuth2TokenMixin """
    __metadata__ = {
        'global_indexes': [
            GlobalIndex.keys('refresh-index', 'refresh_token').throughput(read=10, write=2),
            GlobalIndex.keys('user-index', 'user_id').throughput(read=10, write=2)
        ],
    }

    client_id = Field(type=STRING)
    user_id = Field(type=NUMBER)
    token_type = Field(type=STRING)
    access_token = Field(hash_key=True)
    refresh_token = Field(type=STRING)
    scope = Field()
    revoked = Field(type=bool)
    issued_at = Field(type=NUMBER)
    expires_in = Field(type=NUMBER)

    def get_client_id(self):
        return self.client_id

    def get_scope(self):
        return self.scope

    def get_expires_in(self):
        return self.expires_in

    def get_expires_at(self):
        return self.issued_at + self.expires_in

    def is_refresh_token_active(self):
        if self.revoked:
            return False
        expires_at = self.issued_at + self.expires_in * 2
        return expires_at >= time.time()
Exemple #21
0
class DynamoPackage(Package, Model):
    """ Python package stored in DynamoDB """

    __metadata__ = {"global_indexes": [GlobalIndex("name-index", "name")]}
    filename = Field(hash_key=True)
    name = Field()
    version = Field()
    last_modified = Field(data_type=datetime)
    summary = Field()
    data = Field(data_type=dict)

    def __init__(self, *args, **kwargs):
        super(DynamoPackage, self).__init__(*args, **kwargs)
        # DynamoDB doesn't play nice with empty strings.
        if not self.summary:
            self.summary = None
Exemple #22
0
class Widget(Model):
    """ Test model with composite fields """
    __metadata__ = {
        'global_indexes':
        [GlobalIndex('ts-index', 'userid', 'ts').throughput(1, 1)],
        'throughput': {
            'read': 1,
            'write': 1,
        },
    }
    userid = Field(hash_key=True)
    c_range = Composite('userid', 'id', range_key=True)
    c_index = Composite('userid', 'id', index='comp-index')
    c_plain = Composite('userid', 'id')
    _c_private = Composite('userid', 'id')
    id = Field()
    ts = Field(data_type=NUMBER)

    def __init__(self, userid, id, ts):
        super(Widget, self).__init__(userid, id=id, ts=ts)
Exemple #23
0
class AbstractWidget(Model):
    """ This is an abstract widget. It should be ignored.

    """

    __metadata__ = {
        'global_indexes': [
            GlobalIndex('gindex', 'string2', 'num'),
        ],
        "_abstract": True
    }
    string = Field(hash_key=True)
    string2 = Field()
    num = Field(data_type=NUMBER)

    def __init__(self, string, string2, num):
        super(AbstractWidget, self).__init__()
        self.string = string
        self.string2 = string2
        self.num = num
Exemple #24
0
class Switchday(DyBase):

    __tablename__ = 'switchday'
    __metadata__ = {
        'throughput': {
            'read': 1,
            'write': 1,
        },

        'global_indexes': [
            GlobalIndex.all('ts-index', 'group_id').throughput(read=1, write=1),
        ],
    }

    group_id = Field(data_type=STRING, nullable=False)
    switch_date = Field(data_type=NUMBER, nullable=False)
    from_time_in_24hours = Field(data_type=STRING, default = '0900')
    to_time_in_24hours = Field(data_type=STRING, default = '1630')
    standin_user_id = Field(data_type=STRING, nullable=True)
    is_half_day = Field(data_type=NUMBER, nullable=False, default=False)
    is_work_day = Field(data_type=NUMBER, nullable=False, default=False)

    # New instance instantiation procedure
    def __init__(self, group_id, switch_date, from_time, to_time,
                 standin_user_id, is_half_day, is_work_day):
        super(Switchday, self).__init__()
        self.group_id = group_id
        self.switch_date = switch_date
        self.from_time_in_24hours = from_time
        self.to_time_in_24hours = to_time
        self.standin_user_id = standin_user_id
        self.is_half_day = is_half_day
        self.is_work_day = is_work_day

    def __repr__(self):
        return '<Switch_date %r>' % (self.switch_date)
    def __getitem__(self, key):
        return self.switch_date
Exemple #25
0
class AppDetails(Model):
    __metadata__ = {
        'global_indexes': [
            GlobalIndex('price-index', 'currency', 'price'),
            GlobalIndex('iphone-index', 'supportediPhone'),
            GlobalIndex('ipad-index', 'supportediPad'),
            GlobalIndex('ipod-index', 'supportediPod'),
        ],
    }
    app_id = Field(data_type=types.IntType, hash_key=True, coerce=True)
    country = Field(data_type=types.StringType, range_key=True)
    advisories = Field(data_type=types.ListType)
    artistId = Field(data_type=types.IntType, coerce=True)
    artistName = Field(data_type=types.StringType)
    artistViewUrl = Field(data_type=types.StringType)
    artworkUrl100 = Field(data_type=types.StringType)
    artworkUrl512 = Field(data_type=types.StringType)
    artworkUrl60 = Field(data_type=types.StringType)
    averageUserRating = Field(data_type=types.FloatType, coerce=True)
    averageUserRatingForCurrentVersion = Field(data_type=types.FloatType,
                                               coerce=True)
    bundleId = Field(data_type=types.StringType)
    contentAdvisoryRating = Field(data_type=types.StringType)
    currency = Field(data_type=types.StringType)
    currentVersionReleaseDate = Field(data_type=types.DateTimeType)
    description = Field(data_type=types.StringType)
    features = Field(data_type=types.ListType)
    fileSizeBytes = Field(data_type=types.IntType, coerce=True)
    formattedPrice = Field(data_type=types.StringType)
    genreIds = Field(data_type=types.ListType)
    genres = Field(data_type=types.ListType)
    ipadScreenshotUrls = Field(data_type=types.ListType)
    isGameCenterEnabled = Field(data_type=types.BoolType)
    isVppDeviceBasedLicensingEnabled = Field(data_type=types.BoolType)
    kind = Field(data_type=types.StringType)
    languageCodesISO2A = Field(data_type=types.ListType)
    minimumOsVersion = Field(data_type=types.StringType)
    price = Field(data_type=types.FloatType, coerce=True)
    primaryGenreId = Field(data_type=types.IntType, coerce=True)
    primaryGenreName = Field(data_type=types.StringType)
    releaseDate = Field(data_type=types.DateTimeType, coerce=True)
    releaseNotes = Field(data_type=types.StringType)
    screenshotUrls = Field(data_type=types.ListType)
    sellerName = Field(data_type=types.StringType)
    sellerUrl = Field(data_type=types.StringType)
    supportedDevices = Field(data_type=set_(str), coerce=True)
    supportediPad = Field(data_type=types.IntType, default=0)
    supportediPads = Field(data_type=set_(str))
    supportediPhone = Field(data_type=types.IntType, default=0)
    supportediPhones = Field(data_type=set_(str))
    supportediPod = Field(data_type=types.IntType, default=0)
    supportediPods = Field(data_type=set_(str))
    trackCensoredName = Field(data_type=types.StringType)
    trackContentRating = Field(data_type=types.StringType)
    trackId = Field(data_type=types.IntType, coerce=True)
    trackName = Field(data_type=types.StringType)
    trackViewUrl = Field(data_type=types.StringType)
    userRatingCount = Field(data_type=types.IntType, coerce=True)
    userRatingCountForCurrentVersion = Field(data_type=types.IntType,
                                             coerce=True)
    version = Field(data_type=types.StringType)
    wrapperType = Field(data_type=types.StringType)

    def __repr__(self):
        return "%s (%s) selling for %s %s" % (self.app_id, self.country,
                                              self.price, self.currency)

    def __init__(self, app_id, country, data=None):
        if data is None:
            data = {}

        self.app_id = app_id
        self.country = country
        for field, value in data.items():
            if 'Date' in field:
                value = strptime(value, "%Y-%m-%dT%H:%M:%SZ")
                value = datetime.fromtimestamp(mktime(value))
            setattr(self, field, value)
        if self.supportedDevices:
            self.index_devices()

    def index_devices(self):
        ipads = set()
        ipods = set()
        iphones = set()

        for device in self.supportedDevices:
            if device.startswith('iPad'):
                ipads.add(device)
            elif device.startswith('iPod'):
                ipods.add(device)
            else:
                iphones.add(device)

        if ipods:
            self.supportediPod = 1
            self.supportediPods = ipods
        if ipads:
            self.supportediPad = 1
            self.supportediPads = ipads
        if iphones:
            self.supportediPhone = 1
            self.supportediPhones = iphones

    @classmethod
    def with_price(cls, currency, lower_price, higher_price=None):
        """
        Finds all apps based on currency and price.
        If only one price is passed, finds apps with exact price.
        If higher_price is passed, finds apps within range of lower_price
        and higher_price.
        """
        if higher_price is None:
            return engine(cls).filter(
                currency=currency,
                price=lower_price).index('price-index').all()
        return engine(cls).filter(
            cls.currency == currency,
            cls.price.between_(lower_price,
                               higher_price)).index('price-index').all()

    @classmethod
    def with_supportedDevice(cls, device):
        """
        Query method that returns an array of all apps that support the given
        device name.
        Device name must start with 'iPod', 'iPad', or 'iPhone', else will
        raise an error.
        """
        if device.startswith('iPod'):
            device_type = cls.supportediPod
            device_list = cls.supportediPods
            device_index = 'ipod-index'
        elif device.startswith('iPad'):
            device_type = cls.supportediPad
            device_list = cls.supportediPads
            device_index = 'ipad-index'
        elif device.startswith('iPhone'):
            device_type = cls.supportediPhone
            device_list = cls.supportediPads
            device_index = 'iphone-index'
        else:
            return InValidDeviceName("%s is not a valid device name" % device)
        return engine(cls).filter(
            device_type == 1,
            device_list.contains_(device)).index(device_index).all()