odata_server 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/Gemfile +12 -0
- data/MIT-LICENSE +20 -0
- data/README +14 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/controllers/o_data_controller.rb +145 -0
- data/app/helpers/o_data_helper.rb +203 -0
- data/app/views/o_data/metadata.xml.builder +62 -0
- data/app/views/o_data/resource.atom.builder +8 -0
- data/app/views/o_data/resource.json.erb +1 -0
- data/app/views/o_data/service.xml.builder +11 -0
- data/config/routes.rb +11 -0
- data/init.rb +3 -0
- data/install.rb +1 -0
- data/lib/o_data/abstract_query.rb +27 -0
- data/lib/o_data/abstract_query/base.rb +133 -0
- data/lib/o_data/abstract_query/countable.rb +22 -0
- data/lib/o_data/abstract_query/errors.rb +117 -0
- data/lib/o_data/abstract_query/option.rb +58 -0
- data/lib/o_data/abstract_query/options/enumerated_option.rb +39 -0
- data/lib/o_data/abstract_query/options/expand_option.rb +81 -0
- data/lib/o_data/abstract_query/options/format_option.rb +19 -0
- data/lib/o_data/abstract_query/options/inlinecount_option.rb +20 -0
- data/lib/o_data/abstract_query/options/orderby_option.rb +79 -0
- data/lib/o_data/abstract_query/options/select_option.rb +74 -0
- data/lib/o_data/abstract_query/options/skip_option.rb +32 -0
- data/lib/o_data/abstract_query/options/top_option.rb +32 -0
- data/lib/o_data/abstract_query/parser.rb +77 -0
- data/lib/o_data/abstract_query/segment.rb +43 -0
- data/lib/o_data/abstract_query/segments/collection_segment.rb +24 -0
- data/lib/o_data/abstract_query/segments/count_segment.rb +38 -0
- data/lib/o_data/abstract_query/segments/entity_type_and_key_values_segment.rb +116 -0
- data/lib/o_data/abstract_query/segments/entity_type_segment.rb +31 -0
- data/lib/o_data/abstract_query/segments/links_segment.rb +49 -0
- data/lib/o_data/abstract_query/segments/navigation_property_segment.rb +82 -0
- data/lib/o_data/abstract_query/segments/property_segment.rb +50 -0
- data/lib/o_data/abstract_query/segments/value_segment.rb +40 -0
- data/lib/o_data/abstract_schema.rb +9 -0
- data/lib/o_data/abstract_schema/association.rb +29 -0
- data/lib/o_data/abstract_schema/base.rb +48 -0
- data/lib/o_data/abstract_schema/comparable.rb +42 -0
- data/lib/o_data/abstract_schema/end.rb +50 -0
- data/lib/o_data/abstract_schema/entity_type.rb +64 -0
- data/lib/o_data/abstract_schema/navigation_property.rb +37 -0
- data/lib/o_data/abstract_schema/property.rb +35 -0
- data/lib/o_data/abstract_schema/schema_object.rb +37 -0
- data/lib/o_data/abstract_schema/serializable.rb +79 -0
- data/lib/o_data/active_record_schema.rb +8 -0
- data/lib/o_data/active_record_schema/association.rb +130 -0
- data/lib/o_data/active_record_schema/base.rb +37 -0
- data/lib/o_data/active_record_schema/entity_type.rb +128 -0
- data/lib/o_data/active_record_schema/navigation_property.rb +45 -0
- data/lib/o_data/active_record_schema/property.rb +45 -0
- data/lib/o_data/active_record_schema/serializable.rb +36 -0
- data/lib/odata_server.rb +12 -0
- data/public/clientaccesspolicy.xml +13 -0
- data/tasks/o_data_server_tasks.rake +4 -0
- data/test/helper.rb +17 -0
- data/uninstall.rb +1 -0
- metadata +171 -0
    
        data/Gemfile
    ADDED
    
    | @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            source "http://rubygems.org"
         | 
| 2 | 
            +
            # Add dependencies required to use your gem here.
         | 
| 3 | 
            +
            # Example:
         | 
