activerecord-datastore-adapter 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
 - data/Gemfile +7 -0
 - data/Gemfile.lock +53 -0
 - data/README.textile +38 -0
 - data/Rakefile +9 -0
 - data/activerecord-datastore-adapter.gemspec +25 -0
 - data/examples/rails3.rb +71 -0
 - data/examples/rails3_local.rb +81 -0
 - data/lib/active_record/connection_adapters/datastore_adapter.rb +266 -0
 - data/lib/active_record/datastore_associations_patch.rb +65 -0
 - data/lib/arel/visitors/datastore.rb +144 -0
 - data/spec/create_table_spec.rb +15 -0
 - data/spec/datatypes_spec.rb +43 -0
 - data/spec/operators_spec.rb +29 -0
 - data/spec/query_spec.rb +81 -0
 - data/spec/relations_spec.rb +38 -0
 - data/spec/spec_helper.rb +97 -0
 - data/spec/table_schema.rb +40 -0
 - metadata +108 -0
 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/Gemfile.lock
    ADDED
    
    | 
         @@ -0,0 +1,53 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            PATH
         
     | 
| 
      
 2 
     | 
    
         
            +
              remote: .
         
     | 
| 
      
 3 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 4 
     | 
    
         
            +
                activerecord-datastore-adapter (0.0.1)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  activerecord (>= 3.0.3)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  appengine-apis (= 0.0.22)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  arel (>= 2.0.7)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            GEM
         
     | 
| 
      
 10 
     | 
    
         
            +
              remote: http://rubygems.org/
         
     | 
| 
      
 11 
     | 
    
         
            +
              specs:
         
     | 
| 
      
 12 
     | 
    
         
            +
                activemodel (3.0.5)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  activesupport (= 3.0.5)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  builder (~> 2.1.2)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  i18n (~> 0.4)
         
     | 
| 
      
 16 
     | 
    
         
            +
                activerecord (3.0.5)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  activemodel (= 3.0.5)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  activesupport (= 3.0.5)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  arel (~> 2.0.2)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  tzinfo (~> 0.3.23)
         
     | 
| 
      
 21 
     | 
    
         
            +
                activesupport (3.0.5)
         
     | 
| 
      
 22 
     | 
    
         
            +
                appengine-apis (0.0.22)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  appengine-rack
         
     | 
| 
      
 24 
     | 
    
         
            +
                appengine-rack (0.0.12)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  jruby-jars (>= 1.5.1)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  jruby-rack (>= 1.0.1)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  rack
         
     | 
| 
      
 28 
     | 
    
         
            +
                appengine-sdk (1.4.0)
         
     | 
| 
      
 29 
     | 
    
         
            +
                arel (2.0.9)
         
     | 
| 
      
 30 
     | 
    
         
            +
                builder (2.1.2)
         
     | 
| 
      
 31 
     | 
    
         
            +
                diff-lcs (1.1.2)
         
     | 
| 
      
 32 
     | 
    
         
            +
                i18n (0.5.0)
         
     | 
| 
      
 33 
     | 
    
         
            +
                jruby-jars (1.6.0)
         
     | 
| 
      
 34 
     | 
    
         
            +
                jruby-rack (1.0.7)
         
     | 
| 
      
 35 
     | 
    
         
            +
                rack (1.2.2)
         
     | 
| 
      
 36 
     | 
    
         
            +
                rspec (2.5.0)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  rspec-core (~> 2.5.0)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  rspec-expectations (~> 2.5.0)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  rspec-mocks (~> 2.5.0)
         
     | 
| 
      
 40 
     | 
    
         
            +
                rspec-core (2.5.1)
         
     | 
| 
      
 41 
     | 
    
         
            +
                rspec-expectations (2.5.0)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  diff-lcs (~> 1.1.2)
         
     | 
| 
      
 43 
     | 
    
         
            +
                rspec-mocks (2.5.0)
         
     | 
| 
      
 44 
     | 
    
         
            +
                tzinfo (0.3.25)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            PLATFORMS
         
     | 
| 
      
 47 
     | 
    
         
            +
              java
         
     | 
| 
      
 48 
     | 
    
         
            +
              ruby
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            DEPENDENCIES
         
     | 
| 
      
 51 
     | 
    
         
            +
              activerecord-datastore-adapter!
         
     | 
| 
      
 52 
     | 
    
         
            +
              appengine-sdk (= 1.4.0)
         
     | 
| 
      
 53 
     | 
    
         
            +
              rspec
         
     | 
    
        data/README.textile
    ADDED
    
    | 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            h1. Datastore Adapter
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ActiveRecord Adatper for AppEngine Datastore. The AppEngine Datastore is not a relational database system. So, this adapter only support some basic features. 
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            h2. Installation( under-construction )
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Use appengine-sdk (1.4.0)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            Create Rails 3 application:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            bc. rails new app_name -m http://siddick.github.com/datastore/rails3.rb
         
     | 
| 
      
 12 
     | 
    
         
            +
            cd app_name
         
     | 
| 
      
 13 
     | 
    
         
            +
            appcfg.rb run bin/rails g scaffold post title:string content:text  
         
     | 
| 
      
 14 
     | 
    
         
            +
            appcfg.rb run bin/rake db:migrate
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            Run the server:
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            bc. dev_appserver.rb .
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            h2. Supported Features
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            # has_many and belongs_to
         
     | 
| 
      
 23 
     | 
    
         
            +
            # migration
         
     | 
| 
      
 24 
     | 
    
         
            +
            # table indexes
         
     | 
| 
      
 25 
     | 
    
         
            +
            # operators( =, >, >=, <=, <>, in, and )
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            h2. Not Supported
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            Datastore is not a Relational Database system. So, you can't expect more.
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            # Joins
         
     | 
| 
      
 32 
     | 
    
         
            +
            # operators( or, between, like, etc )
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            h2. Bugs
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            Please report the bugs.
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            https://github.com/siddick/datastore/issues
         
     | 
    
        data/Rakefile
    ADDED
    
    
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # -*- encoding: utf-8 -*-
         
     | 
| 
      
 2 
     | 
    
         
            +
            $:.push File.expand_path("../lib", __FILE__)
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Gem::Specification.new do |s|
         
     | 
| 
      
 5 
     | 
    
         
            +
              s.name        = "activerecord-datastore-adapter"
         
     | 
| 
      
 6 
     | 
    
         
            +
              s.version     = "0.0.1"
         
     | 
| 
      
 7 
     | 
    
         
            +
              s.platform    = Gem::Platform::RUBY
         
     | 
| 
      
 8 
     | 
    
         
            +
              s.authors     = ["Mohammed Siddick"]
         
     | 
| 
      
 9 
     | 
    
         
            +
              s.email       = ["siddick@gmail.com"]
         
     | 
| 
      
 10 
     | 
    
         
            +
              s.homepage    = "http://rubygems.org/gems/datastore"
         
     | 
| 
      
 11 
     | 
    
         
            +
              s.summary     = %q{ActiveRecord Adapter for Appengine Datastore}
         
     | 
