ruby_odata 0.0.10 → 0.1.0
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 +9 -3
- data/.travis.yml +4 -0
- data/CHANGELOG.rdoc +18 -1
- data/README.rdoc +77 -19
- data/config/cucumber.yml +4 -3
- data/features/basic_auth.feature +5 -7
- data/features/batch_request.feature +11 -11
- data/features/complex_types.feature +11 -11
- data/features/query_builder.feature +27 -18
- data/features/service.feature +8 -8
- data/features/service_manage.feature +27 -12
- data/features/service_methods.feature +37 -0
- data/features/ssl.feature +4 -4
- data/features/step_definitions/pickle_steps.rb +100 -0
- data/features/step_definitions/service_steps.rb +99 -65
- data/features/support/constants.rb +3 -0
- data/features/support/custom_helpers.rb +54 -0
- data/features/support/env.rb +0 -10
- data/features/support/hooks.rb +1 -1
- data/features/support/pickle.rb +82 -0
- data/features/type_conversion.feature +10 -10
- data/lib/ruby_odata.rb +4 -1
- data/lib/ruby_odata/association.rb +36 -0
- data/lib/ruby_odata/class_builder.rb +96 -16
- data/lib/ruby_odata/helpers.rb +10 -0
- data/lib/ruby_odata/operation.rb +7 -5
- data/lib/ruby_odata/property_metadata.rb +11 -6
- data/lib/ruby_odata/query_builder.rb +20 -1
- data/lib/ruby_odata/service.rb +407 -94
- data/lib/ruby_odata/version.rb +1 -1
- data/ruby_odata.gemspec +2 -0
- data/spec/association_spec.rb +48 -0
- data/spec/class_builder_spec.rb +11 -2
- data/spec/fixtures/inheritance/edmx_pluralsight.xml +111 -0
- data/spec/fixtures/inheritance/result_pluralsight_courses.xml +229 -0
- data/spec/fixtures/links/result_links_query.xml +6 -0
- data/spec/fixtures/partial/partial_feed_metadata.xml +25 -0
- data/spec/fixtures/partial/partial_feed_part_1.xml +42 -0
- data/spec/fixtures/partial/partial_feed_part_2.xml +42 -0
- data/spec/fixtures/partial/partial_feed_part_3.xml +40 -0
- data/spec/fixtures/sample_service/edmx_categories_products.xml +1 -0
- data/spec/fixtures/sample_service/result_category_names.xml +5 -0
- data/spec/fixtures/sample_service/result_entity_category_web_get.xml +29 -0
- data/spec/fixtures/sample_service/result_entity_single_category_web_get.xml +23 -0
- data/spec/fixtures/sample_service/result_first_category_id.xml +2 -0
- data/spec/fixtures/sample_service/result_multiple_category_products.xml +57 -0
- data/spec/fixtures/sample_service/result_single_category.xml +18 -0
- data/spec/fixtures/sample_service/result_single_product.xml +26 -0
- data/spec/fixtures/sample_service/result_single_product_not_found.xml +4 -0
- data/spec/fixtures/sap/edmx_sap_demo_flight.xml +62 -58
- data/spec/property_metadata_spec.rb +9 -2
- data/spec/query_builder_spec.rb +11 -0
- data/spec/revised_service_spec.rb +197 -0
- data/spec/service_spec.rb +463 -4
- data/test/RubyODataService/RubyODataService.sln +20 -0
- data/test/RubyODataService/RubyODataService/App_Start/EntityFramework.SqlServerCompact.cs +12 -0
- data/test/RubyODataService/RubyODataService/BasicAuth/RubyOData.svc +3 -0
- data/test/RubyODataService/RubyODataService/BasicAuth/RubyOData.svc.cs +107 -0
- data/test/RubyODataService/RubyODataService/Global.asax +1 -0
- data/test/RubyODataService/RubyODataService/Global.asax.cs +49 -0
- data/test/RubyODataService/RubyODataService/Models/AuditFields.cs +16 -0
- data/test/RubyODataService/RubyODataService/Models/Category.cs +16 -0
- data/test/RubyODataService/RubyODataService/Models/Product.cs +20 -0
- data/test/RubyODataService/RubyODataService/Properties/AssemblyInfo.cs +35 -0
- data/test/RubyODataService/RubyODataService/RubyOData.svc +3 -0
- data/test/RubyODataService/RubyODataService/RubyOData.svc.cs +57 -0
- data/test/RubyODataService/RubyODataService/RubyODataContext.cs +16 -0
- data/test/RubyODataService/RubyODataService/RubyODataService.csproj +159 -0
- data/test/RubyODataService/RubyODataService/RubyODataService.csproj.user +31 -0
- data/test/RubyODataService/RubyODataService/Web.Debug.config +30 -0
- data/test/RubyODataService/RubyODataService/Web.Release.config +31 -0
- data/test/RubyODataService/RubyODataService/Web.config +27 -0
- data/test/RubyODataService/RubyODataService/bin/EntityFramework.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Edm.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.OData.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Services.Client.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Services.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/Microsoft.Data.Spatial.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/RubyODataService.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/System.Data.SqlServerCe.Entity.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/System.Data.SqlServerCe.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/System.Spatial.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/WebActivator.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/README_ENU.txt +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/Microsoft.VC90.CRT/msvcr90.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/sqlcecompact40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/sqlceer40EN.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/sqlceme40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/sqlceqp40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/amd64/sqlcese40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
- data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/README_ENU.txt +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/Microsoft.VC90.CRT/msvcr90.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/sqlcecompact40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/sqlceer40EN.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/sqlceme40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/sqlceqp40.dll +0 -0
- data/test/RubyODataService/RubyODataService/bin/x86/sqlcese40.dll +0 -0
- data/test/RubyODataService/RubyODataService/packages.config +7 -0
- data/test/RubyODataService/packages/EntityFramework.4.2.0.0/EntityFramework.4.2.0.0.nupkg +0 -0
- data/test/RubyODataService/packages/EntityFramework.4.2.0.0/lib/net40/EntityFramework.dll +0 -0
- data/test/RubyODataService/packages/EntityFramework.4.2.0.0/lib/net40/EntityFramework.xml +13488 -0
- data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/Content/App_Start/EntityFramework.SqlServerCompact.cs.pp +12 -0
- data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/EULA_ENU.rtf +969 -0
- data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/EntityFramework.SqlServerCompact.4.1.8482.2.nupkg +0 -0
- data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/lib/System.Data.SqlServerCe.Entity.dll +0 -0
- data/test/RubyODataService/packages/EntityFramework.SqlServerCompact.4.1.8482.2/tools/install.ps1 +3 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Content/web.config.transform +8 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/README_ENU.txt +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/Microsoft.VC90.CRT/msvcr90.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlcecompact40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceer40EN.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceme40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlceqp40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/amd64/sqlcese40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest +6 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/README_ENU.txt +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/Microsoft.VC90.CRT/msvcr90.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlcecompact40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceer40EN.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceme40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlceqp40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/NativeBinaries/x86/sqlcese40.dll +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/SQLCE_EULA_ENU.rtf +778 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/SqlServerCompact.4.0.8482.1.nupkg +0 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/GetSqlCEPostBuildCmd.ps1 +12 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/install.ps1 +11 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/Tools/uninstall.ps1 +9 -0
- data/test/RubyODataService/packages/SqlServerCompact.4.0.8482.1/lib/System.Data.SqlServerCe.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/DataSvcUtil.exe +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/License.rtf +708 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Edm.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Edm.xml +4150 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.OData.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.OData.xml +1969 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Client.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Client.xml +1442 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Design.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.Design.xml +191 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Services.xml +2559 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Spatial.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.Data.Spatial.xml +15 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/Microsoft.VsDesigner.DataServices.Adapter.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/README.txt +6 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/System.Spatial.dll +0 -0
- data/test/RubyODataService/packages/WCF DataServices October 2011 CTP/System.Spatial.xml +2276 -0
- data/test/RubyODataService/packages/WebActivator.1.0.0.0/WebActivator.1.0.0.0.nupkg +0 -0
- data/test/RubyODataService/packages/WebActivator.1.0.0.0/lib/WebActivator.dll +0 -0
- data/test/RubyODataService/packages/repositories.config +4 -0
- data/test/applicationhost.config.template +2 -2
- data/test/blueprints.rb +5 -4
- data/test/iisExpress x64.bat b/data/test/iisExpress → x64.bat +0 -0
- data/test/iisExpress x86.bat b/data/test/iisExpress → x86.bat +0 -0
- data/test/setpath.rb +13 -3
- data/test/usage_samples/querying.rb +45 -0
- data/test/usage_samples/reflection.rb +16 -0
- data/test/usage_samples/sample_data.rb +30 -0
- metadata +327 -36
- data/test/Cassini x64.bat +0 -1
- data/test/Cassini x86.bat +0 -1
- data/test/SampleService/App_Code/AuditFields.cs +0 -13
- data/test/SampleService/App_Code/Entities.cs +0 -145
- data/test/SampleService/App_Code/Model.Designer.cs +0 -578
- data/test/SampleService/App_Code/Model.edmx +0 -157
- data/test/SampleService/App_Code/ModelContainerExtended.cs +0 -32
- data/test/SampleService/App_Data/_TestDB.mdf +0 -0
- data/test/SampleService/App_Data/_TestDB_Log.ldf +0 -0
- data/test/SampleService/BasicAuth/Entities.svc +0 -1
- data/test/SampleService/Entities.svc +0 -1
- data/test/SampleService/web.config +0 -37
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module CustomHelpers
|
|
2
|
+
# Used to access the first result of a query
|
|
3
|
+
def first_result
|
|
4
|
+
@service_result = @service_result.first if @service_result.is_a? Enumerable
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Used to access the first save result
|
|
8
|
+
def first_save
|
|
9
|
+
@saved_result = @saved_result.first if @saved_result.is_a? Enumerable
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Allows the string @@LastSave to be used when checking results
|
|
13
|
+
def handle_last_save_fields(val)
|
|
14
|
+
if val =~ /^@@LastSave.first$/
|
|
15
|
+
val = @saved_result.first
|
|
16
|
+
end
|
|
17
|
+
if val =~ /^@@LastSave$/
|
|
18
|
+
val = @saved_result
|
|
19
|
+
end
|
|
20
|
+
val
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Takes in comma-delimited fields string (like key: "value") and parses it into a hash
|
|
24
|
+
def parse_fields_string(fields)
|
|
25
|
+
fields_hash = {}
|
|
26
|
+
|
|
27
|
+
if !fields.nil?
|
|
28
|
+
fields.split(', ').each do |field|
|
|
29
|
+
if field =~ /^(?:(\w+): "(.*)")$/
|
|
30
|
+
key = $1
|
|
31
|
+
val = handle_last_save_fields($2)
|
|
32
|
+
|
|
33
|
+
fields_hash.merge!({key => val})
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
fields_hash
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Takes in a hash and convert special values (like @@LastSave) into the appropriate values
|
|
41
|
+
def parse_fields_hash(fields)
|
|
42
|
+
fields_hash = {}
|
|
43
|
+
|
|
44
|
+
if !fields.nil?
|
|
45
|
+
fields.each do |key, val|
|
|
46
|
+
val = handle_last_save_fields(val)
|
|
47
|
+
fields_hash.merge!({key => val})
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
fields_hash
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
World(CustomHelpers)
|
data/features/support/env.rb
CHANGED
|
@@ -4,13 +4,3 @@ require lib + '/ruby_odata'
|
|
|
4
4
|
require 'machinist/object'
|
|
5
5
|
require 'sham'
|
|
6
6
|
require 'faker'
|
|
7
|
-
|
|
8
|
-
require 'fileutils'
|
|
9
|
-
root_dir = File.expand_path(File.join(File.dirname(__FILE__), "../..", "test/SampleService/App_Data"))
|
|
10
|
-
|
|
11
|
-
if !File.exists?("#{root_dir}/TestDB.mdf")
|
|
12
|
-
FileUtils.copy("#{root_dir}/_TestDB.mdf", "#{root_dir}/TestDB.mdf")
|
|
13
|
-
FileUtils.copy("#{root_dir}/_TestDB_Log.ldf", "#{root_dir}/TestDB_Log.ldf")
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
HTTP_PORT_NUMBER = 8989
|
data/features/support/hooks.rb
CHANGED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'pickle/world'
|
|
2
|
+
require File.expand_path('../../../lib/ruby_odata', __FILE__)
|
|
3
|
+
|
|
4
|
+
module OData
|
|
5
|
+
|
|
6
|
+
module PickleAdapter
|
|
7
|
+
include Pickle::Adapter::Base
|
|
8
|
+
|
|
9
|
+
@@service = OData::Service.new "http://#{WEBSERVER}:#{HTTP_PORT_NUMBER}/SampleService/RubyOData.svc"
|
|
10
|
+
|
|
11
|
+
# Do not consider these to be part of the class list
|
|
12
|
+
def self.except_classes
|
|
13
|
+
@@except_classes ||= []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Gets a list of the available models for this adapter
|
|
17
|
+
def self.model_classes
|
|
18
|
+
@@service.classes.values
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# get a list of column names for a given class
|
|
22
|
+
def self.column_names(klass)
|
|
23
|
+
klass.properties.keys
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Get an instance by id of the model
|
|
27
|
+
def self.get_model(klass, id, expand = false)
|
|
28
|
+
collection = klass.to_s.split('::').last.pluralize
|
|
29
|
+
query = @@service.send collection, id
|
|
30
|
+
|
|
31
|
+
if expand then
|
|
32
|
+
# Expand all navigation properties
|
|
33
|
+
navigation_properties = klass.properties.select { |k, v| v.nav_prop }
|
|
34
|
+
# Ruby 1.9 Hash.select returns a Hash, 1.8 returns an Array, so normalize the return type
|
|
35
|
+
props = (navigation_properties.is_a? Hash) ? navigation_properties : Hash[*navigation_properties.flatten]
|
|
36
|
+
props.keys.each do |prop|
|
|
37
|
+
query.expand(prop)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@@service.execute.first
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Find the first instance matching conditions
|
|
45
|
+
def self.find_first_model(klass, conditions)
|
|
46
|
+
collection = klass.to_s.split('::').last.pluralize
|
|
47
|
+
q = @@service.send collection
|
|
48
|
+
q.filter(conditions)
|
|
49
|
+
q.take(1)
|
|
50
|
+
@@service.execute.first
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Find all models matching conditions
|
|
54
|
+
def self.find_all_models(klass, conditions)
|
|
55
|
+
collection = klass.to_s.split('::').last.pluralize
|
|
56
|
+
q = @@service.send collection
|
|
57
|
+
q.filter(conditions)
|
|
58
|
+
@@service.execute
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Create a model using attributes
|
|
62
|
+
def self.create_model(klass, attributes)
|
|
63
|
+
instance = klass.send :make, attributes
|
|
64
|
+
|
|
65
|
+
collection = klass.to_s.split('::').last.pluralize
|
|
66
|
+
@@service.send "AddTo#{collection}", instance
|
|
67
|
+
@@service.save_changes.first
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
module Pickle
|
|
74
|
+
module Session
|
|
75
|
+
# return a newly selected model with the navigation properties expanded
|
|
76
|
+
def model_with_associations(name)
|
|
77
|
+
model = created_model(name)
|
|
78
|
+
return nil unless model
|
|
79
|
+
OData::PickleAdapter.get_model(model.class, model.id, true)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -4,7 +4,7 @@ Feature: Type conversion
|
|
|
4
4
|
I want types returned to be accurately represented
|
|
5
5
|
|
|
6
6
|
Background:
|
|
7
|
-
Given a
|
|
7
|
+
Given a HTTP ODataService exists
|
|
8
8
|
And blueprints exist for the service
|
|
9
9
|
|
|
10
10
|
Scenario: Integers should be Fixnums
|
|
@@ -12,42 +12,42 @@ Scenario: Integers should be Fixnums
|
|
|
12
12
|
And I save changes
|
|
13
13
|
When I call "Products" on the service
|
|
14
14
|
And I run the query
|
|
15
|
-
Then the "Id" method should return a Fixnum
|
|
15
|
+
Then the "Id" method on the object should return a Fixnum
|
|
16
16
|
|
|
17
17
|
Scenario: Decimals should be BigDecimals
|
|
18
18
|
Given I call "AddToProducts" on the service with a new "Product" object
|
|
19
19
|
And I save changes
|
|
20
20
|
When I call "Products" on the service
|
|
21
21
|
And I run the query
|
|
22
|
-
Then the "Price" method should return a BigDecimal
|
|
22
|
+
Then the "Price" method on the object should return a BigDecimal
|
|
23
23
|
|
|
24
24
|
Scenario: DateTimes should be Times
|
|
25
25
|
Given I call "AddToProducts" on the service with a new "Product" object
|
|
26
26
|
And I save changes
|
|
27
27
|
When I call "Products" on the service
|
|
28
28
|
And I run the query
|
|
29
|
-
Then the "AuditFields.CreateDate" method should return a Time
|
|
29
|
+
Then the "AuditFields.CreateDate" method on the object should return a Time
|
|
30
30
|
|
|
31
31
|
Scenario: Verify that DateTimes don't change if not modified on an update
|
|
32
32
|
Given I call "AddToProducts" on the service with a new "Product" object with Name: "Test Product"
|
|
33
33
|
When I save changes
|
|
34
34
|
And I call "Products" on the service with args: "1"
|
|
35
35
|
And I run the query
|
|
36
|
-
Then I store the last query result for comparison
|
|
37
|
-
When I set "Name" on the result to "Changed Test Product"
|
|
38
|
-
Then the method "Name" on the result should equal: "Changed Test Product"
|
|
39
|
-
And I call "update_object" on the service with the last query result
|
|
36
|
+
Then I store the first last query result for comparison
|
|
37
|
+
When I set "Name" on the first result to "Changed Test Product"
|
|
38
|
+
Then the method "Name" on the first result should equal: "Changed Test Product"
|
|
39
|
+
And I call "update_object" on the service with the first last query result
|
|
40
40
|
And I save changes
|
|
41
41
|
Then the save result should equal: "true"
|
|
42
42
|
When I call "Products" on the service with args: "1"
|
|
43
43
|
And I run the query
|
|
44
|
-
Then the new query result's time "AuditFields.CreateDate" should equal the saved query result
|
|
44
|
+
Then the new query first result's time "AuditFields.CreateDate" should equal the saved query result
|
|
45
45
|
|
|
46
46
|
Scenario: DateTimes should be able to be null
|
|
47
47
|
Given I call "AddToProducts" on the service with a new "Product" object
|
|
48
48
|
And I save changes
|
|
49
49
|
When I call "Products" on the service
|
|
50
50
|
And I run the query
|
|
51
|
-
Then the "DiscontinuedDate" method should return a NilClass
|
|
51
|
+
Then the "DiscontinuedDate" method on the object should return a NilClass
|
|
52
52
|
|
|
53
53
|
|
data/lib/ruby_odata.rb
CHANGED
|
@@ -10,9 +10,12 @@ require 'rest_client'
|
|
|
10
10
|
require 'nokogiri'
|
|
11
11
|
require 'bigdecimal'
|
|
12
12
|
require 'bigdecimal/util'
|
|
13
|
+
require 'backports'
|
|
13
14
|
|
|
15
|
+
require lib + '/ruby_odata/association'
|
|
14
16
|
require lib + '/ruby_odata/property_metadata'
|
|
15
17
|
require lib + '/ruby_odata/query_builder'
|
|
16
18
|
require lib + '/ruby_odata/class_builder'
|
|
17
19
|
require lib + '/ruby_odata/operation'
|
|
18
|
-
require lib + '/ruby_odata/service'
|
|
20
|
+
require lib + '/ruby_odata/service'
|
|
21
|
+
require lib + '/ruby_odata/helpers'
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module OData
|
|
2
|
+
class Association
|
|
3
|
+
|
|
4
|
+
attr_reader :name, :namespace, :relationship, :from_role, :to_role
|
|
5
|
+
|
|
6
|
+
def initialize(nav_prop_element, edmx)
|
|
7
|
+
@edmx = edmx
|
|
8
|
+
|
|
9
|
+
# Get the edm namespace because it varies by version
|
|
10
|
+
edm_ns = @edmx.xpath("edmx:Edmx/edmx:DataServices/*", "edmx" => "http://schemas.microsoft.com/ado/2007/06/edmx").first.namespaces['xmlns'].to_s
|
|
11
|
+
@edmx_namespaces = { "edmx" => "http://schemas.microsoft.com/ado/2007/06/edmx", "edm" => edm_ns }
|
|
12
|
+
parse_nav_prop(nav_prop_element)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def parse_nav_prop(element)
|
|
18
|
+
@relationship = element['Relationship']
|
|
19
|
+
relationship_parts = @relationship.split('.')
|
|
20
|
+
@name = relationship_parts.pop
|
|
21
|
+
@namespace = relationship_parts.join('.')
|
|
22
|
+
@from_role = role_hash(@name, element['FromRole'])
|
|
23
|
+
@to_role = role_hash(@name, element['ToRole'])
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def role_hash(association_name, role_name)
|
|
27
|
+
# Find the end role based on the assocation name
|
|
28
|
+
role_xpath = "/edmx:Edmx/edmx:DataServices/edm:Schema[@Namespace='#{@namespace}']/edm:Association[@Name='#{association_name}']/edm:End[@Role='#{role_name}']"
|
|
29
|
+
role_element = @edmx.xpath(role_xpath, @edmx_namespaces).first
|
|
30
|
+
{ role_name => {
|
|
31
|
+
:edmx_type => "#{role_element['Type']}",
|
|
32
|
+
:multiplicity => "#{role_element['Multiplicity']}"
|
|
33
|
+
}}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -4,61 +4,99 @@ module OData
|
|
|
4
4
|
# Creates a new instance of the ClassBuilder class
|
|
5
5
|
#
|
|
6
6
|
# ==== Required Attributes
|
|
7
|
-
# - klass_name:
|
|
8
|
-
# - methods:
|
|
9
|
-
# - nav_props:
|
|
10
|
-
|
|
7
|
+
# - klass_name: The name/type of the class to create
|
|
8
|
+
# - methods: The accessor methods to add to the class
|
|
9
|
+
# - nav_props: The accessor methods to add for navigation properties
|
|
10
|
+
# - context: The service context that this entity belongs to
|
|
11
|
+
# - namespaces: Optional namespace to create the classes in
|
|
12
|
+
def initialize(klass_name, methods, nav_props, context, namespace = nil)
|
|
11
13
|
@klass_name = klass_name.camelcase
|
|
12
14
|
@methods = methods
|
|
13
15
|
@nav_props = nav_props
|
|
16
|
+
@context = context
|
|
17
|
+
@namespace = namespace
|
|
14
18
|
end
|
|
15
|
-
|
|
19
|
+
|
|
16
20
|
# Returns a dynamically generated class definition based on the constructor parameters
|
|
17
21
|
def build
|
|
18
22
|
# return if already built
|
|
19
23
|
return @klass unless @klass.nil?
|
|
20
|
-
|
|
24
|
+
|
|
21
25
|
# need the class name to build class
|
|
22
26
|
return nil if @klass_name.nil?
|
|
23
|
-
|
|
27
|
+
|
|
24
28
|
# return if we can find constant corresponding to class name
|
|
25
|
-
|
|
29
|
+
already_defined = eval("defined?(#{@klass_name}) == 'constant' and #{@klass_name}.class == Class")
|
|
30
|
+
if already_defined
|
|
26
31
|
@klass = @klass_name.constantize
|
|
27
32
|
return @klass
|
|
28
33
|
end
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
if @namespace
|
|
36
|
+
namespaces = @namespace.split(/\.|::/)
|
|
37
|
+
|
|
38
|
+
namespaces.each_with_index do |ns, index|
|
|
39
|
+
if index == 0
|
|
40
|
+
next if Object.const_defined? ns
|
|
41
|
+
Object.const_set(ns, Module.new)
|
|
42
|
+
else
|
|
43
|
+
current_ns = namespaces[0..index-1].join '::'
|
|
44
|
+
next if eval "#{current_ns}.const_defined? '#{ns}'"
|
|
45
|
+
eval "#{current_ns}.const_set('#{ns}', Module.new)"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
klass_constant = @klass_name.split('::').last
|
|
50
|
+
eval "#{namespaces.join '::'}.const_set('#{klass_constant}', Class.new.extend(ActiveSupport::JSON))"
|
|
51
|
+
else
|
|
52
|
+
Object.const_set(@klass_name, Class.new.extend(ActiveSupport::JSON))
|
|
53
|
+
end
|
|
54
|
+
|
|
31
55
|
@klass = @klass_name.constantize
|
|
32
56
|
@klass.class_eval do
|
|
33
57
|
include OData
|
|
34
58
|
end
|
|
35
59
|
|
|
60
|
+
add_initializer(@klass)
|
|
36
61
|
add_methods(@klass)
|
|
37
62
|
add_nav_props(@klass)
|
|
38
|
-
|
|
63
|
+
add_class_methods(@klass)
|
|
64
|
+
|
|
39
65
|
return @klass
|
|
40
66
|
end
|
|
41
|
-
|
|
67
|
+
|
|
42
68
|
private
|
|
69
|
+
def add_initializer(klass)
|
|
70
|
+
klass.send :define_method, :initialize do |*args|
|
|
71
|
+
return if args.blank?
|
|
72
|
+
props = args[0]
|
|
73
|
+
return unless props.is_a? Hash
|
|
74
|
+
props.each do |k,v|
|
|
75
|
+
raise NoMethodError, "undefined method `#{k}'" unless self.respond_to? k.to_sym
|
|
76
|
+
instance_variable_set("@#{k}", v)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
43
81
|
def add_methods(klass)
|
|
44
82
|
# Add metadata methods
|
|
45
83
|
klass.send :define_method, :__metadata do
|
|
46
84
|
instance_variable_get("@__metadata")
|
|
47
85
|
end
|
|
48
86
|
klass.send :define_method, :__metadata= do |value|
|
|
49
|
-
|
|
87
|
+
instance_variable_set("@__metadata", value)
|
|
50
88
|
end
|
|
51
89
|
klass.send :define_method, :as_json do |*args|
|
|
52
|
-
meta = RUBY_VERSION < "1.9" ? '@__metadata' :'@__metadata'.to_sym
|
|
90
|
+
meta = RUBY_VERSION < "1.9" ? '@__metadata' : ('@__metadata'.to_sym)
|
|
53
91
|
|
|
54
92
|
options = args[0] || {}
|
|
55
93
|
options[:type] ||= :unknown
|
|
56
94
|
|
|
57
95
|
vars = self.instance_values
|
|
58
96
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
97
|
+
if options[:type] == :add
|
|
98
|
+
# For adds, we need to get rid of all attributes except __metadata when passing
|
|
99
|
+
# the object to the server
|
|
62
100
|
vars.each_value do |value|
|
|
63
101
|
if value.is_a? OData
|
|
64
102
|
child_vars = value.instance_variables
|
|
@@ -89,6 +127,12 @@ module OData
|
|
|
89
127
|
vars[t[0]] = sdate
|
|
90
128
|
end
|
|
91
129
|
|
|
130
|
+
if options[:type] == :link
|
|
131
|
+
# For links, delete all of the vars and just add a uri
|
|
132
|
+
uri = self.__metadata[:uri]
|
|
133
|
+
vars = { 'uri' => uri }
|
|
134
|
+
end
|
|
135
|
+
|
|
92
136
|
vars
|
|
93
137
|
end
|
|
94
138
|
|
|
@@ -101,6 +145,23 @@ module OData
|
|
|
101
145
|
instance_variable_set("@#{method_name}", value)
|
|
102
146
|
end
|
|
103
147
|
end
|
|
148
|
+
|
|
149
|
+
# Add an id method pulling out the id from the uri (mainly for Pickle support)
|
|
150
|
+
klass.send :define_method, :id do
|
|
151
|
+
metadata = self.__metadata
|
|
152
|
+
id = nil
|
|
153
|
+
if metadata && metadata[:uri] =~ /\((\d+)\)$/
|
|
154
|
+
id = $~[1]
|
|
155
|
+
end
|
|
156
|
+
return (true if Integer(id) rescue false) ? id.to_i : id
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Override equals
|
|
160
|
+
klass.send :define_method, :== do |other|
|
|
161
|
+
self.class == other.class &&
|
|
162
|
+
self.id == other.id &&
|
|
163
|
+
self.__metadata == other.__metadata
|
|
164
|
+
end
|
|
104
165
|
end
|
|
105
166
|
|
|
106
167
|
def add_nav_props(klass)
|
|
@@ -113,5 +174,24 @@ module OData
|
|
|
113
174
|
end
|
|
114
175
|
end
|
|
115
176
|
end
|
|
177
|
+
|
|
178
|
+
def add_class_methods(klass)
|
|
179
|
+
context = @context
|
|
180
|
+
|
|
181
|
+
# Retrieves a list of properties defined on a type (standard and navigation properties)
|
|
182
|
+
klass.send :define_singleton_method, 'properties' do
|
|
183
|
+
context.class_metadata[klass.to_s] || {}
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Finds a single model by ID
|
|
187
|
+
klass.send :define_singleton_method, 'first' do |id|
|
|
188
|
+
return nil if id.nil?
|
|
189
|
+
# TODO: Instead of just pluralizing the klass name, use the actual collection name
|
|
190
|
+
collection = klass.to_s.pluralize
|
|
191
|
+
context.send "#{collection}", id
|
|
192
|
+
results = context.execute
|
|
193
|
+
results.count == 0 ? nil : results.first
|
|
194
|
+
end
|
|
195
|
+
end
|
|
116
196
|
end
|
|
117
197
|
end # module OData
|