| 4 | 
            +
            #   gem "activesupport", ">= 2.3.5"
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # Add dependencies to develop your gem here.
         | 
| 7 | 
            +
            # Include everything needed to run rake, tests, features, etc.
         | 
| 8 | 
            +
            group :development do
         | 
| 9 | 
            +
              gem "bundler", "~> 1.0.0"
         | 
| 10 | 
            +
              gem "jeweler", "~> 1.5.2"
         | 
| 11 | 
            +
              gem "rcov", ">= 0"
         | 
| 12 | 
            +
            end
         | 
    
        data/MIT-LICENSE
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            Copyright (c) 2010 [name of plugin creator]
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Permission is hereby granted, free of charge, to any person obtaining
         | 
| 4 | 
            +
            a copy of this software and associated documentation files (the
         | 
| 5 | 
            +
            "Software"), to deal in the Software without restriction, including
         | 
| 6 | 
            +
            without limitation the rights to use, copy, modify, merge, publish,
         | 
| 7 | 
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         | 
| 8 | 
            +
            permit persons to whom the Software is furnished to do so, subject to
         | 
| 9 | 
            +
            the following conditions:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            The above copyright notice and this permission notice shall be
         | 
| 12 | 
            +
            included in all copies or substantial portions of the Software.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         | 
| 15 | 
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         | 
| 16 | 
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         | 
| 17 | 
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         | 
| 18 | 
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         | 
| 19 | 
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         | 
| 20 | 
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         | 
    
        data/README
    ADDED
    
    | @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            OData Server
         | 
| 2 | 
            +
            ===========
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            This is a rails plugin/engine to embue your application with OData features (so its data can be readily consumed by 
         | 
| 5 | 
            +
            an OData client).
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            It was forked Mark Borkum's work at from http://rubyforge.org/scm/?group_id=9605 with only a few small additions
         | 
| 8 | 
            +
            to support postgresql and declarative authorization and released as a gem.
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            The software iterates over your models exposing each as an OData source automatically.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            Beware - this code is not heavily tested, it does work in my limited tests usint Tableau public to consume data.
         | 
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'bundler'
         | 
| 3 | 
            +
            begin
         | 
| 4 | 
            +
              Bundler.setup(:default, :development)
         | 
| 5 | 
            +
            rescue Bundler::BundlerError => e
         | 
| 6 | 
            +
              $stderr.puts e.message
         | 
| 7 | 
            +
              $stderr.puts "Run `bundle install` to install missing gems"
         | 
| 8 | 
            +
              exit e.status_code
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
            require 'rake'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            require 'jeweler'
         | 
| 13 | 
            +
            Jeweler::Tasks.new do |gem|
         | 
| 14 | 
            +
              # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
         | 
| 15 | 
            +
              gem.name = "odata_server"
         | 
| 16 | 
            +
              gem.homepage = "http://github.com/bwlang/odata_server"
         | 
| 17 | 
            +
              gem.license = "MIT"
         | 
| 18 | 
            +
              gem.summary = %Q{OData server for Rails}
         | 
| 19 | 
            +
              gem.description = %Q{This is a gem to enable OData consumers to pull data from your Rails application.}
         | 
| 20 | 
            +
              gem.email = "langhorst@neb.com"
         | 
| 21 | 
            +
              gem.authors = ["Mark Borkum", "Brad Langhorst"]
         | 
| 22 | 
            +
              # Include your dependencies below. Runtime dependencies are required when using your gem,
         | 
| 23 | 
            +
              # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
         | 
| 24 | 
            +
              #  gem.add_runtime_dependency 'jabber4r', '> 0.1'
         | 
| 25 | 
            +
              #  gem.add_development_dependency 'rspec', '> 1.2.3'
         | 
| 26 | 
            +
            end
         | 
| 27 | 
            +
            Jeweler::RubygemsDotOrgTasks.new
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            require 'rake/testtask'
         | 
| 30 | 
            +
            Rake::TestTask.new(:test) do |test|
         | 
| 31 | 
            +
              test.libs << 'lib' << 'test'
         | 