| 
      
 12 
     | 
    
         
            +
              s.description = %q{Just an ActiveRecord Adapter for the Appengine Datastore. 
         
     | 
| 
      
 13 
     | 
    
         
            +
                Create Rails3 application: rails new app_name -m http://siddick.github.com/datastore/rails3.rb}
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              s.rubyforge_project = "activerecord-datastore-adapter"
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              s.files         = `git ls-files`.split("\n")
         
     | 
| 
      
 18 
     | 
    
         
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         
     | 
| 
      
 19 
     | 
    
         
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
      
 20 
     | 
    
         
            +
              s.require_paths = ["lib"]
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              s.add_dependency( 'appengine-apis', '0.0.22' )
         
     | 
| 
      
 23 
     | 
    
         
            +
              s.add_dependency( 'activerecord', '>= 3.0.3' )
         
     | 
| 
      
 24 
     | 
    
         
            +
              s.add_dependency( 'arel', '>= 2.0.7' )
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
    
        data/examples/rails3.rb
    ADDED
    
    | 
         @@ -0,0 +1,71 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            remove_file 'Gemfile'
         
     | 
| 
      
 3 
     | 
    
         
            +
            create_file 'Gemfile' do
         
     | 
| 
      
 4 
     | 
    
         
            +
            <<-GEMFILE
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            disable_system_gems
         
     | 
| 
      
 7 
     | 
    
         
            +
            disable_rubygems
         
     | 
| 
      
 8 
     | 
    
         
            +
            bundle_path ".gems/bundler_gems"
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            gem 'rails', '~> 3.0.5'
         
     | 
| 
      
 11 
     | 
    
         
            +
            gem 'activerecord-datastore-adapter'
         
     | 
| 
      
 12 
     | 
    
         
            +
            gem 'jruby-rack', '1.0.5'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            GEMFILE
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            remove_file 'config/boot.rb'
         
     | 
| 
      
 18 
     | 
    
         
            +
            create_file 'config/boot.rb' do
         
     | 
| 
      
 19 
     | 
    
         
            +
            <<-BOOT
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            String.class_eval do
         
     | 
| 
      
 22 
     | 
    
         
            +
              alias :old_plus :+
         
     | 
| 
      
 23 
     | 
    
         
            +
              def +( val )
         
     | 
| 
      
 24 
     | 
    
         
            +
                if( val.is_a? Array )
         
     | 
| 
      
 25 
     | 
    
         
            +
                  [ self ] + val
         
     | 
| 
      
 26 
     | 
    
         
            +
                else
         
     | 
| 
      
 27 
     | 
    
         
            +
                  old_plus val
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
            end
         
     | 
| 
      
 31 
     | 
    
         
            +
            BOOT
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            remove_file 'config/database.yml'
         
     | 
| 
      
 36 
     | 
    
         
            +
            create_file 'config/database.yml' do
         
     | 
| 
      
 37 
     | 
    
         
            +
            <<-DATABASE
         
     | 
| 
      
 38 
     | 
    
         
            +
            development:
         
     | 
| 
      
 39 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 40 
     | 
    
         
            +
              database: db/database.yml
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            test:
         
     | 
| 
      
 43 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 44 
     | 
    
         
            +
              database: db/test.yml
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
            production:
         
     | 
| 
      
 47 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 48 
     | 
    
         
            +
              database: db/database.yml
         
     | 
| 
      
 49 
     | 
    
         
            +
            DATABASE
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            gsub_file 'config/application.rb', /Bundler/ do
         
     | 
| 
      
 53 
     | 
    
         
            +
                "# Bundler"
         
     | 
| 
      
 54 
     | 
    
         
            +
            end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            gsub_file 'config/application.rb', /class Application < Rails::Application$/ do
         
     | 
| 
      
 57 
     | 
    
         
            +
              "class Application < Rails::Application
         
     | 
| 
      
 58 
     | 
    
         
            +
                  require 'appengine-apis/logger'
         
     | 
| 
      
 59 
     | 
    
         
            +
                  config.logger = AppEngine::Logger.new
         
     | 
| 
      
 60 
     | 
    
         
            +
              "
         
     | 
| 
      
 61 
     | 
    
         
            +
            end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            create_file 'config/initializers/cache_store.rb' do
         
     | 
| 
      
 64 
     | 
    
         
            +
            <<-CACHE_STORE
         
     | 
| 
      
 65 
     | 
    
         
            +
            #require 'appengine-apis/memcache'
         
     | 
| 
      
 66 
     | 
    
         
            +
            #ActionController::Base.cache_store = AppEngine::Memcache.new
         
     | 
| 
      
 67 
     | 
    
         
            +
            CACHE_STORE
         
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
            system "appcfg.rb generate_app ."
         
     | 
| 
         @@ -0,0 +1,81 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
             
     | 
| 
      
 2 
     | 
    
         
            +
            remove_file 'Gemfile'
         
     | 
| 
      
 3 
     | 
    
         
            +
            create_file 'Gemfile' do
         
     | 
| 
      
 4 
     | 
    
         
            +
            <<-GEMFILE
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            disable_system_gems
         
     | 
| 
      
 7 
     | 
    
         
            +
            disable_rubygems
         
     | 
| 
      
 8 
     | 
    
         
            +
            bundle_path ".gems/bundler_gems"
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            gem 'rails', '~> 3.0.5'
         
     | 
| 
      
 11 
     | 
    
         
            +
            gem 'appengine-apis', '>= 0.0.22'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            GEMFILE
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            remove_file 'config/boot.rb'
         
     | 
| 
      
 17 
     | 
    
         
            +
            create_file 'config/boot.rb' do
         
     | 
| 
      
 18 
     | 
    
         
            +
            <<-BOOT
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
            String.class_eval do
         
     | 
| 
      
 21 
     | 
    
         
            +
              alias :old_plus :+
         
     | 
| 
      
 22 
     | 
    
         
            +
              def +( val )
         
     | 
| 
      
 23 
     | 
    
         
            +
                if( val.is_a? Array )
         
     | 
| 
      
 24 
     | 
    
         
            +
                  [ self ] + val
         
     | 
| 
      
 25 
     | 
    
         
            +
                else
         
     | 
| 
      
 26 
     | 
    
         
            +
                  old_plus val
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            File.class_eval do
         
     | 
| 
      
 32 
     | 
    
         
            +
              class << self
         
     | 
| 
      
 33 
     | 
    
         
            +
                alias :old_expand_path :expand_path
         
     | 
| 
      
 34 
     | 
    
         
            +
                def expand_path( *args )
         
     | 
| 
      
 35 
     | 
    
         
            +
                  fn = old_expand_path( *args )
         
     | 
| 
      
 36 
     | 
    
         
            +
                  fn.sub(/^.*file:/, 'file:') if fn
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
            end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            $LOAD_PATH.push( '../../lib' )
         
     | 
| 
      
 42 
     | 
    
         
            +
            BOOT
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            remove_file 'config/database.yml'
         
     | 
| 
      
 46 
     | 
    
         
            +
            create_file 'config/database.yml' do
         
     | 
| 
      
 47 
     | 
    
         
            +
            <<-DATABASE
         
     | 
| 
      
 48 
     | 
    
         
            +
            development:
         
     | 
| 
      
 49 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 50 
     | 
    
         
            +
              database: development.yml
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            test:
         
     | 
| 
      
 53 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 54 
     | 
    
         
            +
              database: test.yml
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            production:
         
     | 
| 
      
 57 
     | 
    
         
            +
              adapter: datastore
         
     | 
| 
      
 58 
     | 
    
         
            +
              database: development.yml
         
     | 
| 
      
 59 
     | 
    
         
            +
            DATABASE
         
     | 
| 
      
 60 
     | 
    
         
            +
            end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
            gsub_file 'config/application.rb', /Bundler/ do
         
     | 
| 
      
 63 
     | 
    
         
            +
                "# Bundler"
         
     | 
| 
      
 64 
     | 
    
         
            +
            end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            gsub_file 'config/application.rb', /class Application < Rails::Application$/ do
         
     | 
| 
      
 67 
     | 
    
         
            +
              "class Application < Rails::Application
         
     | 
| 
      
 68 
     | 
    
         
            +
                  require 'appengine-apis/logger'
         
     | 
| 
      
 69 
     | 
    
         
            +
                  config.logger = AppEngine::Logger.new
         
     | 
| 
      
 70 
     | 
    
         
            +
              "
         
     | 
| 
      
 71 
     | 
    
         
            +
            end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
            create_file 'config/initializers/cache_store.rb' do
         
     | 
| 
      
 74 
     | 
    
         
            +
            <<-CACHE_STORE
         
     | 
| 
      
 75 
     | 
    
         
            +
            #require 'appengine-apis/memcache'
         
     | 
| 
      
 76 
     | 
    
         
            +
            #ActionController::Base.cache_store = AppEngine::Memcache.new
         
     | 
| 
      
 77 
     | 
    
         
            +
            CACHE_STORE
         
     | 
| 
      
 78 
     | 
    
         
            +
            end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            system "appcfg.rb generate_app ."
         
     | 
| 
         @@ -0,0 +1,266 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_record/connection_adapters/abstract_adapter'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_support/core_ext/kernel/requires'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'active_support/core_ext/object/blank'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Patch
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'active_record/datastore_associations_patch'
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'arel/visitors/datastore'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            module ActiveRecord
         
     | 
| 
      
 13 
     | 
    
         
            +
              class Base
         
     | 
| 
      
 14 
     | 
    
         
            +
                def self.datastore_connection(config) # :nodoc:
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ConnectionAdapters::DatastoreAdapter.new( ConnectionAdapters::DatastoreAdapter::DB.new( config.symbolize_keys ), logger )
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              module ConnectionAdapters
         
     | 
| 
      
 20 
     | 
    
         
            +
                class DatastoreAdapter < AbstractAdapter
         
     | 
| 
      
 21 
     | 
    
         
            +
                  ADAPTER_NAME = "Datastore"
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def adapter_name #:nodoc:
         
     | 
| 
      
 24 
     | 
    
         
            +
                    ADAPTER_NAME
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                  
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def supports_migrations? #:nodoc:
         
     | 
| 
      
 28 
     | 
    
         
            +
                    true
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def supports_primary_key? #:nodoc:
         
     | 
| 
      
 32 
     | 
    
         
            +
                    true
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def supports_autoincrement? #:nodoc:
         
     | 
| 
      
 36 
     | 
    
         
            +
                    true
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def select( sql, name = nil, binds = [] )
         
     | 
| 
      
 40 
     | 
    
         
            +
                    log( sql.inspect, name ) {
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @connection.select_query( sql.q, sql.options )
         
     | 
| 
      
 42 
     | 
    
         
            +
                    }
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def select_rows(sql, name = nil)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    select(sql, name).map{|r| r.map{|k,v| v } }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    log( "Insert: " + sql.inspect, name ){
         
     | 
| 
      
 51 
     | 
    
         
            +
                      @connection.insert_query( sql )
         
     | 
| 
      
 52 
     | 
    
         
            +
                    }
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def update( sql, name = nil)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    log( "Update: VALUES(#{sql.options[:values].collect{|k,v|k.to_s + " = " + v.inspect}.join(", ")}) " + sql.inspect, name ) {
         
     | 
| 
      
 57 
     | 
    
         
            +
                      @connection.update_query( sql.q, sql.options[:values] )
         
     | 
| 
      
 58 
     | 
    
         
            +
                    }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  
         
     | 
| 
      
 61 
     | 
    
         
            +
                  def delete(sql, name = nil)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    log( "Delete: " + sql.inspect, name ) {
         
     | 
| 
      
 63 
     | 
    
         
            +
                      @connection.delete_query( sql.q )
         
     | 
| 
      
 64 
     | 
    
         
            +
                    }
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  def execute(sql, name = nil)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    log("Not Support: " + sql, name) {
         
     | 
| 
      
 70 
     | 
    
         
            +
                      #@connection.execute( sql )
         
     | 
| 
      
 71 
     | 
    
         
            +
                    } 
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def create_table( table_name, options = {} )
         
     | 
| 
      
 75 
     | 
    
         
            +
                    log( "CREATE TABLE #{table_name}", "Datastore Adapter" ) {
         
     | 
| 
      
 76 
     | 
    
         
            +
                      td = TableDefinition.new(self)
         
     | 
| 
      
 77 
     | 
    
         
            +
                      td.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                      yield td if block_given?
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      fields = {}
         
     | 
| 
      
 82 
     | 
    
         
            +
                      td.columns.each{|c| fields[c.name.to_s] = { "default" => c.default, "type" => c.type.to_s, "null" => c.null } }
         
     | 
| 
      
 83 
     | 
    
         
            +
                      @connection.create_table( table_name, fields )
         
     | 
| 
      
 84 
     | 
    
         
            +
                      td
         
     | 
| 
      
 85 
     | 
    
         
            +
                    }
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  def drop_table( tname, options = {} )
         
     | 
| 
      
 89 
     | 
    
         
            +
                    @connection.drop_table( tname )
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  def rename_table( tname, ntname )
         
     | 
| 
      
 93 
     | 
    
         
            +
                    @connection.drop_table( tname, ntname )
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  def add_column(table_name, column_name, type, options = {})
         
     | 
| 
      
 97 
     | 
    
         
            +
                    @connection.add_column( table_name, column_name, type, options )
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  alias :change_column :add_column
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  def add_index(table_name, column_name, options = {})
         
     | 
| 
      
 103 
     | 
    
         
            +
                    @connection.add_index( table_name, column_name, options )
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  def remove_index(table_name, column_name )
         
     | 
| 
      
 107 
     | 
    
         
            +
                    @connection.remove_index( table_name, column_name )
         
     | 
| 
      
 108 
     | 
    
         
            +
                  end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                  def tables
         
     | 
| 
      
 111 
     | 
    
         
            +
                    @connection.tables.keys
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  def columns( table_name, name = nil)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    @connection.columns( table_name, name ).collect{|k,opt|
         
     | 
| 
      
 116 
     | 
    
         
            +
                      is_primary = opt["type"] == "primary_key"
         
     | 
| 
      
 117 
     | 
    
         
            +
                      c = Column.new( k, opt["default"], is_primary ? "integer" : opt["type"].to_s, opt["null"] )
         
     | 
| 
      
 118 
     | 
    
         
            +
                      c.primary = true if is_primary
         
     | 
| 
      
 119 
     | 
    
         
            +
                      c
         
     | 
| 
      
 120 
     | 
    
         
            +
                    } 
         
     | 
| 
      
 121 
     | 
    
         
            +
                  end
         
     | 
| 
      
 122 
     | 
    
         
            +
                  
         
     | 
| 
      
 123 
     | 
    
         
            +
                  def primary_key( table_name )
         
     | 
| 
      
 124 
     | 
    
         
            +
                    column = @connection.columns( table_name ).find{|k,opt|
         
     | 
| 
      
 125 
     | 
    
         
            +
                      opt["type"] == "primary_key"
         
     | 
| 
      
 126 
     | 
    
         
            +
                    }
         
     | 
| 
      
 127 
     | 
    
         
            +
                    column ? column[0] : nil
         
     | 
| 
      
 128 
     | 
    
         
            +
                  end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  class DB
         
     | 
| 
      
 131 
     | 
    
         
            +
                    def initialize( config )
         
     | 
| 
      
 132 
     | 
    
         
            +
                      @config = { :database => 'database.yaml', :index => 'index.yaml', :namespace => 'dev' }.merge( config )
         
     | 
| 
      
 133 
     | 
    
         
            +
                      if( @config[:database] and File.exist? @config[:database] )
         
     | 
| 
      
 134 
     | 
    
         
            +
                        @tables = YAML.load( File.open( @config[:database], "r" ) )
         
     | 
| 
      
 135 
     | 
    
         
            +
                      else
         
     | 
| 
      
 136 
     | 
    
         
            +
                        @tables = {}
         
     | 
| 
      
 137 
     | 
    
         
            +
                      end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                      if( @config[:index] and File.exist? @config[:index] )
         
     | 
| 
      
 140 
     | 
    
         
            +
                        @indexes = YAML.load( File.open( @config[:index], "r" ) )
         
     | 
| 
      
 141 
     | 
    
         
            +
                        @indexes = @indexes[:indexes] || []
         
     | 
| 
      
 142 
     | 
    
         
            +
                      else
         
     | 
| 
      
 143 
     | 
    
         
            +
                        @indexes = []
         
     | 
| 
      
 144 
     | 
    
         
            +
                      end
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                    def create_table( tname, fields )
         
     | 
| 
      
 148 
     | 
    
         
            +
                      @tables[tname] = fields
         
     | 
| 
      
 149 
     | 
    
         
            +
                      save_schema
         
     | 
| 
      
 150 
     | 
    
         
            +
                    end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                    def drop_table( tname, options = {} )
         
     | 
| 
      
 153 
     | 
    
         
            +
                      @tables.delete(tname)
         
     | 
| 
      
 154 
     | 
    
         
            +
                      save_schema
         
     | 
| 
      
 155 
     | 
    
         
            +
                    end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    def rename_table( tname, ntname )
         
     | 
| 
      
 158 
     | 
    
         
            +
                      value = @tables.delete(tname)
         
     | 
| 
      
 159 
     | 
    
         
            +
                      if( value )
         
     | 
| 
      
 160 
     | 
    
         
            +
                        @tables[ntname] = value 
         
     | 
| 
      
 161 
     | 
    
         
            +
                        save_schema
         
     | 
| 
      
 162 
     | 
    
         
            +
                      end
         
     | 
| 
      
 163 
     | 
    
         
            +
                    end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                    def add_column(table_name, column_name, type, options = {})
         
     | 
| 
      
 166 
     | 
    
         
            +
                      @tables[table_name][column_name] = { "type" => type.to_s, "default" => options[:default], "null" => options[:null] }
         
     | 
| 
      
 167 
     | 
    
         
            +
                      save_schema
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    alias :change_column :add_column
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    def add_index(table_name, column_name, options = {})
         
     | 
| 
      
 173 
     | 
    
         
            +
                      table_name  = table_name.to_s
         
     | 
| 
      
 174 
     | 
    
         
            +
                      column_name = [ column_name ] unless column_name.is_a? Array
         
     | 
| 
      
 175 
     | 
    
         
            +
                      column_name.map!{|c| c.to_s }
         
     | 
| 
      
 176 
     | 
    
         
            +
                      inds = @indexes.find_all{|i| i["kind"] == table_name and i["properties"].map{|p| p["name"] } == column_name }
         
     | 
| 
      
 177 
     | 
    
         
            +
                      if inds.empty?
         
     | 
| 
      
 178 
     | 
    
         
            +
                        @indexes.push( { "kind" => table_name, "properties" => column_name.map{|c| { "name" => c } } } )
         
     | 
| 
      
 179 
     | 
    
         
            +
                        save_indexes
         
     | 
| 
      
 180 
     | 
    
         
            +
                      end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                    def remove_index(table_name, column_name )
         
     | 
| 
      
 184 
     | 
    
         
            +
                      table_name  = table_name.to_s
         
     | 
| 
      
 185 
     | 
    
         
            +
                      column_name = column_name[:column] if column_name.is_a? Hash
         
     | 
| 
      
 186 
     | 
    
         
            +
                      column_name = [ column_name ] unless column_name.is_a? Array
         
     | 
| 
      
 187 
     | 
    
         
            +
                      column_name.map!{|c| c.to_s }
         
     | 
| 
      
 188 
     | 
    
         
            +
                      inds = @indexes.delete_all{|i| i["kind"] == table_name and i["properties"].map{|p| p["name"] } == column_name }
         
     | 
| 
      
 189 
     | 
    
         
            +
                      save_indexes
         
     | 
| 
      
 190 
     | 
    
         
            +
                    end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                    def save_indexes
         
     | 
| 
      
 193 
     | 
    
         
            +
                      f = File.open( @config[:index], 'w' )
         
     | 
| 
      
 194 
     | 
    
         
            +
                      f.write( { "indexes" => @indexes }.to_yaml )
         
     | 
| 
      
 195 
     | 
    
         
            +
                      f.close
         
     | 
| 
      
 196 
     | 
    
         
            +
                    end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                    def save_schema
         
     | 
| 
      
 199 
     | 
    
         
            +
                      f = File.open( @config[:database], 'w' )
         
     | 
| 
      
 200 
     | 
    
         
            +
                      f.write( @tables.to_yaml )
         
     | 
| 
      
 201 
     | 
    
         
            +
                      f.close
         
     | 
| 
      
 202 
     | 
    
         
            +
                    end
         
     | 
| 
      
 203 
     | 
    
         
            +
                    
         
     | 
| 
      
 204 
     | 
    
         
            +
                    def tables
         
     | 
| 
      
 205 
     | 
    
         
            +
                      @tables
         
     | 
| 
      
 206 
     | 
    
         
            +
                    end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                    def columns( table_name, name = nil )
         
     | 
| 
      
 209 
     | 
    
         
            +
                      if tables[table_name]
         
     | 
| 
      
 210 
     | 
    
         
            +
                        tables[table_name]
         
     | 
| 
      
 211 
     | 
    
         
            +
                      end
         
     | 
| 
      
 212 
     | 
    
         
            +
                    end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                    def primary_key( tname )
         
     | 
| 
      
 215 
     | 
    
         
            +
                      'id'
         
     | 
| 
      
 216 
     | 
    
         
            +
                    end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                    def select_query( q, options = {} )
         
     | 
| 
      
 219 
     | 
    
         
            +
                      output = []
         
     | 
| 
      
 220 
     | 
    
         
            +
                      if( options[:empty] )
         
     | 
| 
      
 221 
     | 
    
         
            +
                        []
         
     | 
| 
      
 222 
     | 
    
         
            +
                      elsif( options[:count] )
         
     | 
| 
      
 223 
     | 
    
         
            +
                        output.push( { "count" => q.count() } )
         
     | 
| 
      
 224 
     | 
    
         
            +
                      else
         
     | 
| 
      
 225 
     | 
    
         
            +
                        t_name = q.kind
         
     | 
| 
      
 226 
     | 
    
         
            +
                        p_key  = primary_key( t_name )
         
     | 
| 
      
 227 
     | 
    
         
            +
                        column_list = columns( t_name )  
         
     | 
| 
      
 228 
     | 
    
         
            +
                        q.fetch(options).each{|e| 
         
     | 
| 
      
 229 
     | 
    
         
            +
                          h = {}
         
     | 
| 
      
 230 
     | 
    
         
            +
                          column_list.each{|n,opt|
         
     | 
| 
      
 231 
     | 
    
         
            +
                            h[n] = ( n == p_key ? e.key.id : e[n] )
         
     | 
| 
      
 232 
     | 
    
         
            +
                          }
         
     | 
| 
      
 233 
     | 
    
         
            +
                          output.push( h )
         
     | 
| 
      
 234 
     | 
    
         
            +
                        }
         
     | 
| 
      
 235 
     | 
    
         
            +
                      end
         
     | 
| 
      
 236 
     | 
    
         
            +
                      output
         
     | 
| 
      
 237 
     | 
    
         
            +
                    end
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                    def insert_query( q )
         
     | 
| 
      
 240 
     | 
    
         
            +
                      AppEngine::Datastore.put q
         
     | 
| 
      
 241 
     | 
    
         
            +
                      q.key.id
         
     | 
| 
      
 242 
     | 
    
         
            +
                    end
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
                    def update_query( q, values = nil )
         
     | 
| 
      
 245 
     | 
    
         
            +
                      if( values and values.size > 0 )
         
     | 
| 
      
 246 
     | 
    
         
            +
                        entities = []
         
     | 
| 
      
 247 
     | 
    
         
            +
                        q.each{|e|
         
     | 
| 
      
 248 
     | 
    
         
            +
                          values.each{|k,v| e[k] = v }
         
     | 
| 
      
 249 
     | 
    
         
            +
                          entities.push(e)
         
     | 
| 
      
 250 
     | 
    
         
            +
                        }
         
     | 
| 
      
 251 
     | 
    
         
            +
                        AppEngine::Datastore.put entities 
         
     | 
| 
      
 252 
     | 
    
         
            +
                      end
         
     | 
| 
      
 253 
     | 
    
         
            +
                    end
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                    def delete_query( q )
         
     | 
| 
      
 256 
     | 
    
         
            +
                      keys = []
         
     | 
| 
      
 257 
     | 
    
         
            +
                      q.each{|e| keys.push e.key }
         
     | 
| 
      
 258 
     | 
    
         
            +
                      AppEngine::Datastore.delete keys
         
     | 
| 
      
 259 
     | 
    
         
            +
                    end
         
     | 
| 
      
 260 
     | 
    
         
            +
                  end
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
                end
         
     | 
| 
      
 263 
     | 
    
         
            +
              end
         
     | 
| 
      
 264 
     | 
    
         
            +
            end
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,65 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'active_record/associations'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'active_record/associations/has_many_association'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'active_record/associations/has_many_through_association'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ActiveRecord::Associations::HasManyAssociation.class_eval do
         
     | 
| 
      
 6 
     | 
    
         
            +
              def owner_id
         
     | 
| 
      
 7 
     | 
    
         
            +
                if @reflection.options[:primary_key]
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @owner.send(@reflection.options[:primary_key])
         
     | 
| 
      
 9 
     | 
    
         
            +
                else
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @owner.id
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
              def construct_sql
         
     | 
| 
      
 15 
     | 
    
         
            +
                case
         
     | 
| 
      
 16 
     | 
    
         
            +
                when @reflection.options[:finder_sql]
         
     | 
| 
      
 17 
     | 
    
         
            +
                  @finder_sql = interpolate_sql(@reflection.options[:finder_sql])
         
     | 
| 
      
 18 
     | 
    
         
            +
                when @reflection.options[:as]
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @finder_sql = { ( @reflection.options[:as]+ "_id" ) => owner_id,
         
     | 
| 
      
 20 
     | 
    
         
            +
                    ( @reflection.options[:as] + "_type" ) => @owner.class.quote_value(@owner.class.base_class.name.to_s) }
         
     | 
| 
      
 21 
     | 
    
         
            +
                  @finder_sql.merge!( conditions ) if conditions
         
     | 
| 
      
 22 
     | 
    
         
            +
                else
         
     | 
| 
      
 23 
     | 
    
         
            +
                  @finder_sql = { @reflection.primary_key_name => owner_id }
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @finder_sql.merge!( conditions ) if conditions
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                construct_counter_sql
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            ActiveRecord::Associations::HasManyThroughAssociation.class_eval do
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              def owner_id
         
     | 
| 
      
 34 
     | 
    
         
            +
                if @reflection.options[:primary_key]
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @owner.send(@reflection.options[:primary_key])
         
     | 
| 
      
 36 
     | 
    
         
            +
                else
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @owner.id
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              def construct_conditions
         
     | 
| 
      
 43 
     | 
    
         
            +
                if @reflection.source_reflection.macro == :belongs_to
         
     | 
| 
      
 44 
     | 
    
         
            +
                  source_primary_key = @reflection.source_reflection.primary_key_name
         
     | 
| 
      
 45 
     | 
    
         
            +
                else
         
     | 
| 
      
 46 
     | 
    
         
            +
                  source_primary_key = @reflection.through_reflection.klass.primary_key
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
                ids = @owner.send(@reflection.options[:through]).map{|t| t.send(source_primary_key) }
         
     | 
| 
      
 49 
     | 
    
         
            +
                conditions = { :id => ids }
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              def construct_scope
         
     | 
| 
      
 54 
     | 
    
         
            +
                { :create => construct_owner_attributes(@reflection),
         
     | 
| 
      
 55 
     | 
    
         
            +
                  :find   => { :conditions  => construct_conditions,
         
     | 
| 
      
 56 
     | 
    
         
            +
            #        :joins       => construct_joins,
         
     | 
| 
      
 57 
     | 
    
         
            +
                    :include     => @reflection.options[:include] || @reflection.source_reflection.options[:include],
         
     | 
| 
      
 58 
     | 
    
         
            +
                    :select      => construct_select,
         
     | 
| 
      
 59 
     | 
    
         
            +
                    :order       => @reflection.options[:order],
         
     | 
| 
      
 60 
     | 
    
         
            +
                    :limit       => @reflection.options[:limit],
         
     | 
| 
      
 61 
     | 
    
         
            +
                    :readonly    => @reflection.options[:readonly],
         
     | 
| 
      
 62 
     | 
    
         
            +
                } }
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,144 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'arel'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'arel/visitors'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'arel/visitors/to_sql'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'appengine-apis/datastore'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            module Arel
         
     | 
| 
      
 7 
     | 
    
         
            +
              module Visitors
         
     | 
| 
      
 8 
     | 
    
         
            +
                class Datastore < Arel::Visitors::ToSql
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  class QString
         
     | 
| 
      
 11 
     | 
    
         
            +
                    attr :kind
         
     | 
| 
      
 12 
     | 
    
         
            +
                    attr :q 
         
     | 
| 
      
 13 
     | 
    
         
            +
                    attr :options
         
     | 
| 
      
 14 
     | 
    
         
            +
                    attr :connection
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    def initialize( conn, kind, options = {} )
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @connection = conn
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @kind = kind
         
     | 
| 
      
 19 
     | 
    
         
            +
                      @q = AppEngine::Datastore::Query.new( kind )
         
     | 
| 
      
 20 
     | 
    
         
            +
                      @options = options
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    def to_s
         
     | 
| 
      
 24 
     | 
    
         
            +
                      out = q.inspect 
         
     | 
| 
      
 25 
     | 
    
         
            +
                      out += " OFFSET #{options[:offset]} " if options[:offset]  
         
     | 
| 
      
 26 
     | 
    
         
            +
                      out += " LIMIT  #{options[:limit]} "  if options[:limit]  
         
     | 
| 
      
 27 
     | 
    
         
            +
                      out
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    alias :inspect :to_s
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    def projections( projs )
         
     | 
| 
      
 33 
     | 
    
         
            +
                      projs.each{|p|
         
     | 
| 
      
 34 
     | 
    
         
            +
                        if( p.is_a? Arel::Nodes::Count )
         
     | 
| 
      
 35 
     | 
    
         
            +
                          options[:count] = true
         
     | 
| 
      
 36 
     | 
    
         
            +
                        end
         
     | 
| 
      
 37 
     | 
    
         
            +
                      }
         
     | 
| 
      
 38 
     | 
    
         
            +
                      self
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    def wheres( conditions )
         
     | 
| 
      
 42 
     | 
    
         
            +
                      conditions.each{|w|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        w_expr  = w.expr rescue w
         
     | 
| 
      
 44 
     | 
    
         
            +
                        if( w_expr.class != Arel::Nodes::SqlLiteral )
         
     | 
| 
      
 45 
     | 
    
         
            +
                          key     = w_expr.left.name
         
     | 
| 
      
 46 
     | 
    
         
            +
                          val     = w_expr.right
         
     | 
| 
      
 47 
     | 
    
         
            +
                          opt     = w_expr.operator
         
     | 
| 
      
 48 
     | 
    
         
            +
                          apply_filter( key, opt, val )
         
     | 
| 
      
 49 
     | 
    
         
            +
                        else
         
     | 
| 
      
 50 
     | 
    
         
            +
                          parese_expression_string( w_expr.to_s )
         
     | 
| 
      
 51 
     | 
    
         
            +
                        end
         
     | 
| 
      
 52 
     | 
    
         
            +
                      }
         
     | 
| 
      
 53 
     | 
    
         
            +
                      self
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    TypeCast = {
         
     | 
| 
      
 57 
     | 
    
         
            +
                      :primary_key => lambda{|k,v| AppEngine::Datastore::Key.from_path( k, v.to_i ) },
         
     | 
| 
      
 58 
     | 
    
         
            +
                      :integer     => lambda{|k,i| i.to_i },
         
     | 
| 
      
 59 
     | 
    
         
            +
                      :datetime    => lambda{|k,t| t.is_a?(Time)? t : Time.parse(t.to_s) },
         
     | 
| 
      
 60 
     | 
    
         
            +
                      :date        => lambda{|k,t| t.is_a?(Date)? t : Date.parse(t.to_s) },
         
     | 
| 
      
 61 
     | 
    
         
            +
                      :float       => lambda{|k,f| f.to_f }
         
     | 
| 
      
 62 
     | 
    
         
            +
                    }
         
     | 
| 
      
 63 
     | 
    
         
            +
                    InScan = /'((\\.|[^'])*)'|(\d+)/
         
     | 
