Ejemplo n.º 1
0
    def testTransaction(self):
        class MyModel(model.Model):
            text = model.StringProperty()

        key = model.Key(MyModel, 'babaz')
        self.assertEqual(key.get(), None)

        def callback():
            # Emulate get_or_insert()
            a = key.get()
            if a is None:
                a = MyModel(text='baz', key=key)
                a.put()
            return a

        b = model.transaction(callback)
        self.assertNotEqual(b, None)
        self.assertEqual(b.text, 'baz')
        self.assertEqual(key.get(), b)

        key = model.Key(MyModel, 'bababaz')
        self.assertEqual(key.get(), None)
        c = model.transaction(callback, retry=0, entity_group=key)
        self.assertNotEqual(c, None)
        self.assertEqual(c.text, 'baz')
        self.assertEqual(key.get(), c)
Ejemplo n.º 2
0
  def testTransaction(self):
    class MyModel(model.Model):
      text = model.StringProperty()

    key = model.Key(MyModel, 'babaz')
    self.assertEqual(key.get(), None)

    def callback():
      # Emulate get_or_insert()
      a = key.get()
      if a is None:
        a = MyModel(text='baz', key=key)
        a.put()
      return a

    b = model.transaction(callback)
    self.assertNotEqual(b, None)
    self.assertEqual(b.text, 'baz')
    self.assertEqual(key.get(), b)

    key = model.Key(MyModel, 'bababaz')
    self.assertEqual(key.get(), None)
    c = model.transaction(callback, retry=0, entity_group=key)
    self.assertNotEqual(c, None)
    self.assertEqual(c.text, 'baz')
    self.assertEqual(key.get(), c)
Ejemplo n.º 3
0
    def create_multi(cls, values):
        """Creates multiple unique values at once.

        :param values:
            A sequence of values to be unique. See :meth:`create`.
        :returns:
            A tuple (bool, list_of_keys). If all values were created, bool is
            True and list_of_keys is empty. If one or more values weren't
            created, bool is False and the list contains all the values that
            already existed in datastore during the creation attempt.
        """
        # Maybe do a preliminary check, before going for transactions?
        # entities = model.get_multi(keys)
        # existing = [entity.key.id() for entity in entities if entity]
        # if existing:
        #    return False, existing

        # Create all records transactionally.
        keys = [model.Key(cls, value) for value in values]
        entities = [cls(key=key) for key in keys]
        func = lambda e: e.put() if not e.key.get() else None
        created = [model.transaction(lambda: func(e)) for e in entities]

        if created != keys:
            # A poor man's "rollback": delete all recently created records.
            model.delete_multi(k for k in created if k)
            return False, [k.id() for k in keys if k not in created]

        return True, []
Ejemplo n.º 4
0
    def create_multi(cls, values):
        """Creates multiple unique values at once.

        :param values:
            A sequence of values to be unique. See :meth:`create`.
        :returns:
            A tuple (bool, list_of_keys). If all values were created, bool is
            True and list_of_keys is empty. If one or more values weren't
            created, bool is False and the list contains all the values that
            already existed in datastore during the creation attempt.
        """
        # Maybe do a preliminary check, before going for transactions?
        # entities = model.get_multi(keys)
        # existing = [entity.key.id() for entity in entities if entity]
        # if existing:
        #    return False, existing

        # Create all records transactionally.
        keys = [model.Key(cls, value) for value in values]
        entities = [cls(key=key) for key in keys]
        func = lambda e: e.put() if not e.key.get() else None
        created = [model.transaction(lambda: func(e)) for e in entities]

        if created != keys:
            # A poor man's "rollback": delete all recently created records.
            model.delete_multi(k for k in created if k)
            return False, [k.id() for k in keys if k not in created]

        return True, []
Ejemplo n.º 5
0
  def try_transition(self, next_state, **kwargs):
    """Transition (if conditions are met) to the given next_state if next state
    arg is set;  otherwise (no specific next_state indicated)
    to a next state whose transition conditions are met. make_transit should
    return True if transition made; False, if error while
    making transition.  try_transition returns None if no transition tried
    (no conditions met).
    """
    # Note: wrapping the entire transition, including its condition checking,
    # in a transaction.  This is overkill under many circumstances (so we might
    # want to change this if there are contention issues), and also takes
    # advantage of the fact that currently everything we need to operate on
    # is in the same entity group, but makes the semantics of the
    # implementation more clear.

    def _tx():
      res = None
      if next_state:  # if state specified, try to transit to it
        if self._check_transit_conds(next_state, **kwargs):
          res = self._make_transit(next_state, **kwargs)
      else:
        for ns in self.next_states:
          # take the first transition whose conditions are met
          if self._check_transit_conds(ns, **kwargs):
            res = self._make_transit(ns, **kwargs)
            logging.info("finished make_transit with res %s", res)
            break
      return res
    resp = model.transaction(_tx)  # run the transaction
    return resp