| 32 | 
            +
              test.pattern = 'test/**/test_*.rb'
         | 
| 33 | 
            +
              test.verbose = true
         | 
| 34 | 
            +
            end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            require 'rcov/rcovtask'
         | 
| 37 | 
            +
            Rcov::RcovTask.new do |test|
         | 
| 38 | 
            +
              test.libs << 'test'
         | 
| 39 | 
            +
              test.pattern = 'test/**/test_*.rb'
         | 
| 40 | 
            +
              test.verbose = true
         | 
| 41 | 
            +
            end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            task :default => :test
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            require 'rake/rdoctask'
         | 
| 46 | 
            +
            Rake::RDocTask.new do |rdoc|
         | 
| 47 | 
            +
              version = File.exist?('VERSION') ? File.read('VERSION') : ""
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              rdoc.rdoc_dir = 'rdoc'
         | 
| 50 | 
            +
              rdoc.title = "odata_server #{version}"
         | 
| 51 | 
            +
              rdoc.rdoc_files.include('README*')
         | 
| 52 | 
            +
              rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 53 | 
            +
            end
         | 
    
        data/VERSION
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            0.0.1
         | 
| @@ -0,0 +1,145 @@ | |
| 1 | 
            +
            class ODataController < ApplicationController
         | 
| 2 | 
            +
              cattr_reader :path_param
         | 
| 3 | 
            +
              @@path_param = :__path__.freeze
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              cattr_reader :schema
         | 
| 6 | 
            +
              @@schema = OData::ActiveRecordSchema::Base.new.freeze
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              cattr_reader :parser
         | 
| 9 | 
            +
              @@parser = OData::AbstractQuery::Parser.new(@@schema).freeze
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
              rescue_from OData::ODataException, :with => :handle_exception
         | 
| 12 | 
            +
              rescue_from ActiveRecord::RecordNotFound, :with => :handle_exception
         | 
| 13 | 
            +
              
         | 
| 14 | 
            +
              before_filter :extract_resource_path_and_query_string, :only => [:resource]
         | 
| 15 | 
            +
              before_filter :parse_resource_path_and_query_string!,  :only => [:resource]
         | 
| 16 | 
            +
              before_filter :set_request_format!,                    :only => [:resource]
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
              %w{service metadata resource}.each do |method_name|
         | 
| 19 | 
            +
                define_method(:"redirect_to_#{method_name}") do
         | 
| 20 | 
            +
                  # redirect_to(send(:"o_data_#{method_name}_url"))
         | 
| 21 | 
            +
                  redirect_to(params.merge(:action => method_name.to_s))
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
              def service
         | 
| 26 | 
            +
                respond_to do |format|
         | 
| 27 | 
            +
                  format.xml  # service.xml.builder
         | 
| 28 | 
            +
                  format.json { render :json => @@schema.to_json }
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
              
         | 
| 32 | 
            +
              def metadata
         | 
| 33 | 
            +
                respond_to do |format|
         | 
| 34 | 
            +
                  format.xml  # metadata.xml.builder
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
              def resource
         | 
| 39 | 
            +
                @last_segment = @query.segments.last
         | 
| 40 | 
            +
                
         | 
| 41 | 
            +
                @results = @query.execute!
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                case @last_segment.class.segment_name
         | 
| 44 | 
            +
                when OData::AbstractQuery::Segments::CountSegment.segment_name
         | 
| 45 | 
            +
                  render :text => @results.to_i
         | 
| 46 | 
            +
                when OData::AbstractQuery::Segments::LinksSegment.segment_name
         | 
| 47 | 
            +
                  request.format = :xml unless request.format == :json
         | 
| 48 | 
            +
                  
         | 
| 49 | 
            +
                  respond_to do |format|
         | 
| 50 | 
            +
                    format.xml  { render :inline => "xml.instruct!; @results.empty? ? xml.links('xmlns' => 'http://schemas.microsoft.com/ado/2007/08/dataservices') : xml.links('xmlns' => 'http://schemas.microsoft.com/ado/2007/08/dataservices') { @results.each { |r| xml.uri(o_data_resource_url(r[1])) } }", :type => :builder }
         | 