| 
      
 64 
     | 
    
         
            +
                    def apply_filter( key, opt, value )
         
     | 
| 
      
 65 
     | 
    
         
            +
                      key, opt = key.to_sym, opt.to_sym
         
     | 
| 
      
 66 
     | 
    
         
            +
                      column = @connection.columns(kind).find{|c| c.name == key.to_s }
         
     | 
| 
      
 67 
     | 
    
         
            +
                      opt = :in      if value.is_a? Array
         
     | 
| 
      
 68 
     | 
    
         
            +
                      type_cast_proc = TypeCast[ column.primary ? :primary_key : column.type ]
         
     | 
| 
      
 69 
     | 
    
         
            +
                      if opt == :in or opt == :IN
         
     | 
| 
      
 70 
     | 
    
         
            +
                        value = value.scan(InScan).collect{|d| d.find{|i| i}}   if value.is_a? String
         
     | 
| 
      
 71 
     | 
    
         
            +
                        value.collect!{|v| type_cast_proc.call(kind,v) }        if type_cast_proc
         
     | 
| 
      
 72 
     | 
    
         
            +
                        options[:empty], value = true, [ "EMPTY" ]              if value.empty?
         
     | 
| 
      
 73 
     | 
    
         
            +
                      else
         
     | 
| 
      
 74 
     | 
    
         
            +
                        value = type_cast_proc.call( kind, value ) if type_cast_proc
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
                      key = :__key__ if column.primary
         
     | 