Ejemplo n.º 6
0
    def create_multi(cls, values):
        """Creates multiple unique values at once.

        :param values:
            A sequence of values to be unique. See :meth:`create`.
        :returns:
            A tuple (bool, list_of_keys). If all values were created, bool is
            True and list_of_keys is empty. If one or more values weren't
            created, bool is False and the list contains all the values that
            already existed in datastore during the creation attempt.
        """
        keys = [cls.get_key(value) for value in values]

        # Preliminary check, before going for more expensive transactions.
        entities = model.get_multi(keys)
        existing = [entity.key.id() for entity in entities if entity]
        if existing:
            return False, existing

        # Create all records transactionally.
        created = []
        entities = [cls(key=key) for key in keys]
        for entity in entities:
            txn = lambda: entity.put() if not entity.key.get() else None
            key = model.transaction(txn)
            if key:
                created.append(key)

        if created != keys:
            # A poor man's "rollback": delete all recently created records.
            model.delete_multi(created)
            return False, [k.id() for k in keys if k not in created]

        return True, []
Ejemplo n.º 7
0
    def register(cls, **user_values):
        """Registers a new user."""
        if 'password_raw' in user_values:
            user_values['password'] = security.create_password_hash(
                user_values.pop('password_raw'), bit_strength=12)

        user_values['username'] = username = user_values['name'].lower()
        user = User(key=cls.get_key(username), **user_values)

        # Unique auth id and email.
        unique_auth_id = 'User.auth_id:%s' % user_values['auth_id']
        unique_email = 'User.email:%s' % user_values['email']
        uniques = [unique_auth_id, unique_email]
        success, existing = unique_model.Unique.create_multi(uniques)

        if success:
            txn = lambda: user.put() if not user.key.get() else None
            if model.transaction(txn):
                return True, user
            else:
                unique_model.Unique.delete_multi(uniques)
                return False, ['username']
        else:
            properties = []
            if unique_auth_id in uniques:
                properties.append('auth_id')

            if unique_email in uniques:
                properties.append('email')

            return False, properties
Ejemplo n.º 8
0
    def create_multi(cls, values):
        keys = [model.Key(cls, value) for value in values]
        entities = [cls(key=key) for key in keys]
        func = lambda e: e.put() if not e.key.get() else None
        created = [model.transaction(lambda: func(e)) for e in entities]

        if created != keys:
            # A poor man's rollback: delete all recently created records.
            model.delete_multi(k for k in created if k)
            return False, [k.id() for k in keys if k not in created]

        return True, []
Ejemplo n.º 9
0
    def create(cls, value):
        """Creates a new unique value.

        :param value:
            The value to be unique, as a string.

            The value should include the scope in which the value must be
            unique (ancestor, namespace, kind and/or property name).

            For example, for a unique property `email` from kind `User`, the
            value can be `User.email:[email protected]`. In this case `User.email`
            is the scope, and `[email protected]` is the value to be unique.
        :returns:
            True if the unique value was created, False otherwise.
        """
        entity = cls(key=model.Key(cls, value))
        txn = lambda: entity.put() if not entity.key.get() else None
        return model.transaction(txn) is not None
Ejemplo n.º 10
0
    def create(cls, value):
        """Creates a new unique value.

        :param value:
            The value to be unique, as a string.

            The value should include the scope in which the value must be
            unique (ancestor, namespace, kind and/or property name).

            For example, for a unique property `email` from kind `User`, the
            value can be `User.email:[email protected]`. In this case `User.email`
            is the scope, and `[email protected]` is the value to be unique.
        :returns:
            True if the unique value was created, False otherwise.
        """
        entity = cls(key=model.Key(cls, value))
        txn = lambda: entity.put() if not entity.key.get() else None
        return model.transaction(txn) is not None
Ejemplo n.º 11
0
  def get_current_game(cls, hangout_id):
    """Retrieves the current game, or creates one if none exists."""

    def _tx():
      dirty = False
      hangout = cls.get_by_id(hangout_id)
      if not hangout:
        hangout = cls(id=hangout_id)
        dirty = True
      if hangout.current_game:
        game = hangout.current_game.get()
      else:
        game = Game.new_game(hangout)
        game.put()
        hangout.current_game = game.key
        dirty = True
      if dirty:
        model.put_multi([hangout, game])
      return game
    return model.transaction(_tx)
