Module: AppEngine::Datastore

Defined in:
lib/appengine-apis/datastore.rb,
lib/appengine-apis/datastore_types.rb

Overview

The Datastore provides access to a schema-less data storage system. The fundamental unit of data in this system is the Datastore::Entity, which has an immutable identity (represented by a Datastore::Key) and zero of more mutable properties. Entity objects can be created, updated, deleted, retrieved by identifier, and queried via a combination of properties using Datastore::Query.

The Datastore can be used transactionally and supports the notion of a “current” transaction. A current transaction is established by calling #begin_transaction. The transaction returned by this method ceases to be current when an attempt is made to commit or rollback or when another call is made to #begin_transaction. A transaction can only be current within the Thread that created it.

The various overloads of put, get, and delete all support transactions. Users of this class have the choice of explicitly passing a (potentially null) Transaction to these methods or relying on the current transaction.

Supported property types:

  • String (max 500 chars)

  • Integer ((-2**63)..(2**63 - 1))

  • Float

  • Time

  • TrueClass

  • FalseClass

  • NilClass

  • Datastore::Key

  • Datastore::Link

  • Datastore::Text

  • Datastore::Blob

  • Datastore::ByteString

  • Users::User

Defined Under Namespace

Classes: Blob, ByteString, Category, Email, Entity, EntityNotFound, Error, GeoPt, IMHandle, InternalError, Iterable, Iterator, Key, KeyRange, Link, NeedIndex, PhoneNumber, PostalAddress, Query, Rating, Rollback, Text, Timeout, TooManyResults, TransactionFailed

Constant Summary collapse

JavaDatastore =
Java.ComGoogleAppengineApiDatastore
SPECIAL_RUBY_TYPES =
[Time, Text, Blob, ByteString, Link, Email,
Category, PhoneNumber, PostalAddress].freeze

Class Method Summary collapse

Class Method Details

.active_transactionsObject

Returns all Transactions started by this thread upon which no attempt to commit or rollback has been made.



183
184
185
186
187
# File 'lib/appengine-apis/datastore.rb', line 183

def active_transactions
  convert_exceptions do
    @@db.active_transactions
  end
end

.allocate_ids(*args) ⇒ Object

call-seq:

Datastore.allocate_ids(kind, num)
Datastore.allocate_ids(parent, kind, num)

Ids are allocated within a namespace defined by a parent key and a kind. This method allocates a contiguous range of unique ids of size num within the namespace defined by the given parent key and the given kind.

Returns a KeyRange representing the range of allocated ids.



248
249
250
251
252
# File 'lib/appengine-apis/datastore.rb', line 248

def allocate_ids(*args)
  convert_exceptions do
    @@db.allocate_ids(*args)
  end
end

.begin_transactionObject

Begins a transaction agains the datastore. Callers are responsible for explicitly calling #Transaction.commit or #Transaction.rollback when they no longer need the Transaction.

The Transaction returned by this call will be considered the current transaction and will be returned by subsequent, same-thread calls to #current_transaction until one of the following happens:

  1. begin_transaction is invoked from the same thread. In this case current_transaction will return the result of the more recent call to begin_transaction.

  2. Transaction.commit is invoked on the Transaction returned by this method. Whether or not the commit succeeds, the Transaction will no longer be current.

  3. Transaction.rollback is invoked on the Transaction returned by this method. Whether or not the rollback succeeds, the Transaction will no longer be current.



157
158
159
160
161
# File 'lib/appengine-apis/datastore.rb', line 157

def begin_transaction
  convert_exceptions do
    @@db.begin_transaction
  end
end

.convert_exceptionsObject

:nodoc:



542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/appengine-apis/datastore_types.rb', line 542

def Datastore.convert_exceptions  # :nodoc:
  begin
    yield
  rescue java.lang.IllegalArgumentException => ex
    raise ArgumentError, ex.message
  rescue java.lang.NullPointerException => ex
    raise ArgumentError, ex.message
  rescue java.util.ConcurrentModificationException => ex
    raise TransactionFailed, ex.message
  rescue java.util.NoSuchElementException => ex
    raise IndexError, ex.message
  rescue JavaDatastore::DatastoreNeedIndexException => ex
    raise NeedIndex, ex.message
  rescue JavaDatastore::DatastoreTimeoutException => ex
    raise Timeout, ex.message
  rescue JavaDatastore::DatastoreFailureException => ex
    raise InternalError, ex.message
  rescue JavaDatastore::EntityNotFoundException => ex
    raise EntityNotFound, ex.message
  rescue JavaDatastore::PreparedQuery::TooManyResultsException => ex
    raise TooManyResults, ex.message
  end
end

.current_transaction(*args) ⇒ Object

call-seq:

Datastore.current_transaction -> transaction || IndexError
Datastore.current_transaction(default) -> transaction

Returns the current transaction for this thread. The current transaction is defined as the result of the most recent, same-thread invocation of #begin_transaction that has not been committed or rolled back.

Raises IndexError if there is no current transaction and no default is specified.