| 51 | 
            +
                    format.json { render :json => { "links" => @results.collect { |r| { "uri" => r } } }.to_json }
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                when OData::AbstractQuery::Segments::ValueSegment.segment_name
         | 
| 54 | 
            +
                  render :text => @results.to_s
         | 
| 55 | 
            +
                when OData::AbstractQuery::Segments::PropertySegment.segment_name
         | 
| 56 | 
            +
                  request.format = :xml unless request.format == :json
         | 
| 57 | 
            +
                  
         | 
| 58 | 
            +
                  respond_to do |format|
         | 
| 59 | 
            +
                    format.xml  { render :inline => "xml.instruct!; value.blank? ? xml.tag!(key.to_sym, 'm:null' => true, 'xmlns' => 'http://schemas.microsoft.com/ado/2007/08/dataservices', 'xmlns:m' => 'http://schemas.microsoft.com/ado/2007/08/dataservices') : xml.tag!(key.to_sym, value, 'edm:Type' => type, 'xmlns' => 'http://schemas.microsoft.com/ado/2007/08/dataservices', 'xmlns:edm' => 'http://schemas.microsoft.com/ado/2007/05/edm')", :locals => { :key => @results.keys.first.name, :type => @results.keys.first.return_type, :value => @results.values.first }, :type => :builder }
         | 
| 60 | 
            +
                    format.json { render :json => { @results.keys.first.name => @results.values.first }.to_json }
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                when OData::AbstractQuery::Segments::NavigationPropertySegment.segment_name
         | 
| 63 | 
            +
                  @countable = @last_segment.countable?
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  @navigation_property = @last_segment.navigation_property
         | 
| 66 | 
            +
                  @polymorphic = @navigation_property.to_end.polymorphic?
         | 
| 67 | 
            +
                  
         | 
| 68 | 
            +
                  if @polymorphic
         | 
| 69 | 
            +
                    @entity_type = nil
         | 
| 70 | 
            +
                    @entity_type_name = @navigation_property.to_end.name.singularize
         | 
| 71 | 
            +
                  else
         | 
| 72 | 
            +
                    @entity_type = @navigation_property.to_end.entity_type
         | 
| 73 | 
            +
                    @entity_type_name = @entity_type.name
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  @collection_name = @entity_type_name.pluralize
         | 
| 77 | 
            +
                  
         | 
| 78 | 
            +
                  @expand_navigation_property_paths = {}
         | 
| 79 | 
            +
                  if expand_option = @query.options.find { |o| o.option_name == OData::AbstractQuery::Options::ExpandOption.option_name }
         | 
| 80 | 
            +
                    @expand_navigation_property_paths = expand_option.navigation_property_paths
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                  
         | 
| 83 | 
            +
                  respond_to do |format|
         | 
| 84 | 
            +
                    format.atom # resource.atom.builder
         | 
| 85 | 
            +
                    format.json # resource.json.erb
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
                when OData::AbstractQuery::Segments::CollectionSegment.segment_name
         | 
| 88 | 
            +
                  @countable = @last_segment.countable?
         | 
| 89 | 
            +
                  
         | 
| 90 | 
            +
                  @navigation_property = nil
         | 
| 91 | 
            +
                  @polymorphic = true
         | 
| 92 | 
            +
                  
         | 
| 93 | 
            +
                  @entity_type = @last_segment.entity_type
         | 
| 94 | 
            +
                  
         | 
| 95 | 
            +
                  @expand_navigation_property_paths = {}
         | 
| 96 | 
            +
                  if expand_option = @query.options.find { |o| o.option_name == OData::AbstractQuery::Options::ExpandOption.option_name }
         | 
| 97 | 
            +
                    @expand_navigation_property_paths = expand_option.navigation_property_paths
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
                  
         | 
| 100 | 
            +
                  respond_to do |format|
         | 
| 101 | 
            +
                    format.atom # resource.atom.builder
         | 