Ejemplo n.º 12
0
  def get_or_create_participant(cls, game_key, plus_id):
    """ Either return the participant associated with the given plus_is,
    or create a new participant with that id, and deal them some cards.
    """

    def _tx():
      game = game_key.get()
      participant = cls.get_by_id(plus_id, parent=game_key)
      if not participant:
        participant = cls(id=plus_id, parent=game_key)
        participant.channel_id = str(participant.key)
        participant.channel_token = channel.create_channel(
            participant.channel_id)
      participant.playing = True
      # deal the hand for the participant.
      # TODO - deal with the case where the player did not get any cards,
      # indicated if hand is None.
      hand = game.deal_hand(participant)
      # if not hand:
        # react usefully if there were not enough cards for their hand.
      model.put_multi([participant, game])
      return participant
    return model.transaction(_tx)
Ejemplo n.º 13
0
 def create(cls, value):
     entity = cls(key=model.Key(cls, value))
     txn = lambda: entity.put() if not entity.key.get() else None
     return model.transaction(txn) is not None
Ejemplo n.º 14
0
    def create_user(cls, _unique_email=True, **user_values):
        """Creates a new user.

        :param _unique_email:
            True to require the email to be unique, False otherwise.
        :param user_values:
            Keyword arguments to create a new user entity. Required ones are:

            - name
            - username
            - auth_id
            - email

            Optional keywords:

            - password_raw (a plain password to be hashed)

            The properties values of `username` and `auth_id` must be unique.
            Optionally, `email` can also be required to be unique.
        :returns:
            A tuple (boolean, info). The boolean indicates if the user
            was created. If creation succeeds,  ``info`` is the user entity;
            otherwise it is a list of duplicated unique properties that
            caused the creation to fail.
        """
        assert user_values.get('password') is None, \
            'Use password_raw instead of password to create new users'

        if 'password_raw' in user_values:
            user_values['password'] = security.generate_password_hash(
                user_values.pop('password_raw'), length=12)

        user_values['username'] = user_values['username'].lower()
        user_values['auth_id'] = user_values['auth_id'].lower()
        user = User(key=cls.get_key(user_values['auth_id']), **user_values)

        # Unique auth id and email.
        unique_username = '******' % user_values['username']
        uniques = [unique_username]
        if _unique_email:
            unique_email = 'User.email:%s' % user_values['email']
            uniques.append(unique_email)
        else:
            unique_email = None

        if uniques:
            success, existing = unique_model.Unique.create_multi(uniques)

        if success:
            txn = lambda: user.put() if not user.key.get() else None
            if model.transaction(txn):
                return True, user
            else:
                unique_model.Unique.delete_multi(uniques)
                return False, ['auth_id']
        else:
            properties = []
            if unique_username in uniques:
                properties.append('username')

            if unique_email in uniques:
                properties.append('email')

            return False, properties
Ejemplo n.º 15
0
 def create(cls, value):
     entity = cls(key=model.Key(cls, value))
     txn = lambda: entity.put() if not entity.key.get() else None
     return model.transaction(txn) or None
Ejemplo n.º 16
0
    def create_user(cls, _unique_email=True, **user_values):
        """Creates a new user.

        :param _unique_email:
            True to require the email to be unique, False otherwise.
        :param user_values:
            Keyword arguments to create a new user entity. Required ones are:

            - name
            - username
            - auth_id
            - email

            Optional keywords:

            - password_raw (a plain password to be hashed)

            The properties values of `username` and `auth_id` must be unique.
            Optionally, `email` can also be required to be unique.
        :returns:
            A tuple (boolean, info). The boolean indicates if the user
            was created. If creation succeeds,  ``info`` is the user entity;
            otherwise it is a list of duplicated unique properties that
            caused the creation to fail.
        """
        assert user_values.get('password') is None, \
            'Use password_raw instead of password to create new users'

        if 'password_raw' in user_values:
            user_values['password'] = security.generate_password_hash(
                user_values.pop('password_raw'), length=12)

        user_values['username'] = user_values['username'].lower()
        user_values['auth_id'] = user_values['auth_id'].lower()
        user = User(key=cls.get_key(user_values['auth_id']), **user_values)

        # Unique auth id and email.
        unique_username = '******' % user_values['username']
        uniques = [unique_username]
        if _unique_email:
            unique_email = 'User.email:%s' % user_values['email']
            uniques.append(unique_email)
        else:
            unique_email = None

        if uniques:
            success, existing = unique_model.Unique.create_multi(uniques)

        if success:
            txn = lambda: user.put() if not user.key.get() else None
            if model.transaction(txn):
                return True, user
            else:
                unique_model.Unique.delete_multi(uniques)
                return False, ['auth_id']
        else:
            properties = []
            if unique_username in uniques:
                properties.append('username')

            if unique_email in uniques:
                properties.append('email')

            return False, properties