yaccl 0.1.5 → 1.0.pre.alpha

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/lib/yaccl/children.rb +55 -0
  3. data/lib/yaccl/connection.rb +147 -0
  4. data/lib/yaccl/document.rb +62 -0
  5. data/lib/yaccl/folder.rb +76 -0
  6. data/lib/yaccl/helpers.rb +59 -0
  7. data/lib/yaccl/item.rb +11 -0
  8. data/lib/yaccl/object.rb +122 -0
  9. data/lib/yaccl/object_factory.rb +27 -0
  10. data/lib/yaccl/policy.rb +26 -0
  11. data/lib/yaccl/property_definition.rb +32 -0
  12. data/lib/yaccl/query.rb +53 -0
  13. data/lib/yaccl/query_result.rb +15 -0
  14. data/lib/yaccl/relationship.rb +18 -0
  15. data/lib/yaccl/repository.rb +108 -0
  16. data/lib/yaccl/server.rb +37 -0
  17. data/lib/yaccl/type.rb +106 -0
  18. data/lib/yaccl/version.rb +1 -1
  19. data/lib/yaccl.rb +21 -11
  20. data/readme.md +0 -3
  21. data/spec/{model/document_spec.rb → document_spec.rb} +4 -4
  22. data/spec/{model/folder_spec.rb → folder_spec.rb} +6 -6
  23. data/spec/helper.rb +12 -12
  24. data/spec/{model/object_spec.rb → object_spec.rb} +6 -6
  25. data/spec/relationship_spec.rb +19 -0
  26. data/spec/repository_spec.rb +150 -0
  27. data/spec/server_spec.rb +22 -0
  28. data/spec/{model/type_spec.rb → type_spec.rb} +6 -4
  29. data/yaccl.gemspec +1 -0
  30. metadata +48 -50
  31. data/examples/create_type_manual.rb +0 -40
  32. data/lib/yaccl/model/document.rb +0 -68
  33. data/lib/yaccl/model/folder.rb +0 -74
  34. data/lib/yaccl/model/item.rb +0 -9
  35. data/lib/yaccl/model/object.rb +0 -159
  36. data/lib/yaccl/model/object_factory.rb +0 -24
  37. data/lib/yaccl/model/policy.rb +0 -20
  38. data/lib/yaccl/model/property_definition.rb +0 -66
  39. data/lib/yaccl/model/relationship.rb +0 -22
  40. data/lib/yaccl/model/repository.rb +0 -155
  41. data/lib/yaccl/model/server.rb +0 -13
  42. data/lib/yaccl/model/type.rb +0 -146
  43. data/lib/yaccl/model.rb +0 -11
  44. data/lib/yaccl/services/acl_services.rb +0 -23
  45. data/lib/yaccl/services/discovery_services.rb +0 -29
  46. data/lib/yaccl/services/internal/browser_binding_service.rb +0 -170
  47. data/lib/yaccl/services/internal/simple_cache.rb +0 -103
  48. data/lib/yaccl/services/multi_filing_services.rb +0 -22
  49. data/lib/yaccl/services/navigation_services.rb +0 -84
  50. data/lib/yaccl/services/object_services.rb +0 -211
  51. data/lib/yaccl/services/policy_services.rb +0 -30
  52. data/lib/yaccl/services/relationship_services.rb +0 -18
  53. data/lib/yaccl/services/repository_services.rb +0 -67
  54. data/lib/yaccl/services/versioning_services.rb +0 -69
  55. data/lib/yaccl/services.rb +0 -34
  56. data/spec/model/relationship_spec.rb +0 -15
  57. data/spec/model/repository_spec.rb +0 -138
  58. data/spec/model/server_spec.rb +0 -16
  59. data/spec/services/navigation_services_spec.rb +0 -64
  60. data/spec/services/object_services_spec.rb +0 -44
  61. data/spec/services/repository_services_spec.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2be620b3ea23dd8af7f061906eb36770615248c4
4
- data.tar.gz: df9cc9ddcb337eae01a20c6b844637c83071ff39
3
+ metadata.gz: 9199d278a1744c0fcfd31a290d40171fbba57a9d
4
+ data.tar.gz: 40f3bae9069f48696fe544760a44b90bf263d9c2
5
5
  SHA512:
6
- metadata.gz: 9a0d541919670208cd3609a2f3a7ce82752f6e4834c94cdaa7bd35bef2d664da23e057ce500efc82f86b7738c21d6de9f44bf047e74a2cfc1e0179636ce0a976
7
- data.tar.gz: 8af874ca863f0773d96c32f091eac49ea499d58db61aaff7ad214bf11d64126518fea02241e576e94bdfef442668c133076b11b1e33a629ef9ad6c7b66390636
6
+ metadata.gz: 0dc47bf5bb0cc9d71f5eb37fedc6f2dec2f204665d3d82bb0d2921583f225727136fb78c01d30f875fc69a32466ffadf6017d28eab17669886060dc035707d59
7
+ data.tar.gz: fb01d554a6688a03804b950df00a72eafb3d01a461d42feae11265cdfd2046c70f891439a01fa44eab98f4b8f5c021bfa1392a13cb2b4bd1daf22be2d00694ad
@@ -0,0 +1,55 @@
1
+ module YACCL
2
+ class Children
3
+
4
+ def initialize(folder, options)
5
+ options.stringify_keys!
6
+
7
+ @folder = folder
8
+ @repository = folder.repository
9
+ @connection = folder.repository.connection
10
+
11
+ @max_items = options['max_items'] || 10
12
+ @skip_count = options['skip_count'] || 0
13
+ @order_by = options['order_by']
14
+
15
+ @has_next = true
16
+ end
17
+
18
+ def next_results
19
+ result = do_get_children
20
+
21
+ @skip_count += result.results.size
22
+ @has_next = result.has_more_items
23
+ @total = result.num_items
24
+
25
+ result.results
26
+ end
27
+
28
+ def has_next?
29
+ @has_next
30
+ end
31
+
32
+ def total
33
+ @total ||= do_get_children.num_items
34
+ end
35
+
36
+
37
+ private
38
+
39
+ def do_get_children
40
+ result = @connection.execute!({ cmisselector: 'children',
41
+ repositoryId: @repository.id,
42
+ objectId: @folder.cmis_object_id,
43
+ maxItems: @max_items,
44
+ skipCount: @skip_count,
45
+ orderBy: @order_by })
46
+
47
+ results = result['objects'].map do |r|
48
+ ObjectFactory.create(r['object'], @repository)
49
+ end
50
+
51
+ QueryResult.new(results, result['numItems'], result['hasMoreItems'])
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,147 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'date'
3
+ require 'typhoeus'
4
+ require 'net/http/post/multipart'
5
+ require 'multi_json'
6
+
7
+ module YACCL
8
+
9
+ class CMISRequestError < Exception; end
10
+
11
+ class Connection
12
+
13
+ def initialize(service_url, username, password, headers = {})
14
+ @service_url = service_url
15
+ @username = username
16
+ @password = password
17
+ @headers = headers
18
+
19
+ @url_cache = {}
20
+ end
21
+
22
+ def execute!(params = {}, query = {}, headers = {})
23
+
24
+ url = get_url(params.delete(:repositoryId), params[:objectId])
25
+
26
+ params = transform_hash(params)
27
+
28
+ if params.has_key?(:cmisaction)
29
+ method = params.has_key?(:content) ? 'multipart_post' : 'post'
30
+ body = params
31
+ else
32
+ method = 'get'
33
+ body = nil
34
+ query.merge!(params)
35
+ end
36
+
37
+ response = perform_request(method: method,
38
+ url: url,
39
+ query: query,
40
+ body: body,
41
+ headers: headers)
42
+
43
+ result = response.body
44
+
45
+ content_type = if response.respond_to?(:content_type)
46
+ response.content_type
47
+ else
48
+ response.headers['Content-Type']
49
+ end
50
+
51
+ result = MultiJson.load(result) if content_type =~ /application\/json/
52
+ result = result.with_indifferent_access if result.is_a? Hash
53
+
54
+ unless (200...300).include?(response.code.to_i)
55
+ if result.is_a?(Hash) && result.has_key?(:exception)
56
+ raise CMISRequestError, "#{response.code} -- #{result[:exception]} -- #{result[:message]}"
57
+ else
58
+ raise CMISRequestError, "#{response.code} -- #{result}"
59
+ end
60
+ end
61
+
62
+ result
63
+ end
64
+
65
+ private
66
+
67
+ def get_url(repository_id, cmis_object_id)
68
+ if repository_id.nil?
69
+ @service_url
70
+ else
71
+ urls = repository_urls(repository_id)
72
+ if cmis_object_id
73
+ urls[:root_folder_url]
74
+ else
75
+ urls[:repository_url]
76
+ end
77
+ end
78
+ end
79
+
80
+ def repository_urls(repository_id)
81
+ if @url_cache[repository_id].nil?
82
+ repository_infos = MultiJson.load(perform_request(url: @service_url).body , symbolize_keys: false)
83
+ raise "No repository found with ID #{repository_id}." unless repository_infos.has_key?(repository_id)
84
+ repository_info = repository_infos[repository_id]
85
+ @url_cache[repository_id] = { repository_url: repository_info['repositoryUrl'],
86
+ root_folder_url: repository_info['rootFolderUrl'] }
87
+ end
88
+ @url_cache[repository_id]
89
+ end
90
+
91
+ def transform_hash(hash)
92
+ hash.reject! { |_, v| v.nil? }
93
+
94
+ if hash.has_key?(:content)
95
+ content = hash.delete(:content)
96
+ hash[:content] = UploadIO.new(content[:stream],
97
+ content[:mime_type],
98
+ content[:filename])
99
+ end # Move to multipart_post?
100
+
101
+ if hash.has_key?(:properties)
102
+ props = hash.delete(:properties)
103
+ if props.is_a?(Hash)
104
+ props.each_with_index do |(id, value), index|
105
+ value = value.to_time if value.is_a?(Date) or value.is_a?(DateTime)
106
+ value = (value.to_f * 1000).to_i if value.is_a?(Time)
107
+ if value.is_a?(Array)
108
+ hash.merge!("propertyId[#{index}]" => id)
109
+ value.each_with_index { |v, idx|
110
+ hash.merge!("propertyValue[#{index}][#{idx}]" => value[idx])
111
+ }
112
+ else
113
+ hash.merge!("propertyId[#{index}]" => id,
114
+ "propertyValue[#{index}]" => value)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ hash
120
+ end
121
+
122
+ def perform_request(options)
123
+ if options[:method] == 'multipart_post'
124
+ multipart_post(options)
125
+ else
126
+ typhoeus_request(options)
127
+ end
128
+ end
129
+
130
+ def typhoeus_request(options)
131
+ options[:params] = options.delete(:query)
132
+ options[:followlocation] = true
133
+ options[:userpwd] = "#{@username}:#{@password}" if @username
134
+ Typhoeus::Request.new(options.delete(:url), options).run
135
+ end
136
+
137
+ def multipart_post(options)
138
+ url = URI.parse(options[:url])
139
+ req = Net::HTTP::Post::Multipart.new(url.path, options[:body])
140
+ options[:headers].each {|key, value| req[key] = value }
141
+ req.basic_auth @username, @password if @username
142
+ opts = url.scheme == 'https' ? { use_ssl: true , verify_mode: OpenSSL::SSL::VERIFY_NONE } : {}
143
+ Net::HTTP.start(url.host, url.port, opts) { |http| http.request(req) }
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,62 @@
1
+ module YACCL
2
+ class Document < Object
3
+
4
+ def initialize(raw, repository)
5
+ super
6
+ cmis_properties %w( cmis:isImmutable cmis:isLatestVersion
7
+ cmis:isMajorVersion cmis:isLatestMajorVersion
8
+ cmis:isPrivateWorkingCopy cmis:versionLabel
9
+ cmis:versionSeriesId cmis:isVersionSeriesCheckedOut
10
+ cmis:versionSeriesCheckedOutBy
11
+ cmis:versionSeriesCheckedOutId cmis:checkinComment
12
+ cmis:contentStreamLength cmis:contentStreamMimeType
13
+ cmis:contentStreamFileName cmis:contentStreamId )
14
+ end
15
+
16
+ def create_in_folder(folder)
17
+ r = connection.execute!({ cmisaction: 'createDocument',
18
+ repositoryId: repository.id,
19
+ properties: properties,
20
+ objectId: folder.cmis_object_id,
21
+ folderId: folder.cmis_object_id,
22
+ content: @local_content })
23
+
24
+ ObjectFactory.create(r, repository)
25
+ end
26
+
27
+ def copy_in_folder(folder)
28
+ id = connection.execute!({ cmisaction: 'createDocument',
29
+ repositoryId: repository.id,
30
+ sourceId: cmis_object_id,
31
+ objectId: folder.cmis_object_id })
32
+
33
+ repository.object(id)
34
+ end
35
+
36
+ def content
37
+ connection.execute!({ cmisselector: 'content',
38
+ repositoryId: repository.id,
39
+ objectId: cmis_object_id })
40
+
41
+ rescue YACCL::CMISRequestError
42
+ nil
43
+ end
44
+
45
+ def set_content(stream, mime_type, filename)
46
+ content = { stream: stream,
47
+ mime_type: mime_type,
48
+ filename: filename }
49
+
50
+ if detached?
51
+ @local_content = content
52
+ else
53
+ update_change_token connection.execute!({ cmisaction: 'setContent',
54
+ repositoryId: repository.id,
55
+ objectId: cmis_object_id,
56
+ content: content,
57
+ changeToken:change_token })
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,76 @@
1
+ module YACCL
2
+ class Folder < Object
3
+
4
+ def initialize(raw, repository)
5
+ super
6
+ cmis_properties %w( cmis:parentId cmis:path
7
+ cmis:allowedChildObjectTypeIds )
8
+ end
9
+
10
+ def parent
11
+ repository.object(parent_id) if parent_id
12
+ end
13
+
14
+ def allowed_child_object_types
15
+ return nil unless allowed_child_object_type_ids
16
+ allowed_child_object_type_ids.map { |type_id| repository.type(type_id) }
17
+ end
18
+
19
+ def children(options = {})
20
+ Children.new(self, options)
21
+ end
22
+
23
+ def create(object)
24
+ case object
25
+ when Relationship
26
+ raise "'cmis:relationship' is not fileable. Use Repository#create_relationship"
27
+
28
+ when Document
29
+ return object.create_in_folder(self)
30
+
31
+ when Folder
32
+ o = connection.execute!({ cmisaction: 'createFolder',
33
+ repositoryId: repository.id,
34
+ properties: object.properties,
35
+ objectId: cmis_object_id })
36
+
37
+ when Policy
38
+ o = connection.execute!({ cmisaction: 'createPolicy',
39
+ repositoryId: repository.id,
40
+ properties: object.properties,
41
+ objectId: cmis_object_id })
42
+ when Item
43
+ o = connection.execute!({ cmisaction: 'createItem',
44
+ repositoryId: repository.id,
45
+ properties: object.properties,
46
+ objectId: cmis_object_id })
47
+
48
+ else
49
+ raise "Unexpected base_type_id: #{object.base_type_id}"
50
+ end
51
+
52
+ ObjectFactory.create(o, repository)
53
+ end
54
+
55
+ def delete_tree
56
+ connection.execute!({ cmisaction: 'deleteTree',
57
+ repositoryId: repository.id,
58
+ objectId: cmis_object_id })
59
+ end
60
+
61
+ def add(object)
62
+ connection.execute!({ cmisaction: 'addObjectToFolder',
63
+ repositoryId: repository.id,
64
+ objectId: object.cmis_object_id,
65
+ folderId: cmis_object_id })
66
+ end
67
+
68
+ def remove(object)
69
+ connection.execute!({ cmisaction: 'removeObjectFromFolder',
70
+ repositoryId: repository.id,
71
+ objectId: object.cmis_object_id,
72
+ folderId: cmis_object_id })
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module YACCL
4
+ module Helpers
5
+
6
+ def initialize_properties(raw)
7
+ @properties = get_properties_map(raw)
8
+ end
9
+
10
+ def cmis_properties(properties)
11
+ properties.each do |property_name|
12
+ method_name = method_name(property_name)
13
+ class_eval "def #{method_name};@properties['#{property_name}'];end"
14
+ class_eval "def #{method_name}=(value);@properties['#{property_name}']=value;end"
15
+ end
16
+ end
17
+
18
+ def update_change_token(r)
19
+ if r['properties']
20
+ @change_token = r['properties']['cmis:changeToken']['value']
21
+ elsif r['succinctProperties']
22
+ @change_token = r['succinctProperties']['cmis:changeToken']
23
+ else
24
+ raise "Unexpected hash: #{r}"
25
+ end
26
+ end
27
+
28
+
29
+ private
30
+
31
+ def method_name(property_name)
32
+ if property_name == 'cmis:objectId'
33
+ 'cmis_object_id'
34
+ else
35
+ property_name.gsub('cmis:', '').underscore
36
+ end
37
+ end
38
+
39
+ def get_properties_map(raw)
40
+ raw = raw.with_indifferent_access
41
+
42
+ if raw['succinctProperties']
43
+ result = raw['succinctProperties']
44
+ elsif raw['properties']
45
+ result = raw['properties'].inject({}) do |h, (k, v)|
46
+ val = v['value']
47
+ val = v['value'].first if v['value'].is_a?(Array) and v['cardinality'] == 'single'
48
+ val = Time.at(val / 1000) if val and v['type'] == 'datetime'
49
+ h.merge(k => val)
50
+ end
51
+ else
52
+ result = {}
53
+ end
54
+
55
+ result.with_indifferent_access
56
+ end
57
+
58
+ end
59
+ end
data/lib/yaccl/item.rb ADDED
@@ -0,0 +1,11 @@
1
+ module YACCL
2
+
3
+ class Item < Object
4
+
5
+ def initialize(raw, repository)
6
+ super
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,122 @@
1
+ module YACCL
2
+ class Object
3
+
4
+ include Helpers
5
+
6
+ attr_reader :connection
7
+ attr_reader :repository
8
+ attr_accessor :properties
9
+
10
+ def initialize(raw, repository)
11
+ initialize_properties(raw)
12
+ cmis_properties %w( cmis:objectId cmis:baseTypeId cmis:objectTypeId
13
+ cmis:secondaryObjectTypeIds cmis:name cmis:description
14
+ cmis:createdBy cmis:creationDate cmis:lastModifiedBy
15
+ cmis:lastModificationDate cmis:changeToken )
16
+
17
+ @repository = repository
18
+ @connection = repository.connection
19
+ end
20
+
21
+ def object_type
22
+ repository.type(object_type_id)
23
+ end
24
+
25
+ def delete
26
+ connection.execute!({ cmisaction: 'delete',
27
+ repositoryId: repository.id,
28
+ objectId: cmis_object_id,
29
+ allVersions: true })
30
+ end
31
+
32
+ def update_properties(properties)
33
+ update_change_token connection.execute!({ cmisaction: 'update',
34
+ repositoryId: repository.id,
35
+ objectId: cmis_object_id,
36
+ properties: properties,
37
+ changeToken: change_token })
38
+ end
39
+
40
+ def parents
41
+ result = connection.execute!({ cmisselector: 'parents',
42
+ repositoryId: repository.id,
43
+ objectId: cmis_object_id })
44
+
45
+ result.map { |o| ObjectFactory.create(o['object'], repository) }
46
+ end
47
+
48
+ def allowable_actions
49
+ connection.execute!({ cmisselector: 'allowableActions',
50
+ repositoryId: repository.id,
51
+ objectId: cmis_object_id })
52
+ end
53
+
54
+ def relationships(direction = :either)
55
+ result = connection.execute!({ cmisselector: 'relationships',
56
+ repositoryId: repository.id,
57
+ objectId: cmis_object_id,
58
+ relationshipDirection: direction })
59
+
60
+ result['objects'].map { |r| Relationship.new(r, repository) }
61
+ end
62
+
63
+ def policies
64
+ result = connection.execute!({ cmisselector: 'policies',
65
+ repositoryId: repository.id,
66
+ objectId: cmis_object_id })
67
+
68
+
69
+
70
+ result.map { |r| Policy.new(r, repository) }
71
+ end
72
+
73
+ # By default removes from all folders
74
+ def unfile(folder = nil)
75
+ options = { repositoryId: repository.id,
76
+ cmisaction: 'removeObjectFromFolder',
77
+ objectId: cmis_object_id }
78
+ options[:folderId] = folder.cmis_object_id if folder
79
+
80
+ connection.execute!(options)
81
+ end
82
+
83
+ def move(target_folder)
84
+ object_parents = parents
85
+
86
+ unless object_parents.size == 1
87
+ raise 'Cannot move object because it is not in excatly one folder'
88
+ end
89
+
90
+ connection.execute!({ cmisaction: 'move',
91
+ repositoryId: repository.id,
92
+ objectId: cmis_object_id,
93
+ targetFolderId: target_folder.cmis_object_id,
94
+ sourceFolderId: object_parents.first.cmis_object_id })
95
+ end
96
+
97
+ def acls
98
+ connection.execute!({ cmisselector: 'acl',
99
+ repositoryId: repository.id,
100
+ objectId: cmis_object_id })
101
+ end
102
+
103
+ def add_aces(aces)
104
+ connection.execute!({ cmisaction: 'applyACL',
105
+ repositoryId: repository.id,
106
+ objectId: cmis_object_id,
107
+ addACEs: aces })
108
+ end
109
+
110
+ def remove_aces(aces)
111
+ connection.execute!({ cmisaction: 'applyACL',
112
+ repositoryId: repository.id,
113
+ objectId: cmis_object_id,
114
+ removeACEs: aces })
115
+ end
116
+
117
+ def detached?
118
+ cmis_object_id.nil?
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,27 @@
1
+ module YACCL
2
+ class ObjectFactory
3
+
4
+ def self.create(raw, repository)
5
+ case base_type_id(raw)
6
+ when 'cmis:folder' then Folder.new(raw, repository)
7
+ when 'cmis:document' then Document.new(raw, repository)
8
+ when 'cmis:relationship' then Relationship.new(raw, repository)
9
+ when 'cmis:policy' then Policy.new(raw, repository)
10
+ when 'cmis:item' then Item.new(raw, repository)
11
+ else raise "Unexpected baseTypeId: #{base_type_id}."
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def self.base_type_id(raw)
18
+ if raw['properties']
19
+ raw['properties']['cmis:baseTypeId']['value']
20
+ elsif raw['succinctProperties']
21
+ raw['succinctProperties']['cmis:baseTypeId']
22
+ else
23
+ raise "Unexpected json: #{raw}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module YACCL
2
+ class Policy < Object
3
+
4
+ attr_reader :policy_text
5
+
6
+ def initialize(raw, repository)
7
+ super
8
+ cmis_properties %w( cmis:policyText )
9
+ end
10
+
11
+ def apply_to(object)
12
+ connection.execute!({ cmisaction: 'applyPolicy',
13
+ repositoryId: repository_id,
14
+ policyId: cmis_object_id,
15
+ objectId: object.cmis_object_id })
16
+ end
17
+
18
+ def remove_from(object)
19
+ connection.execute!({ cmisaction: 'removePolicy',
20
+ repositoryId: repository_id,
21
+ policyId: cmis_object_id,
22
+ objectId: object.cmis_object_id })
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module YACCL
4
+ class PropertyDefinition
5
+
6
+ def initialize(hash = {})
7
+ @hash = hash.with_indifferent_access
8
+
9
+ @hash.each_key do |key|
10
+ class_eval "def #{key.underscore};@hash['#{key}'];end"
11
+ class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
12
+ end
13
+ end
14
+
15
+ def readonly?
16
+ updatability == 'readonly'
17
+ end
18
+
19
+ def oncreate?
20
+ updatability == 'oncreate'
21
+ end
22
+
23
+ def readwrite?
24
+ updatability == 'readwrite'
25
+ end
26
+
27
+ def to_hash
28
+ @hash
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ module YACCL
2
+ class Query
3
+
4
+ def initialize(repository, statement, options)
5
+ options.stringify_keys!
6
+
7
+ @repository = repository
8
+ @connection = repository.connection
9
+
10
+ @statement = statement
11
+ @max_items = options['max_items'] || 10
12
+ @skip_count = options['skip_count'] || 0
13
+
14
+ @has_next = true
15
+ end
16
+
17
+ def next_results
18
+ result = do_query
19
+
20
+ @skip_count += result.results.size
21
+ @has_next = result.has_more_items
22
+ @total = result.num_items
23
+
24
+ result.results
25
+ end
26
+
27
+ def has_next?
28
+ @has_next
29
+ end
30
+
31
+ def total
32
+ @total ||= do_query.num_items
33
+ end
34
+
35
+
36
+ private
37
+
38
+ def do_query
39
+ result = @connection.execute!({ cmisselector: 'query',
40
+ repositoryId: @repository.id,
41
+ q: @statement,
42
+ maxItems: @max_items,
43
+ skipCount: @skip_count })
44
+
45
+ results = result['results'].map do |r|
46
+ ObjectFactory.create(r, @repository)
47
+ end
48
+
49
+ QueryResult.new(results, result['numItems'], result['hasMoreItems'])
50
+ end
51
+
52
+ end
53
+ end