| 
      
 77 
     | 
    
         
            +
                      q.filter( key, opt, value )
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    
         
     | 
| 
      
 81 
     | 
    
         
            +
                    RExpr = Regexp.union( /(in)/i,
         
     | 
| 
      
 82 
     | 
    
         
            +
                                 /\(\s*(('((\\.|[^'])*)'|\d+)(\s*,\s*('((\\.|[^'])*)'|\d+))*)\s*\)/,
         
     | 
| 
      
 83 
     | 
    
         
            +
                                 /"((\\.|[^"])*)"/,
         
     | 
| 
      
 84 
     | 
    
         
            +
                                 /'((\\.|[^'])*)'/,
         
     | 
| 
      
 85 
     | 
    
         
            +
                                 /([\w\.]+)/,
         
     | 
| 
      
 86 
     | 
    
         
            +
                                 /([^\w\s\.'"]+)/ )
         
     | 
| 
      
 87 
     | 
    
         
            +
                    Optr      = { "=" => :== }
         
     | 
| 
      
 88 
     | 
    
         
            +
                    ExOptr    = ["(",")"]
         
     | 
| 
      
 89 
     | 
    
         
            +
                    def parese_expression_string( query )
         
     | 
| 
      
 90 
     | 
    
         
            +
                      datas = query.scan( RExpr ).collect{|a| a.find{|i| i } }
         
     | 
| 
      
 91 
     | 
    
         
            +
                      datas.delete_if{|d| ExOptr.include?(d) }
         
     | 
| 
      
 92 
     | 
    
         
            +
                      while( datas.size >= 3 )
         
     | 
| 
      
 93 
     | 
    
         
            +
                        key = datas.shift.sub(/^[^.]*\./,'').to_sym
         
     | 
| 
      
 94 
     | 
    
         
            +
                        opt = datas.shift
         
     | 
| 
      
 95 
     | 
    
         
            +
                        val = datas.shift
         
     | 
| 
      
 96 
     | 
    
         
            +
                        concat_opt = datas.shift
         
     | 
| 
      
 97 
     | 
    
         
            +
                        apply_filter( key, Optr[opt] || opt.to_sym, val )
         
     | 
| 
      
 98 
     | 
    
         
            +
                      end
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    def orders( ords )
         
     | 
| 
      
 102 
     | 
    
         
            +
                      ords.each{|o|
         
     | 
| 
      
 103 
     | 
    
         
            +
                        if( o.is_a? String )
         
     | 
| 
      
 104 
     | 
    
         
            +
                          key, dir, notuse = o.split
         
     | 
| 
      
 105 
     | 
    
         
            +
                        else
         
     | 
| 
      
 106 
     | 
    
         
            +
                          key, dir = o.expr, o.direction
         
     | 
| 
      
 107 
     | 
    
         
            +
                        end
         
     | 
| 
      
 108 
     | 
    
         
            +
                        q.sort( key, dir )
         
     | 
| 
      
 109 
     | 
    
         
            +
                      }
         
     | 
| 
      
 110 
     | 
    
         
            +
                      self
         
     | 
| 
      
 111 
     | 
    
         
            +
                    end
         
     | 
| 
      
 112 
     | 
    
         
            +
                  end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  def get_limit_and_offset( o )
         
     | 
| 
      
 115 
     | 
    
         
            +
                    options = {}
         
     | 
| 
      
 116 
     | 
    
         
            +
                    options[:limit]  = o.limit.expr if o.limit
         
     | 
| 
      
 117 
     | 
    
         
            +
                    options[:offset] = o.offset.expr if o.offset
         
     | 
| 
      
 118 
     | 
    
         
            +
                    options
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                  def visit_Arel_Nodes_SelectStatement o
         
     | 
| 
      
 122 
     | 
    
         
            +
                    c    = o.cores.first
         
     | 
| 
      
 123 
     | 
    
         
            +
                    QString.new( @connection, c.froms.name, get_limit_and_offset(o) ).wheres( c.wheres ).orders(o.orders).projections( c.projections )
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  def visit_Arel_Nodes_InsertStatement o
         
     | 
| 
      
 127 
     | 
    
         
            +
                    e = AppEngine::Datastore::Entity.new(o.relation.name)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    o.columns.each_with_index{|c,i| e[c.name] = o.values.left[i] }
         
     | 
| 
      
 129 
     | 
    
         
            +
                    e
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  def visit_Arel_Nodes_UpdateStatement o
         
     | 
| 
      
 133 
     | 
    
         
            +
                    QString.new( @connection, o.relation.name, :values => o.values.collect{|v| [ v.left.name, v.right ] } ).wheres( o.wheres )
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  def visit_Arel_Nodes_DeleteStatement o
         
     | 
| 
      
 137 
     | 
    
         
            +
                    QString.new( @connection, o.relation.name ).wheres( o.wheres )
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
            end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
            Arel::Visitors::VISITORS['datastore'] = Arel::Visitors::Datastore
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class User < ActiveRecord::Base
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              validates_uniqueness_of :name
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              connection.create_table table_name, :force => true do |t|
         
     | 
| 
      
 8 
     | 
    
         
            +
                t.string      :name,  :limit => 25
         
     | 
| 
      
 9 
     | 
    
         
            +
                t.datetime    :dob
         
     | 
| 
      
 10 
     | 
    
         
            +
                t.integer     :rating
         
     | 
| 
      
 11 
     | 
    
         
            +
                t.float       :score
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                t.timestamps
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            describe Person do
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              before :each do
         
     | 
| 
      
 20 
     | 
    
         
            +
                AppEngine::Testing.install_test_datastore
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              it "time object" do
         
     | 
| 
      
 24 
     | 
    
         
            +
                name = "guest"
         
     | 
| 
      
 25 
     | 
    
         
            +
                dob  = Time.now
         
     | 
| 
      
 26 
     | 
    
         
            +
                user = User.create!( :name => "guest", :dob => dob )
         
     | 
| 
      
 27 
     | 
    
         
            +
                user.dob.should == dob
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                user = User.first
         
     | 
| 
      
 30 
     | 
    
         
            +
                user.dob.should == dob
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                user = User.find_by_dob( dob )
         
     | 
| 
      
 33 
     | 
    
         
            +
                user.dob.should == dob
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              it "rating object" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                5.times{|i|
         
     | 
| 
      
 38 
     | 
    
         
            +
                  User.create!( :name => "guest#{i}", :rating => i )
         
     | 
| 
      
 39 
     | 
    
         
            +
                }
         
     | 
| 
      
 40 
     | 
    
         
            +
                users = User.where( " rating >= 1 and rating <= 3 " )
         
     | 
| 
      
 41 
     | 
    
         
            +
                users.all.size.should == 3
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Person do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before :each do
         
     | 
| 
      
 5 
     | 
    
         
            +
                AppEngine::Testing.install_test_datastore
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it " in operator" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                Person.create!( :name => "guest" )
         
     | 
| 
      
 10 
     | 
    
         
            +
                people = Person.where( " created_at <= ? ", Time.now + 1 )
         
     | 
| 
      
 11 
     | 
    
         
            +
                people.all.size.should_not == 0
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                people = Person.where( :name => [ "guest", "not_guest" ] )
         
     | 
| 
      
 14 
     | 
    
         
            +
                people.all.size.should == 1
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                people = Person.where( " name in('guest','not_guest')" )
         
     | 
| 
      
 17 
     | 
    
         
            +
                people.all.size.should == 1
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                people = Person.where( " name in( 'guest', 'not_guest' )" )
         
     | 
| 
      
 20 
     | 
    
         
            +
                people.all.size.should == 1
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                people = Person.where( "( name in( 'guest', 'not_guest' ) )" )
         
     | 
| 
      
 23 
     | 
    
         
            +
                people.all.size.should == 1
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                people = Person.where( "(name in( 'guest', 'not_guest' ))" )
         
     | 
| 
      
 26 
     | 
    
         
            +
                people.all.size.should == 1
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/query_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,81 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe Person do
         
     | 
| 
      
 5 
     | 
    
         
            +
              before :each do
         
     | 
| 
      
 6 
     | 
    
         
            +
                AppEngine::Testing.install_test_datastore
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              it "init record" do
         
     | 
| 
      
 10 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 11 
     | 
    
         
            +
                person = Person.new( :name => person_name )
         
     | 
| 
      
 12 
     | 
    
         
            +
                person.id.should == nil
         
     | 
| 
      
 13 
     | 
    
         
            +
                person.name.should == person_name
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              it "save record" do
         
     | 
| 
      
 17 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 18 
     | 
    
         
            +
                person = Person.new( :name => person_name )
         
     | 
| 
      
 19 
     | 
    
         
            +
                person.save.should == true
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              it "record have id" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 24 
     | 
    
         
            +
                person = Person.new( :name => person_name )
         
     | 
| 
      
 25 
     | 
    
         
            +
                person.save.should == true
         
     | 
| 
      
 26 
     | 
    
         
            +
                person.id.should_not  == nil
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              it "retrive the record by id" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 31 
     | 
    
         
            +
                person = Person.new( :name => person_name )
         
     | 
| 
      
 32 
     | 
    
         
            +
                person.save
         
     | 
| 
      
 33 
     | 
    
         
            +
                find_person = Person.find( person.id )
         
     | 
| 
      
 34 
     | 
    
         
            +
                find_person.name.should == person_name
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              it "retrive the record by name" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 39 
     | 
    
         
            +
                person = Person.new( :name => person_name )
         
     | 
| 
      
 40 
     | 
    
         
            +
                person.save
         
     | 
| 
      
 41 
     | 
    
         
            +
                find_person = Person.find_by_name( person_name )
         
     | 
| 
      
 42 
     | 
    
         
            +
                find_person.name.should == person_name
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              it "retrive the record by name and description" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 47 
     | 
    
         
            +
                person_description = "description"
         
     | 
| 
      
 48 
     | 
    
         
            +
                Person.create!( :name => person_name, :description => person_description )
         
     | 
| 
      
 49 
     | 
    
         
            +
                find_person = Person.where( :name => person_name, :description => person_description ).first
         
     | 
| 
      
 50 
     | 
    
         
            +
                find_person.name.should == person_name
         
     | 
| 
      
 51 
     | 
    
         
            +
                find_person.description.should == person_description
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
              it "update the record" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                person_name     = "guest"
         
     | 
| 
      
 56 
     | 
    
         
            +
                new_person_name = "new_guest"
         
     | 
| 
      
 57 
     | 
    
         
            +
                person = Person.create!( :name => person_name )
         
     | 
| 
      
 58 
     | 
    
         
            +
                person.name.should        == person_name
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                person.update_attributes( :name => new_person_name ).should == true
         
     | 
| 
      
 61 
     | 
    
         
            +
                person.name.should  == new_person_name
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                person = Person.find_by_name( new_person_name )
         
     | 
| 
      
 64 
     | 
    
         
            +
                person.name.should  == new_person_name 
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              it "destroy the record" do
         
     | 
| 
      
 68 
     | 
    
         
            +
                person_name = "guest"
         
     | 
| 
      
 69 
     | 
    
         
            +
                person = Person.create!( :name => person_name )
         
     | 
| 
      
 70 
     | 
    
         
            +
                person.should_not == nil
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                person = Person.find_by_name( person_name )
         
     | 
| 
      
 73 
     | 
    
         
            +
                person.should_not == nil
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                person.destroy
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                person = Person.find_by_name( person_name )
         
     | 
| 
      
 78 
     | 
    
         
            +
                person.should == nil
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            describe Person do
         
     | 
| 
      
 4 
     | 
    
         
            +
              before :each do
         
     | 
| 
      
 5 
     | 
    
         
            +
                AppEngine::Testing.install_test_datastore
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              it "create person on role" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                person = Person.create!( :name => "guest" )
         
     | 
| 
      
 10 
     | 
    
         
            +
                role   = Role.create!( :name => "guest" )
         
     | 
| 
      
 11 
     | 
    
         
            +
                person.roles.push( role )
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                person.save.should == true
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                person = Person.find_by_name( "guest" )
         
     | 
| 
      
 16 
     | 
    
         
            +
                person.roles.size.should == 1
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                role   = Role.find_by_name( "guest" )
         
     | 
| 
      
 19 
     | 
    
         
            +
                role.people.size.should == 1
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                person.roles.build( :name => "admin" )
         
     | 
| 
      
 22 
     | 
    
         
            +
                person.save.should == true
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                person = Person.find_by_name( "guest" )
         
     | 
| 
      
 25 
     | 
    
         
            +
                person.roles.size.should == 2
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                Role.all.size.should == 2
         
     | 
| 
      
 28 
     | 
    
         
            +
                PersonRole.all.size.should == 2
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                person = Person.find_by_name( "guest" )
         
     | 
| 
      
 31 
     | 
    
         
            +
                person.destroy
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                PersonRole.all.size.should == 0
         
     | 
| 
      
 34 
     | 
    
         
            +
                Person.all.size.should == 0
         
     | 
| 
      
 35 
     | 
    
         
            +
                Role.all.size.should == 2
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,97 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rubygems'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
         
     | 
| 
      
 5 
     | 
    
         
            +
            Bundler.require(:default)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'appengine-sdk'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'appengine-apis/testing'
         
     | 
| 
      
 9 
     | 
    
         
            +
            AppEngine::Testing.setup
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            require 'appengine-apis/datastore'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require 'active_record'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'logger'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            ActiveRecord::Base.logger = Logger.new( File.open( File.expand_path('../test.log', __FILE__),  "w") )
         
     | 
| 
      
 18 
     | 
    
         
            +
            db_config_path    = File.expand_path('../database.yml', __FILE__)
         
     | 
| 
      
 19 
     | 
    
         
            +
            index_config_path = File.expand_path('../indexs.yml', __FILE__)
         
     | 
| 
      
 20 
     | 
    
         
            +
            ActiveRecord::Base.establish_connection( :adapter => 'datastore', :database => db_config_path, :index => index_config_path )
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'table_schema'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            class ProtoMatcher
         
     | 
| 
      
 25 
     | 
    
         
            +
              def compare(hash, proto, prefix='')
         
     | 
| 
      
 26 
     | 
    
         
            +
                hash.each do |key, value|
         
     | 
| 
      
 27 
     | 
    
         
            +
                  name = "#{prefix}#{key}"
         
     | 
| 
      
 28 
     | 
    
         
            +
                  case value
         
     | 
| 
      
 29 
     | 
    
         
            +
                  when Array
         
     | 
| 
      
 30 
     | 
    
         
            +
                    if value[0].kind_of? Hash
         
     | 
| 
      
 31 
     | 
    
         
            +
                      count = proto.send("#{key}_size")
         
     | 
| 
      
 32 
     | 
    
         
            +
                      compare_value("#{name}.size", value.size, count)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      value.each_with_index do |item, index|
         
     | 
| 
      
 34 
     | 
    
         
            +
                        break if index == count
         
     | 
| 
      
 35 
     | 
    
         
            +
                        compare(item, proto.send(key, index), "#{name}[#{index}].")
         
     | 
| 
      
 36 
     | 
    
         
            +
                      end
         
     | 
| 
      
 37 
     | 
    
         
            +
                    else
         
     | 
| 
      
 38 
     | 
    
         
            +
                      actual = proto.send("#{key}s").to_a
         
     | 
| 
      
 39 
     | 
    
         
            +
                      compare_value(name, value, actual)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  when Hash
         
     | 
| 
      
 42 
     | 
    
         
            +
                    compare(value, proto.send(key), "#{name}.")
         
     | 
| 
      
 43 
     | 
    
         
            +
                  else
         
     | 
| 
      
 44 
     | 
    
         
            +
                    compare_value(name, value, proto.send(key))
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              def compare_value(label, expected, actual)
         
     | 
| 
      
 50 
     | 
    
         
            +
                if expected != actual
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @failures << "%s differs. expected: %s actual: %s" %
         
     | 
| 
      
 52 
     | 
    
         
            +
                      [label, expected.inspect, actual.inspect]
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              def initialize(klass, expected)
         
     | 
| 
      
 57 
     | 
    
         
            +
                @klass = klass
         
     | 
| 
      
 58 
     | 
    
         
            +
                @expected = expected
         
     | 
| 
      
 59 
     | 
    
         
            +
              end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
              def matches(bytes)
         
     | 
| 
      
 62 
     | 
    
         
            +
                @failures = []
         
     | 
| 
      
 63 
     | 
    
         
            +
                @proto = @klass.new
         
     | 
| 
      
 64 
     | 
    
         
            +
                @proto.parse_from(bytes)
         
     | 
| 
      
 65 
     | 
    
         
            +
                compare(@expected, @proto)
         
     | 
| 
      
 66 
     | 
    
         
            +
                @failures.empty?
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              def ==(bytes)
         
     | 
| 
      
 70 
     | 
    
         
            +
                Spec::Expectations.fail_with(failure_message) unless matches(bytes)
         
     | 
| 
      
 71 
     | 
    
         
            +
                true
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              def failure_message
         
     | 
| 
      
 75 
     | 
    
         
            +
                @failures.join("\n")
         
     | 
| 
      
 76 
     | 
    
         
            +
              end
         
     | 
| 
      
 77 
     | 
    
         
            +
            end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
            module ProtoMethods
         
     | 
| 
      
 80 
     | 
    
         
            +
              def proto(klass, hash)
         
     | 
| 
      
 81 
     | 
    
         
            +
                ProtoMatcher.new(klass, hash)
         
     | 
| 
      
 82 
     | 
    
         
            +
              end
         
     | 
| 
      
 83 
     | 
    
         
            +
              alias be_proto proto
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              def mock_delegate
         
     | 
| 
      
 86 
     | 
    
         
            +
                delegate = mock("apiproxy")
         
     | 
| 
      
 87 
     | 
    
         
            +
                delegate.instance_eval do
         
     | 
| 
      
 88 
     | 
    
         
            +
                  class << self
         
     | 
| 
      
 89 
     | 
    
         
            +
                    include AppEngine::ApiProxy::Delegate
         
     | 
| 
      
 90 
     | 
    
         
            +
                  end
         
     | 
| 
      
 91 
     | 
    
         
            +
                end
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            RSpec.configure do |config|
         
     | 
| 
      
 96 
     | 
    
         
            +
              config.include(ProtoMethods)
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Person < ActiveRecord::Base
         
     | 
| 
      
 2 
     | 
    
         
            +
              has_many :person_roles, :dependent => :destroy
         
     | 
| 
      
 3 
     | 
    
         
            +
              has_many :roles, :through => :person_roles
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
              validates_uniqueness_of :name
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              connection.create_table table_name, :force => true do |t|
         
     | 
| 
      
 8 
     | 
    
         
            +
                t.string :name
         
     | 
| 
      
 9 
     | 
    
         
            +
                t.string :description
         
     | 
| 
      
 10 
     | 
    
         
            +
                t.text   :data
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                t.timestamps
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            class Role < ActiveRecord::Base
         
     | 
| 
      
 17 
     | 
    
         
            +
              has_many :person_roles, :dependent => :destroy
         
     | 
| 
      
 18 
     | 
    
         
            +
              has_many :people, :through => :person_roles
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              connection.create_table table_name, :force => true do |t|
         
     | 
| 
      
 21 
     | 
    
         
            +
                t.string :name
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                t.timestamps
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            class PersonRole < ActiveRecord::Base
         
     | 
| 
      
 28 
     | 
    
         
            +
              belongs_to :person
         
     | 
| 
      
 29 
     | 
    
         
            +
              belongs_to :role
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              connection.create_table table_name, :force => true do |t|
         
     | 
| 
      
 33 
     | 
    
         
            +
                t.integer :person_id
         
     | 
| 
      
 34 
     | 
    
         
            +
                t.integer :role_id
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                t.timestamps
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              connection.add_index table_name, [ :person_id, :role_id ]
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,108 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: activerecord-datastore-adapter
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 5 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 8 
     | 
    
         
            +
              - Mohammed Siddick
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2011-04-06 00:00:00 +05:30
         
     | 
| 
      
 14 
     | 
    
         
            +
            default_executable: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 16 
     | 
    
         
            +
              - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 17 
     | 
    
         
            +
                name: appengine-apis
         
     | 
| 
      
 18 
     | 
    
         
            +
                prerelease: false
         
     | 
| 
      
 19 
     | 
    
         
            +
                requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 20 
     | 
    
         
            +
                  none: false
         
     | 
| 
      
 21 
     | 
    
         
            +
                  requirements: 
         
     | 
| 
      
 22 
     | 
    
         
            +
                    - - "="
         
     | 
| 
      
 23 
     | 
    
         
            +
                      - !ruby/object:Gem::Version 
         
     | 
| 
      
 24 
     | 
    
         
            +
                        version: 0.0.22
         
     | 
| 
      
 25 
     | 
    
         
            +
                type: :runtime
         
     | 
| 
      
 26 
     | 
    
         
            +
                version_requirements: *id001
         
     | 
| 
      
 27 
     | 
    
         
            +
              - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 28 
     | 
    
         
            +
                name: activerecord
         
     | 
| 
      
 29 
     | 
    
         
            +
                prerelease: false
         
     | 
| 
      
 30 
     | 
    
         
            +
                requirement: &id002 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 31 
     | 
    
         
            +
                  none: false
         
     | 
| 
      
 32 
     | 
    
         
            +
                  requirements: 
         
     | 
| 
      
 33 
     | 
    
         
            +
                    - - ">="
         
     | 
| 
      
 34 
     | 
    
         
            +
                      - !ruby/object:Gem::Version 
         
     | 
| 
      
 35 
     | 
    
         
            +
                        version: 3.0.3
         
     | 
| 
      
 36 
     | 
    
         
            +
                type: :runtime
         
     | 
| 
      
 37 
     | 
    
         
            +
                version_requirements: *id002
         
     | 
| 
      
 38 
     | 
    
         
            +
              - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 39 
     | 
    
         
            +
                name: arel
         
     | 
| 
      
 40 
     | 
    
         
            +
                prerelease: false
         
     | 
| 
      
 41 
     | 
    
         
            +
                requirement: &id003 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 42 
     | 
    
         
            +
                  none: false
         
     | 
| 
      
 43 
     | 
    
         
            +
                  requirements: 
         
     | 
| 
      
 44 
     | 
    
         
            +
                    - - ">="
         
     | 
| 
      
 45 
     | 
    
         
            +
                      - !ruby/object:Gem::Version 
         
     | 
| 
      
 46 
     | 
    
         
            +
                        version: 2.0.7
         
     | 
| 
      
 47 
     | 
    
         
            +
                type: :runtime
         
     | 
| 
      
 48 
     | 
    
         
            +
                version_requirements: *id003
         
     | 
| 
      
 49 
     | 
    
         
            +
            description: |-
         
     | 
| 
      
 50 
     | 
    
         
            +
              Just an ActiveRecord Adapter for the Appengine Datastore. 
         
     | 
| 
      
 51 
     | 
    
         
            +
                  Create Rails3 application: rails new app_name -m http://siddick.github.com/datastore/rails3.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            email: 
         
     | 
| 
      
 53 
     | 
    
         
            +
              - siddick@gmail.com
         
     | 
| 
      
 54 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 61 
     | 
    
         
            +
              - .gitignore
         
     | 
| 
      
 62 
     | 
    
         
            +
              - Gemfile
         
     | 
| 
      
 63 
     | 
    
         
            +
              - Gemfile.lock
         
     | 
| 
      
 64 
     | 
    
         
            +
              - README.textile
         
     | 
| 
      
 65 
     | 
    
         
            +
              - Rakefile
         
     | 
| 
      
 66 
     | 
    
         
            +
              - activerecord-datastore-adapter.gemspec
         
     | 
| 
      
 67 
     | 
    
         
            +
              - examples/rails3.rb
         
     | 
| 
      
 68 
     | 
    
         
            +
              - examples/rails3_local.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
              - lib/active_record/connection_adapters/datastore_adapter.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
              - lib/active_record/datastore_associations_patch.rb
         
     | 
| 
      
 71 
     | 
    
         
            +
              - lib/arel/visitors/datastore.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
              - spec/create_table_spec.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
              - spec/datatypes_spec.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
              - spec/operators_spec.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
              - spec/query_spec.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
              - spec/relations_spec.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
              - spec/spec_helper.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
              - spec/table_schema.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            has_rdoc: true
         
     | 
| 
      
 80 
     | 
    
         
            +
            homepage: http://rubygems.org/gems/datastore
         
     | 
| 
      
 81 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 84 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 87 
     | 
    
         
            +
              - lib
         
     | 
| 
      
 88 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 89 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 90 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 91 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 92 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 93 
     | 
    
         
            +
                    version: "0"
         
     | 
| 
      
 94 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 95 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 96 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 97 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 98 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 99 
     | 
    
         
            +
                    version: "0"
         
     | 
| 
      
 100 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
            rubyforge_project: activerecord-datastore-adapter
         
     | 
| 
      
 103 
     | 
    
         
            +
            rubygems_version: 1.5.0
         
     | 
| 
      
 104 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 105 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 106 
     | 
    
         
            +
            summary: ActiveRecord Adapter for Appengine Datastore
         
     | 
| 
      
 107 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     |