| 102 | 
            +
                    format.json # resource.json.erb
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
                else
         | 
| 105 | 
            +
                  # in theory, this branch is unreachable because the <tt>parse_resource_path_and_query_string!</tt>
         | 
| 106 | 
            +
                  # method will throw an exception if the <tt>OData::AbstractQuery::Parser</tt> fails to match any
         | 
| 107 | 
            +
                  # segment of the resource path.
         | 
| 108 | 
            +
                  raise OData::AbstractQuery::Errors::AbstractQueryException.new(@query)
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
              end
         | 
| 111 | 
            +
              
         | 
| 112 | 
            +
              private
         | 
| 113 | 
            +
              
         | 
| 114 | 
            +
              def extract_resource_path_and_query_string
         | 
| 115 | 
            +
                @resource_path = params[@@path_param].join('/')
         | 
| 116 | 
            +
                
         | 
| 117 | 
            +
                @query_string = params.inject({}) { |acc, pair|
         | 
| 118 | 
            +
                  key, value = pair
         | 
| 119 | 
            +
                  acc[key.to_sym] = value unless [@@path_param, :controller, :action].include?(key.to_sym)
         | 
| 120 | 
            +
                  acc
         | 
| 121 | 
            +
                }.collect { |key, value|
         | 
| 122 | 
            +
                  key.to_s + '=' + value.to_s
         | 
| 123 | 
            +
                }.join('&')
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
              
         | 
| 126 | 
            +
              def parse_resource_path_and_query_string!
         | 
| 127 | 
            +
                @query = @@parser.parse!([@resource_path, @query_string].compact.join('?'))
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
              
         | 
| 130 | 
            +
              def set_request_format!
         | 
| 131 | 
            +
                if format_option = @query.options.find { |o| o.option_name == OData::AbstractQuery::Options::FormatOption.option_name }
         | 
| 132 | 
            +
                  if format_value = format_option.value
         | 
| 133 | 
            +
                    request.format = format_value.to_sym
         | 
| 134 | 
            +
                  end
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
              end
         | 
| 137 | 
            +
              
         | 
| 138 | 
            +
              def handle_exception(ex)
         | 
| 139 | 
            +
                request.format = :xml
         | 
| 140 | 
            +
                
         | 
| 141 | 
            +
                respond_to do |format|
         | 
| 142 | 
            +
                  format.xml { render :inline => "xml.instruct!; xml.error('xmlns' => 'http://schemas.microsoft.com/ado/2007/08/dataservices/metadata') { xml.code(code.to_s); xml.message(message); xml.uri(uri) }", :type => :builder, :locals => { :code => nil, :message => ex.message, :uri => request.url } }
         | 
| 143 | 
            +
                end
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
            end
         | 
| @@ -0,0 +1,203 @@ | |
| 1 | 
            +
            module ODataHelper
         | 
| 2 | 
            +
              @@o_data_atom_xmlns = { 
         | 
| 3 | 
            +
                "xmlns"   => "http://www.w3.org/2005/Atom",
         | 
| 4 | 
            +
                "xmlns:d" => "http://schemas.microsoft.com/ado/2007/08/dataservices", 
         | 
| 5 | 
            +
                "xmlns:m" => "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" 
         | 
| 6 | 
            +
              }.freeze
         | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              def o_data_atom_feed(xml, query, results, options = {})
         | 
| 9 | 
            +
                results_href, results_url = begin
         | 
| 10 | 
            +
                  if base_href = options.delete(:href)
         | 
| 11 | 
            +
                    [base_href.to_s, o_data_resource_url(base_href.to_s)]
         | 
| 12 | 
            +
                  else
         | 
| 13 | 
            +
                    [query.resource_path, o_data_resource_url(query.to_uri)]
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                
         | 
| 17 | 
            +
                results_title = options.delete(:title) || results_href
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                xml.tag!(:feed, { "xml:base" => o_data_service_url }.merge(options[:hide_xmlns] ? {} : @@o_data_atom_xmlns)) do
         | 
| 20 | 
            +
                  xml.tag!(:title, results_title)
         | 