174
175
176
177
178
# File 'lib/appengine-apis/datastore.rb', line 174

def current_transaction(*args)
  convert_exceptions do
    @@db.current_transaction(*args)
  end
end

.delete(*args) ⇒ Object

call-seq:

Datastore.delete(transaction=current_transaction, key)
Datastore.delete(transaction=current_transaction, [keys])

Deletes one or more entities from the datastore.

If transaction is specified this operation will execute within that transaction instead of the current transaction.



132
133
134
135
136
137
# File 'lib/appengine-apis/datastore.rb', line 132

def delete(*args)
  convert_exceptions do
    args = extract_tx(args)
    @@db.delete(*args)
  end
end

.extract_tx(args) ⇒ Object

:nodoc:



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/appengine-apis/datastore.rb', line 254

def extract_tx(args)  # :nodoc:
  tx = :none
  keys = args[0]
  if keys.java_kind_of?(JavaDatastore::Transaction) || keys.nil?
    tx = args.shift
    keys = args[0]
  end
  if args.size > 1
    keys = args
  end
  if keys.kind_of? Array
    keys = Iterable.new(keys)
  end
  if tx == :none
    [keys]
  else
    [tx, keys]
  end
end

.get(*args) ⇒ Object

call-seq:

Datastore.get(transaction=current_transaction, key) -> Entity
Datastore.get(transaction=current_transaction, [keys]) -> Entities

Retrieves one or more entities from the datastore.

Retrieves the entity or entities with the given key(s) from the datastore and returns them as fully populated Entity objects, as defined below. If there is an error, raises a subclass of Datastore::Error.

With a single key, an Entity will be returned, or EntityNotFound will be raised if no existing entity matches the key.

With an array of keys, an array of entities will be returned that corresponds to the sequence of keys. It will include entities for keys that were found and None placeholders for keys that were not found.

If transaction is specified, it will be used instead of the current transaction.



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/appengine-apis/datastore.rb', line 87

def get(*args)
  convert_exceptions do
    args = extract_tx(args)
    entities = @@db.get(*args)
    if entities.kind_of? java.util.Map
      keys = args[-1]
      entities = keys.collect do |key|
        entities.get(key)
      end
    end
    entities
  end
end

.put(*args) ⇒ Object

call-seq:

Datastore.put(transaction=current_transaction, entity) -> Key
Datastore.put(transaction=current_transaction, entities) -> Keys

Store one or more entities in the datastore.

The entities may be new or previously existing. For new entities, #put will fill in the app id and key assigned by the datastore.

If the argument is a single Entity, a single Key will be returned. If the argument is an array of Entity, an Enumerable of Keys will be returned.

If transaction is specified this operation will execute within that transaction instead of the current transaction.



116
117
118
119
120
121
# File 'lib/appengine-apis/datastore.rb', line 116

def put(*args)
  convert_exceptions do
    args = extract_tx(args)
    @@db.put(*args)
  end
end

.ruby_to_java(value) ⇒ Object

:nodoc:



525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'lib/appengine-apis/datastore_types.rb', line 525

def Datastore.ruby_to_java(value)  # :nodoc:
  if SPECIAL_RUBY_TYPES.include? value.class
    value.to_java
  else
    case value
    when Fixnum
      java.lang.Long.new(value)
    when Float
      java.lang.Double.new(value)
    when String
      java.lang.String.new(value)
    else
      value
    end
  end
end

.serviceObject

:nodoc:



274
275
276
# File 'lib/appengine-apis/datastore.rb', line 274

def service  # :nodoc:
  @@db
end

.transaction(retries = 3) ⇒ Object

Runs the block inside a transaction. Every #get, #put, and #delete call in the block is made within the transaction, unless another transaction is explicitly specified.

The block may raise any exception to roll back the transaction instead of committing it. If this happens, the transaction will be rolled back and the exception will be re-raised up to #transaction’s caller.

If you want to roll back intentionally, but don’t have an appropriate exception to raise, you can raise an instance of Datastore::Rollback. It will cause a rollback, but will not be re-raised up to the caller.

If retries is greater than 0 and the transaction fails to commit, the block may be run more than once, so it should be idempotent. It should avoid side effects, and it shouldn’t have any side effects that aren’t safe to occur multiple times. However, this doesn’t include Put, Get, and Delete calls, of course.

Raises:



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/appengine-apis/datastore.rb', line 207

def transaction(retries=3)
  while retries >= 0
    retries -= 1
    tx = begin_transaction
    begin
      convert_exceptions do
        result = yield
        tx.commit
        return result
      end
    rescue Rollback
      convert_exceptions do
        tx.rollback
        return nil
      end
    rescue TransactionFailed => ex
      raise ex unless retries >= 0
    ensure
      begin
        convert_exceptions do
          tx.rollback
        end
      rescue java.lang.IllegalStateException
        # already commited/rolled back. ignore
      rescue java.util.NoSuchElementException
        # already commited/rolled back. ignore
      end
    end
  end
  raise TransactionFailed
end