yaccl 0.1.5 → 1.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
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