| 21 | 
            +
                  xml.tag!(:id, results_url)
         | 
| 22 | 
            +
                  xml.tag!(:link, :rel => "self", :title => results_title, :href => results_href)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  unless results.empty?
         | 
| 25 | 
            +
                    if last_result = results.last
         | 
| 26 | 
            +
                      if atom_updated_at = query.schema.atom_updated_at_for(last_result)
         | 
| 27 | 
            +
                        xml.tag!(:updated, atom_updated_at.iso8601)
         | 
| 28 | 
            +
                      end
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
                    
         | 
| 31 | 
            +
                    results.each do |result|
         | 
| 32 | 
            +
                      o_data_atom_entry(xml, query, result, options.merge(:hide_xmlns => true, :href => results_href))
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                  
         | 
| 36 | 
            +
                  if inlinecount_option = query.options.find { |o| o.option_name == OData::AbstractQuery::Options::InlinecountOption.option_name }
         | 
| 37 | 
            +
                    if inlinecount_option.value == 'allpages'
         | 
| 38 | 
            +
                      xml.m(:count, results.length)
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
              
         | 
| 44 | 
            +
              def o_data_atom_entry(xml, query, result, options = {})
         | 
| 45 | 
            +
                entity_type = options[:entity_type] || query.schema.find_entity_type(:active_record => result.class)
         | 
| 46 | 
            +
                raise OData::AbstractQuery::Errors::EntityTypeNotFound.new(query, result.class.name) if entity_type.blank?
         | 
| 47 | 
            +
                
         | 
| 48 | 
            +
                result_href = entity_type.href_for(result)
         | 
| 49 | 
            +
                result_url = o_data_resource_url(result_href)
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                result_title = entity_type.atom_title_for(result)
         | 
| 52 | 
            +
                result_summary = entity_type.atom_summary_for(result)
         | 
| 53 | 
            +
                result_updated_at = entity_type.atom_updated_at_for(result)
         | 
| 54 | 
            +
                
         | 
| 55 | 
            +
                xml.tag!(:entry, {}.merge(options[:hide_xmlns] ? {} : @@o_data_atom_xmlns)) do
         | 
| 56 | 
            +
                  xml.tag!(:id, result_url) unless result_href.blank?     
         | 
| 57 | 
            +
                  xml.tag!(:title, result_title, :type => "text") unless result_title.blank?
         | 
| 58 | 
            +
                  xml.tag!(:summary, result_summary, :type => "text") unless result_summary.blank?
         | 
| 59 | 
            +
                  xml.tag!(:updated, result_updated_at.iso8601) unless result_updated_at.blank?
         | 
| 60 | 
            +
                  
         | 
| 61 | 
            +
                  xml.tag!(:author) do
         | 
| 62 | 
            +
                    xml.tag!(:name)
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  
         | 
| 65 | 
            +
                  xml.tag!(:link, :rel => "edit", :title => result_title, :href => result_href) unless result_title.blank? || result_href.blank?
         | 
| 66 | 
            +
                  
         | 
| 67 | 
            +
                  unless entity_type.navigation_properties.empty?
         | 
| 68 | 
            +
                    entity_type.navigation_properties.sort_by(&:name).each do |navigation_property|
         | 
| 69 | 
            +
                      navigation_property_href = result_href + '/' + navigation_property.name
         | 
| 70 | 
            +
                      
         | 
| 71 | 
            +
                      navigation_property_attrs = { :rel => "http://schemas.microsoft.com/ado/2007/08/dataservices/related/" + navigation_property.name, :type => "application/atom+xml;type=#{navigation_property.to_end.multiple? ? 'feed' : 'entry'}", :title => navigation_property.name, :href => navigation_property_href }
         | 
| 72 | 
            +
                      
         | 
| 73 | 
            +
                      if (options[:expand] || {}).keys.include?(navigation_property)
         | 
| 74 | 
            +
                        xml.tag!(:link, navigation_property_attrs) do
         | 
| 75 | 
            +
                          xml.m(:inline, :type => navigation_property_attrs[:type]) do
         | 
| 76 | 
            +
                            if navigation_property.to_end.multiple?
         | 
| 77 | 
            +
                              o_data_atom_feed(xml, query, navigation_property.find_all(result), options.merge(:entity_type => navigation_property.to_end.entity_type, :expand => options[:expand][navigation_property]))
         | 
| 78 | 
            +
                            else
         | 
| 79 | 
            +
                              o_data_atom_entry(xml, query, navigation_property.find_one(result), options.merge(:entity_type => navigation_property.to_end.entity_type, :expand => options[:expand][navigation_property]))
         | 
| 80 | 
            +
                            end
         | 
| 81 | 
            +
                          end
         | 
| 82 | 
            +
                        end
         | 
| 83 | 
            +
                      else
         | 
| 84 | 
            +
                        xml.tag!(:link, navigation_property_attrs)
         | 
| 85 | 
            +
                      end
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                  
         | 
| 89 | 
            +
                  xml.tag!(:category, :term => entity_type.qualified_name, :scheme => "http://schemas.microsoft.com/ado/2007/08/dataservices/scheme")
         | 
| 90 | 
            +
                  
         | 
| 91 | 
            +
                  unless (properties = get_selected_properties_for(query, entity_type)).empty?
         | 
| 92 | 
            +
                    xml.tag!(:content, :type => "application/xml") do
         | 
| 93 | 
            +
                      xml.m(:properties) do
         | 
| 94 | 
            +
                        properties.each do |property|
         | 
| 95 | 
            +
                          property_attrs = { "m:type" => property.return_type }
         | 
| 96 | 
            +
                          
         | 
| 97 | 
            +
                          unless (value = property.value_for(result)).blank?
         | 
| 98 | 
            +
                            xml.d(property.name.to_sym, value, property_attrs)
         | 
| 99 | 
            +
                          else
         | 
| 100 | 
            +
                            xml.d(property.name.to_sym, property_attrs.merge("m:null" => true))
         | 
| 101 | 
            +
                          end
         | 
| 102 | 
            +
                        end
         | 
| 103 | 
            +
                      end
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
              def o_data_json_feed(query, results, options = {})
         | 
| 110 | 
            +
                results_json = results.collect { |result| o_data_json_entry(query, result, options.merge(:d => false, :deferred => false)) }
         | 
| 111 | 
            +
                
         | 
| 112 | 
            +
                if inlinecount_option = query.options.find { |o| o.option_name == OData::AbstractQuery::Options::InlinecountOption.option_name }
         | 
| 113 | 
            +
                  if inlinecount_option.value == 'allpages'
         | 
| 114 | 
            +
                    _json = {
         | 
| 115 | 
            +
                      "results" => results_json,
         | 
| 116 | 
            +
                      "__count" => results.length
         | 
| 117 | 
            +
                    }
         | 
| 118 | 
            +
                    
         | 
| 119 | 
            +
                    return options[:d] ? { "d" => _json } : _json
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                options[:d] ? { "d" => results_json } : results_json
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
              
         | 
| 126 | 
            +
              def o_data_json_entry(query, result, options = {})
         | 
| 127 | 
            +
                entity_type = options[:entity_type] || query.schema.find_entity_type(:active_record => result.class)
         | 
| 128 | 
            +
                raise OData::AbstractQuery::Errors::EntityTypeNotFound.new(query, result.class.name) if entity_type.blank?
         | 
| 129 | 
            +
                
         | 
| 130 | 
            +
                resource_uri = o_data_resource_url(entity_type.href_for(result))
         | 
| 131 | 
            +
                resource_type = entity_type.qualified_name
         | 
| 132 | 
            +
                
         | 
| 133 | 
            +
                json = begin
         | 
| 134 | 
            +
                  if options[:deferred]
         | 
| 135 | 
            +
                    {
         | 
| 136 | 
            +
                      "__deferred" => { 
         | 
| 137 | 
            +
                        "uri" => resource_uri 
         | 
| 138 | 
            +
                      } 
         | 
| 139 | 
            +
                    }
         | 
| 140 | 
            +
                  else
         | 
| 141 | 
            +
                    _json = { 
         | 
| 142 | 
            +
                      "__metadata" => {
         | 
| 143 | 
            +
                        "uri" => resource_uri,
         | 
| 144 | 
            +
                        "type" => resource_type
         | 
| 145 | 
            +
                      } 
         | 
| 146 | 
            +
                    }
         | 
| 147 | 
            +
                    
         | 
| 148 | 
            +
                    get_selected_properties_for(query, entity_type).each do |property|
         | 
| 149 | 
            +
                      unless %w{__deferred __metadata}.include?(property.name.to_s)
         | 
| 150 | 
            +
                        _json[property.name.to_s] = property.value_for(result)
         | 
| 151 | 
            +
                      else
         | 
| 152 | 
            +
                        # TODO: raise JSONException (property with reserved name)
         | 
| 153 | 
            +
                      end
         | 
| 154 | 
            +
                    end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                    entity_type.navigation_properties.sort_by(&:name).each do |navigation_property|
         | 
| 157 | 
            +
                      unless %w{__deferred __metadata}.include?(navigation_property.name.to_s)
         | 
| 158 | 
            +
                        navigation_property_uri = resource_uri + '/' + navigation_property.name.to_s
         | 
| 159 | 
            +
                        
         | 
| 160 | 
            +
                        _json[navigation_property.name.to_s] = begin
         | 
| 161 | 
            +
                          if (options[:expand] || {}).keys.include?(navigation_property)
         | 
| 162 | 
            +
                            if navigation_property.to_end.multiple?
         | 
| 163 | 
            +
                              o_data_json_feed(query, navigation_property.find_all(result), options.merge(:entity_type => navigation_property.to_end.entity_type, :expand => options[:expand][navigation_property], :d => false))
         | 
| 164 | 
            +
                            else
         | 
| 165 | 
            +
                              o_data_json_entry(query, navigation_property.find_one(result), options.merge(:entity_type => navigation_property.to_end.entity_type, :expand => options[:expand][navigation_property], :d => false))
         | 
| 166 | 
            +
                            end
         | 
| 167 | 
            +
                          else
         | 
| 168 | 
            +
                            {
         | 
| 169 | 
            +
                              "__deferred" => {
         | 
| 170 | 
            +
                                "uri" => navigation_property_uri
         | 
| 171 | 
            +
                              }
         | 
| 172 | 
            +
                            }
         | 
| 173 | 
            +
                          end
         | 
| 174 | 
            +
                        end
         | 
| 175 | 
            +
                      else
         | 
| 176 | 
            +
                        # TODO: raise JSONException (navigation property with reserved name)
         | 
| 177 | 
            +
                      end
         | 
| 178 | 
            +
                    end
         | 
| 179 | 
            +
                    
         | 
| 180 | 
            +
                    _json
         | 
| 181 | 
            +
                  end
         | 
| 182 | 
            +
                end
         | 
| 183 | 
            +
                
         | 
| 184 | 
            +
                options[:d] ? { "d" => json } : json
         | 
| 185 | 
            +
              end
         | 
| 186 | 
            +
              
         | 
| 187 | 
            +
              protected
         | 
| 188 | 
            +
              
         | 
| 189 | 
            +
              def get_selected_properties_for(query, entity_type)
         | 
| 190 | 
            +
                if select_option = query.options.find { |o| o.option_name == OData::AbstractQuery::Options::SelectOption.option_name }
         | 
| 191 | 
            +
                  if select_option.entity_type == entity_type
         | 
| 192 | 
            +
                    # entity_type is the $select'ed collection/navigation property
         | 
| 193 | 
            +
                    return select_option.properties
         | 
| 194 | 
            +
                  else
         | 
| 195 | 
            +
                    # entity_type is an $expand'ed navigation property
         | 
| 196 | 
            +
                    return []
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
                
         | 
| 200 | 
            +
                # $select option not supplied
         | 
| 201 | 
            +
                entity_type.properties
         | 
| 202 | 
            +
              end
         | 
| 203 | 
            +
            end
         |