mongo 2.1.0.beta → 2.1.0.rc0
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Rakefile +2 -2
- data/lib/mongo.rb +2 -3
- data/lib/mongo/address.rb +7 -5
- data/lib/mongo/address/unix.rb +2 -2
- data/lib/mongo/auth/ldap/conversation.rb +6 -2
- data/lib/mongo/auth/scram/conversation.rb +8 -2
- data/lib/mongo/auth/user/view.rb +21 -0
- data/lib/mongo/bulk_write.rb +155 -23
- data/lib/mongo/bulk_write/combineable.rb +51 -0
- data/lib/mongo/bulk_write/ordered_combiner.rb +55 -0
- data/lib/mongo/bulk_write/result.rb +61 -8
- data/lib/mongo/bulk_write/result_combiner.rb +117 -0
- data/lib/mongo/bulk_write/transformable.rb +117 -0
- data/lib/mongo/bulk_write/unordered_combiner.rb +52 -0
- data/lib/mongo/bulk_write/validatable.rb +62 -0
- data/lib/mongo/client.rb +7 -3
- data/lib/mongo/cluster.rb +3 -3
- data/lib/mongo/cluster/topology/replica_set.rb +8 -6
- data/lib/mongo/cluster/topology/unknown.rb +5 -2
- data/lib/mongo/collection.rb +75 -4
- data/lib/mongo/collection/view.rb +1 -2
- data/lib/mongo/collection/view/aggregation.rb +13 -8
- data/lib/mongo/collection/view/immutable.rb +6 -6
- data/lib/mongo/collection/view/iterable.rb +13 -4
- data/lib/mongo/collection/view/map_reduce.rb +22 -17
- data/lib/mongo/collection/view/readable.rb +121 -70
- data/lib/mongo/cursor.rb +5 -1
- data/lib/mongo/database.rb +3 -3
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/error.rb +7 -0
- data/lib/mongo/{bulk_write/unordered_bulk_write.rb → error/closed_stream.rb} +12 -21
- data/lib/mongo/{bulk_write/ordered_bulk_write.rb → error/extra_file_chunk.rb} +13 -27
- data/lib/mongo/error/file_not_found.rb +37 -0
- data/lib/mongo/error/invalid_file.rb +2 -2
- data/lib/mongo/error/invalid_file_revision.rb +37 -0
- data/lib/mongo/error/invalid_uri.rb +5 -4
- data/lib/mongo/error/missing_file_chunk.rb +38 -0
- data/lib/mongo/error/operation_failure.rb +1 -1
- data/lib/mongo/error/unchangeable_collection_option.rb +38 -0
- data/lib/mongo/error/unexpected_chunk_length.rb +39 -0
- data/lib/mongo/grid.rb +2 -1
- data/lib/mongo/grid/file.rb +12 -9
- data/lib/mongo/grid/file/chunk.rb +6 -6
- data/lib/mongo/grid/file/{metadata.rb → info.rb} +41 -39
- data/lib/mongo/grid/fs_bucket.rb +441 -0
- data/lib/mongo/grid/stream.rb +64 -0
- data/lib/mongo/grid/stream/read.rb +208 -0
- data/lib/mongo/grid/stream/write.rb +187 -0
- data/lib/mongo/index/view.rb +1 -1
- data/lib/mongo/loggable.rb +34 -57
- data/lib/mongo/logger.rb +16 -78
- data/lib/mongo/monitoring.rb +1 -5
- data/lib/mongo/monitoring/command_log_subscriber.rb +35 -17
- data/lib/mongo/monitoring/event/command_succeeded.rb +20 -1
- data/lib/mongo/monitoring/publishable.rb +22 -12
- data/lib/mongo/operation.rb +3 -6
- data/lib/mongo/operation/commands.rb +24 -0
- data/lib/mongo/operation/{aggregate.rb → commands/aggregate.rb} +3 -41
- data/lib/mongo/operation/{aggregate → commands/aggregate}/result.rb +0 -0
- data/lib/mongo/operation/commands/collections_info.rb +66 -0
- data/lib/mongo/operation/{command.rb → commands/command.rb} +2 -18
- data/lib/mongo/operation/commands/indexes.rb +70 -0
- data/lib/mongo/operation/commands/list_collections.rb +54 -0
- data/lib/mongo/operation/commands/list_collections/result.rb +112 -0
- data/lib/mongo/operation/commands/list_indexes.rb +56 -0
- data/lib/mongo/operation/commands/list_indexes/result.rb +115 -0
- data/lib/mongo/operation/{map_reduce.rb → commands/map_reduce.rb} +3 -41
- data/lib/mongo/operation/{map_reduce → commands/map_reduce}/result.rb +0 -0
- data/lib/mongo/operation/{parallel_scan.rb → commands/parallel_scan.rb} +3 -23
- data/lib/mongo/operation/{parallel_scan → commands/parallel_scan}/result.rb +0 -0
- data/lib/mongo/operation/commands/user_query.rb +69 -0
- data/lib/mongo/operation/commands/users_info.rb +53 -0
- data/lib/mongo/operation/commands/users_info/result.rb +36 -0
- data/lib/mongo/operation/executable.rb +4 -68
- data/lib/mongo/operation/kill_cursors.rb +3 -3
- data/lib/mongo/operation/read.rb +0 -4
- data/lib/mongo/operation/read/get_more.rb +2 -22
- data/lib/mongo/operation/read/query.rb +2 -21
- data/lib/mongo/operation/{read_preferrable.rb → read_preference.rb} +3 -2
- data/lib/mongo/operation/specifiable.rb +24 -0
- data/lib/mongo/operation/write.rb +2 -0
- data/lib/mongo/operation/write/bulk.rb +6 -3
- data/lib/mongo/operation/write/bulk/bulkable.rb +82 -0
- data/lib/mongo/operation/write/bulk/delete.rb +71 -0
- data/lib/mongo/operation/write/bulk/delete/result.rb +74 -0
- data/lib/mongo/operation/write/bulk/insert.rb +96 -0
- data/lib/mongo/operation/write/bulk/insert/result.rb +129 -0
- data/lib/mongo/operation/write/bulk/legacy_mergable.rb +87 -0
- data/lib/mongo/operation/write/bulk/mergable.rb +71 -0
- data/lib/mongo/operation/write/bulk/update.rb +81 -0
- data/lib/mongo/operation/write/bulk/update/result.rb +174 -0
- data/lib/mongo/operation/write/command/create_index.rb +0 -1
- data/lib/mongo/operation/write/command/create_user.rb +0 -1
- data/lib/mongo/operation/write/command/delete.rb +0 -1
- data/lib/mongo/operation/write/command/drop_index.rb +0 -1
- data/lib/mongo/operation/write/command/insert.rb +0 -1
- data/lib/mongo/operation/write/command/remove_user.rb +0 -1
- data/lib/mongo/operation/write/command/update.rb +0 -1
- data/lib/mongo/operation/write/command/update_user.rb +0 -1
- data/lib/mongo/operation/write/command/writable.rb +13 -18
- data/lib/mongo/operation/write/create_index.rb +4 -27
- data/lib/mongo/operation/write/create_user.rb +4 -30
- data/lib/mongo/operation/write/delete.rb +5 -28
- data/lib/mongo/operation/write/drop_index.rb +3 -3
- data/lib/mongo/operation/write/gle.rb +48 -0
- data/lib/mongo/operation/write/idable.rb +5 -0
- data/lib/mongo/operation/write/insert.rb +2 -24
- data/lib/mongo/operation/write/remove_user.rb +4 -27
- data/lib/mongo/operation/write/update.rb +4 -32
- data/lib/mongo/operation/write/update_user.rb +4 -30
- data/lib/mongo/operation/write/write_command_enabled.rb +53 -0
- data/lib/mongo/options/mapper.rb +4 -2
- data/lib/mongo/protocol/delete.rb +68 -3
- data/lib/mongo/protocol/get_more.rb +54 -2
- data/lib/mongo/protocol/insert.rb +59 -1
- data/lib/mongo/protocol/kill_cursors.rb +53 -4
- data/lib/mongo/protocol/message.rb +12 -12
- data/lib/mongo/protocol/query.rb +139 -65
- data/lib/mongo/protocol/reply.rb +69 -1
- data/lib/mongo/protocol/update.rb +70 -1
- data/lib/mongo/server/connection.rb +11 -3
- data/lib/mongo/server/description.rb +29 -0
- data/lib/mongo/server/description/features.rb +2 -1
- data/lib/mongo/server/monitor.rb +2 -2
- data/lib/mongo/server_selector.rb +14 -10
- data/lib/mongo/server_selector/selectable.rb +24 -22
- data/lib/mongo/socket.rb +6 -3
- data/lib/mongo/socket/tcp.rb +2 -2
- data/lib/mongo/socket/unix.rb +5 -8
- data/lib/mongo/uri.rb +243 -139
- data/lib/mongo/version.rb +1 -1
- data/spec/mongo/address/unix_spec.rb +1 -1
- data/spec/mongo/address_spec.rb +25 -0
- data/spec/mongo/auth/ldap/conversation_spec.rb +43 -0
- data/spec/mongo/auth/user/view_spec.rb +26 -1
- data/spec/mongo/bulk_write/ordered_combiner_spec.rb +271 -0
- data/spec/mongo/bulk_write/unordered_combiner_spec.rb +239 -0
- data/spec/mongo/bulk_write_spec.rb +332 -166
- data/spec/mongo/client_spec.rb +25 -0
- data/spec/mongo/cluster/topology/replica_set_spec.rb +2 -0
- data/spec/mongo/collection/view/aggregation_spec.rb +65 -0
- data/spec/mongo/collection/view/immutable_spec.rb +103 -0
- data/spec/mongo/collection/view/map_reduce_spec.rb +98 -3
- data/spec/mongo/collection/view/readable_spec.rb +17 -30
- data/spec/mongo/collection/view_spec.rb +233 -7
- data/spec/mongo/collection_spec.rb +360 -18
- data/spec/mongo/command_monitoring_spec.rb +51 -0
- data/spec/mongo/connection_string_spec.rb +137 -0
- data/spec/mongo/database_spec.rb +27 -11
- data/spec/mongo/grid/file/chunk_spec.rb +5 -5
- data/spec/mongo/grid/file/{metadata_spec.rb → info_spec.rb} +29 -17
- data/spec/mongo/grid/file_spec.rb +8 -8
- data/spec/mongo/grid/fs_bucket_spec.rb +1020 -0
- data/spec/mongo/grid/stream/read_spec.rb +275 -0
- data/spec/mongo/grid/stream/write_spec.rb +440 -0
- data/spec/mongo/grid/stream_spec.rb +48 -0
- data/spec/mongo/gridfs_spec.rb +50 -0
- data/spec/mongo/logger_spec.rb +0 -40
- data/spec/mongo/monitoring/command_log_subscriber_spec.rb +76 -0
- data/spec/mongo/operation/{aggregate_spec.rb → commands/aggregate_spec.rb} +0 -42
- data/spec/mongo/operation/{read → commands}/collections_info_spec.rb +1 -1
- data/spec/mongo/operation/{command_spec.rb → commands/command_spec.rb} +0 -0
- data/spec/mongo/operation/{read → commands}/indexes_spec.rb +1 -1
- data/spec/mongo/operation/{map_reduce_spec.rb → commands/map_reduce_spec.rb} +0 -18
- data/spec/mongo/operation/kill_cursors_spec.rb +1 -1
- data/spec/mongo/operation/{read_preferrable_spec.rb → read_preference_spec.rb} +11 -11
- data/spec/mongo/operation/write/bulk/{bulk_delete_spec.rb → delete_spec.rb} +1 -12
- data/spec/mongo/operation/write/bulk/{bulk_insert_spec.rb → insert_spec.rb} +1 -12
- data/spec/mongo/operation/write/bulk/{bulk_update_spec.rb → update_spec.rb} +1 -12
- data/spec/mongo/operation/write/insert_spec.rb +0 -11
- data/spec/mongo/protocol/kill_cursors_spec.rb +5 -3
- data/spec/mongo/server/description_spec.rb +42 -0
- data/spec/mongo/server/monitor_spec.rb +21 -0
- data/spec/mongo/server_discovery_and_monitoring_spec.rb +1 -0
- data/spec/mongo/server_selection_spec.rb +3 -3
- data/spec/mongo/server_selector/nearest_spec.rb +34 -27
- data/spec/mongo/server_selector/primary_preferred_spec.rb +31 -30
- data/spec/mongo/server_selector/primary_spec.rb +14 -13
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +27 -26
- data/spec/mongo/server_selector/secondary_spec.rb +23 -22
- data/spec/mongo/server_selector_spec.rb +87 -24
- data/spec/mongo/socket/unix_spec.rb +52 -0
- data/spec/mongo/uri_spec.rb +251 -39
- data/spec/spec_helper.rb +11 -4
- data/spec/support/authorization.rb +4 -5
- data/spec/support/command_monitoring.rb +365 -0
- data/spec/support/command_monitoring/bulkWrite.yml +73 -0
- data/spec/support/command_monitoring/command.yml +42 -0
- data/spec/support/command_monitoring/deleteMany.yml +55 -0
- data/spec/support/command_monitoring/deleteOne.yml +55 -0
- data/spec/support/command_monitoring/find.yml +219 -0
- data/spec/support/command_monitoring/insertMany.yml +81 -0
- data/spec/support/command_monitoring/insertOne.yml +51 -0
- data/spec/support/command_monitoring/updateMany.yml +67 -0
- data/spec/support/command_monitoring/updateOne.yml +95 -0
- data/spec/support/connection_string.rb +228 -0
- data/spec/support/connection_string_tests/invalid-uris.yml +193 -0
- data/spec/support/connection_string_tests/valid-auth.yml +256 -0
- data/spec/support/connection_string_tests/valid-host_identifiers.yml +121 -0
- data/spec/support/connection_string_tests/valid-options.yml +30 -0
- data/spec/support/connection_string_tests/valid-unix_socket-absolute.yml +197 -0
- data/spec/support/connection_string_tests/valid-unix_socket-relative.yml +213 -0
- data/spec/support/connection_string_tests/valid-warnings.yml +55 -0
- data/spec/support/crud.rb +3 -1
- data/spec/support/crud/read.rb +14 -10
- data/spec/support/crud/write.rb +36 -9
- data/spec/support/gridfs.rb +637 -0
- data/spec/support/gridfs_tests/delete.yml +157 -0
- data/spec/support/gridfs_tests/download.yml +210 -0
- data/spec/support/gridfs_tests/download_by_name.yml +113 -0
- data/spec/support/gridfs_tests/upload.yml +158 -0
- data/spec/support/sdam/rs/equal_electionids.yml +1 -2
- data/spec/support/sdam/rs/new_primary_new_electionid.yml +0 -3
- data/spec/support/sdam/rs/primary_mismatched_me.yml +37 -0
- data/spec/support/sdam/rs/primary_to_no_primary_mismatched_me.yml +75 -0
- data/spec/support/sdam/rs/secondary_mismatched_me.yml +37 -0
- data/spec/support/sdam/single/direct_connection_rsarbiter.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rsprimary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_rssecondary.yml +1 -1
- data/spec/support/sdam/single/direct_connection_slave.yml +1 -1
- data/spec/support/sdam/single/direct_connection_standalone.yml +1 -1
- data/spec/support/sdam/single/not_ok_response.yml +0 -1
- data/spec/support/server_discovery_and_monitoring.rb +3 -1
- data/spec/support/server_selection.rb +3 -1
- data/spec/support/shared/bulk_write.rb +192 -0
- data/spec/support/shared/server_selector.rb +21 -12
- metadata +147 -57
- metadata.gz.sig +0 -0
- data/lib/mongo/bulk_write/bulk_writable.rb +0 -252
- data/lib/mongo/bulk_write/deletable.rb +0 -57
- data/lib/mongo/bulk_write/insertable.rb +0 -49
- data/lib/mongo/bulk_write/replacable.rb +0 -58
- data/lib/mongo/bulk_write/updatable.rb +0 -69
- data/lib/mongo/grid/fs.rb +0 -146
- data/lib/mongo/operation/list_collections/result.rb +0 -114
- data/lib/mongo/operation/list_indexes/result.rb +0 -118
- data/lib/mongo/operation/read/collections_info.rb +0 -68
- data/lib/mongo/operation/read/indexes.rb +0 -69
- data/lib/mongo/operation/read/list_collections.rb +0 -76
- data/lib/mongo/operation/read/list_indexes.rb +0 -78
- data/lib/mongo/operation/write/bulk/bulk_delete.rb +0 -145
- data/lib/mongo/operation/write/bulk/bulk_delete/result.rb +0 -75
- data/lib/mongo/operation/write/bulk/bulk_insert.rb +0 -132
- data/lib/mongo/operation/write/bulk/bulk_insert/result.rb +0 -130
- data/lib/mongo/operation/write/bulk/bulk_mergable.rb +0 -67
- data/lib/mongo/operation/write/bulk/bulk_update.rb +0 -154
- data/lib/mongo/operation/write/bulk/bulk_update/result.rb +0 -174
- data/lib/mongo/operation/write/bulk/legacy_bulk_mergable.rb +0 -83
- data/spec/mongo/grid/fs_spec.rb +0 -160
- data/spec/mongo/loggable_spec.rb +0 -63
@@ -160,17 +160,17 @@ module Mongo
|
|
160
160
|
# Chunks.split(data)
|
161
161
|
#
|
162
162
|
# @param [ String ] data The raw bytes.
|
163
|
-
# @param [
|
163
|
+
# @param [ File::Info ] file_info The files collection file doc.
|
164
164
|
#
|
165
165
|
# @return [ Array<Chunk> ] The chunks of the data.
|
166
166
|
#
|
167
167
|
# @since 2.0.0
|
168
|
-
def split(data,
|
169
|
-
chunks, index, n = [], 0,
|
168
|
+
def split(data, file_info, offset = 0)
|
169
|
+
chunks, index, n = [], 0, offset
|
170
170
|
while index < data.length
|
171
|
-
bytes = data.slice(index,
|
172
|
-
|
173
|
-
chunk = Chunk.new(:data => BSON::Binary.new(bytes), :files_id =>
|
171
|
+
bytes = data.slice(index, file_info.chunk_size)
|
172
|
+
file_info.md5.update(bytes)
|
173
|
+
chunk = Chunk.new(:data => BSON::Binary.new(bytes), :files_id => file_info.id, :n => n)
|
174
174
|
chunks.push(chunk)
|
175
175
|
index += bytes.length
|
176
176
|
n += 1
|
@@ -16,10 +16,10 @@ module Mongo
|
|
16
16
|
module Grid
|
17
17
|
class File
|
18
18
|
|
19
|
-
# Encapsulates behaviour around GridFS file
|
19
|
+
# Encapsulates behaviour around GridFS files collection file document.
|
20
20
|
#
|
21
21
|
# @since 2.0.0
|
22
|
-
class
|
22
|
+
class Info
|
23
23
|
|
24
24
|
# Name of the files collection.
|
25
25
|
#
|
@@ -35,8 +35,10 @@ module Mongo
|
|
35
35
|
:filename => :filename,
|
36
36
|
:_id => :_id,
|
37
37
|
:md5 => :md5,
|
38
|
+
:length => :length,
|
38
39
|
:metadata => :metadata,
|
39
|
-
:upload_date => :uploadDate
|
40
|
+
:upload_date => :uploadDate,
|
41
|
+
:aliases => :aliases
|
40
42
|
}.freeze
|
41
43
|
|
42
44
|
# Default content type for stored files.
|
@@ -44,13 +46,13 @@ module Mongo
|
|
44
46
|
# @since 2.0.0
|
45
47
|
DEFAULT_CONTENT_TYPE = 'binary/octet-stream'.freeze
|
46
48
|
|
47
|
-
# @return [ BSON::Document ] document The
|
49
|
+
# @return [ BSON::Document ] document The files collection document.
|
48
50
|
attr_reader :document
|
49
51
|
|
50
|
-
# Is this
|
52
|
+
# Is this file information document equal to another?
|
51
53
|
#
|
52
|
-
# @example Check
|
53
|
-
#
|
54
|
+
# @example Check file information document equality.
|
55
|
+
# file_info == other
|
54
56
|
#
|
55
57
|
# @param [ Object ] other The object to check against.
|
56
58
|
#
|
@@ -58,14 +60,14 @@ module Mongo
|
|
58
60
|
#
|
59
61
|
# @since 2.0.0
|
60
62
|
def ==(other)
|
61
|
-
return false unless other.is_a?(
|
63
|
+
return false unless other.is_a?(Info)
|
62
64
|
document == other.document
|
63
65
|
end
|
64
66
|
|
65
|
-
# Get the BSON type for a
|
67
|
+
# Get the BSON type for a files information document.
|
66
68
|
#
|
67
69
|
# @example Get the BSON type.
|
68
|
-
#
|
70
|
+
# file_info.bson_type
|
69
71
|
#
|
70
72
|
# @return [ Integer ] The BSON type.
|
71
73
|
#
|
@@ -74,10 +76,10 @@ module Mongo
|
|
74
76
|
BSON::Hash::BSON_TYPE
|
75
77
|
end
|
76
78
|
|
77
|
-
# Get the
|
79
|
+
# Get the file chunk size.
|
78
80
|
#
|
79
81
|
# @example Get the chunk size.
|
80
|
-
#
|
82
|
+
# file_info.chunk_size
|
81
83
|
#
|
82
84
|
# @return [ Integer ] The chunksize in bytes.
|
83
85
|
#
|
@@ -86,10 +88,10 @@ module Mongo
|
|
86
88
|
document[:chunkSize]
|
87
89
|
end
|
88
90
|
|
89
|
-
# Get the
|
91
|
+
# Get the file information content type.
|
90
92
|
#
|
91
93
|
# @example Get the content type.
|
92
|
-
#
|
94
|
+
# file_info.content_type
|
93
95
|
#
|
94
96
|
# @return [ String ] The content type.
|
95
97
|
#
|
@@ -98,32 +100,32 @@ module Mongo
|
|
98
100
|
document[:contentType]
|
99
101
|
end
|
100
102
|
|
101
|
-
# Get the
|
103
|
+
# Get the filename from the file information.
|
102
104
|
#
|
103
105
|
# @example Get the filename.
|
104
|
-
#
|
106
|
+
# file_info.filename
|
105
107
|
#
|
106
108
|
# @return [ String ] The filename.
|
107
109
|
def filename
|
108
110
|
document[:filename]
|
109
111
|
end
|
110
112
|
|
111
|
-
# Get the
|
113
|
+
# Get the file id from the file information.
|
112
114
|
#
|
113
|
-
# @example Get the
|
114
|
-
#
|
115
|
+
# @example Get the file id.
|
116
|
+
# file_info.id
|
115
117
|
#
|
116
|
-
# @return [ BSON::ObjectId ] The
|
118
|
+
# @return [ BSON::ObjectId ] The file id.
|
117
119
|
#
|
118
120
|
# @since 2.0.0
|
119
121
|
def id
|
120
122
|
document[:_id]
|
121
123
|
end
|
122
124
|
|
123
|
-
# Create the new
|
125
|
+
# Create the new file information document.
|
124
126
|
#
|
125
|
-
# @example Create the new
|
126
|
-
#
|
127
|
+
# @example Create the new file information document.
|
128
|
+
# Info.new(:filename => 'test.txt')
|
127
129
|
#
|
128
130
|
# @param [ BSON::Document ] document The document to create from.
|
129
131
|
#
|
@@ -135,23 +137,23 @@ module Mongo
|
|
135
137
|
|
136
138
|
# Get a readable inspection for the object.
|
137
139
|
#
|
138
|
-
# @example Inspect the
|
139
|
-
#
|
140
|
+
# @example Inspect the file information.
|
141
|
+
# file_info.inspect
|
140
142
|
#
|
141
143
|
# @return [ String ] The nice inspection.
|
142
144
|
#
|
143
145
|
# @since 2.0.0
|
144
146
|
def inspect
|
145
|
-
"#<Mongo::Grid::File::
|
147
|
+
"#<Mongo::Grid::File::Info:0x#{object_id} chunk_size=#{chunk_size} " +
|
146
148
|
"filename=#{filename} content_type=#{content_type} id=#{id} md5=#{md5}>"
|
147
149
|
end
|
148
150
|
|
149
151
|
# Get the length of the document in bytes.
|
150
152
|
#
|
151
|
-
# @example Get the length
|
152
|
-
#
|
153
|
+
# @example Get the file length from the file information document.
|
154
|
+
# file_info.length
|
153
155
|
#
|
154
|
-
# @return [ Integer ] The length.
|
156
|
+
# @return [ Integer ] The file length.
|
155
157
|
#
|
156
158
|
# @since 2.0.0
|
157
159
|
def length
|
@@ -159,12 +161,12 @@ module Mongo
|
|
159
161
|
end
|
160
162
|
alias :size :length
|
161
163
|
|
162
|
-
# Get the additional metadata.
|
164
|
+
# Get the additional metadata from the file information document.
|
163
165
|
#
|
164
166
|
# @example Get additional metadata.
|
165
|
-
#
|
167
|
+
# file_info.metadata
|
166
168
|
#
|
167
|
-
# @return [ String ] The additional metadata.
|
169
|
+
# @return [ String ] The additional metadata from file information document.
|
168
170
|
#
|
169
171
|
# @since 2.0.0
|
170
172
|
def metadata
|
@@ -174,7 +176,7 @@ module Mongo
|
|
174
176
|
# Get the md5 hash.
|
175
177
|
#
|
176
178
|
# @example Get the md5 hash.
|
177
|
-
#
|
179
|
+
# file_info.md5
|
178
180
|
#
|
179
181
|
# @return [ String ] The md5 hash as a string.
|
180
182
|
#
|
@@ -183,13 +185,13 @@ module Mongo
|
|
183
185
|
document[:md5] || @client_md5
|
184
186
|
end
|
185
187
|
|
186
|
-
#
|
188
|
+
# Convert the file information document to BSON for storage.
|
187
189
|
#
|
188
|
-
# @note If no md5 exists in the
|
189
|
-
# and is not a new file) then we digest the md5 and set it.
|
190
|
+
# @note If no md5 exists in the file information document (it was loaded
|
191
|
+
# from the server and is not a new file) then we digest the md5 and set it.
|
190
192
|
#
|
191
|
-
# @example Convert the
|
192
|
-
#
|
193
|
+
# @example Convert the file information document to BSON.
|
194
|
+
# file_info.to_bson
|
193
195
|
#
|
194
196
|
# @param [ String ] encoded The encoded data to append to.
|
195
197
|
#
|
@@ -204,7 +206,7 @@ module Mongo
|
|
204
206
|
# Get the upload date.
|
205
207
|
#
|
206
208
|
# @example Get the upload date.
|
207
|
-
#
|
209
|
+
# file_info.upload_date
|
208
210
|
#
|
209
211
|
# @return [ Time ] The upload date.
|
210
212
|
#
|
@@ -0,0 +1,441 @@
|
|
1
|
+
# Copyright (C) 2014-2015 MongoDB, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Mongo
|
16
|
+
module Grid
|
17
|
+
|
18
|
+
# Represents a view of the GridFS in the database.
|
19
|
+
#
|
20
|
+
# @since 2.0.0
|
21
|
+
class FSBucket
|
22
|
+
|
23
|
+
# The default root prefix.
|
24
|
+
#
|
25
|
+
# @since 2.0.0
|
26
|
+
DEFAULT_ROOT = 'fs'.freeze
|
27
|
+
|
28
|
+
# The specification for the chunks collection index.
|
29
|
+
#
|
30
|
+
# @since 2.0.0
|
31
|
+
CHUNKS_INDEX = { :files_id => 1, :n => 1 }.freeze
|
32
|
+
|
33
|
+
# The specification for the files collection index.
|
34
|
+
#
|
35
|
+
# @since 2.1.0
|
36
|
+
FILES_INDEX = { filename: 1, uploadDate: 1 }.freeze
|
37
|
+
|
38
|
+
# @return [ Collection ] chunks_collection The chunks collection.
|
39
|
+
#
|
40
|
+
# @since 2.0.0
|
41
|
+
attr_reader :chunks_collection
|
42
|
+
|
43
|
+
# @return [ Database ] database The database.
|
44
|
+
#
|
45
|
+
# @since 2.0.0
|
46
|
+
attr_reader :database
|
47
|
+
|
48
|
+
# @return [ Collection ] files_collection The files collection.
|
49
|
+
#
|
50
|
+
# @since 2.0.0
|
51
|
+
attr_reader :files_collection
|
52
|
+
|
53
|
+
# @return [ Hash ] options The FSBucket options.
|
54
|
+
#
|
55
|
+
# @since 2.1.0
|
56
|
+
attr_reader :options
|
57
|
+
|
58
|
+
# Find files collection documents matching a given selector.
|
59
|
+
#
|
60
|
+
# @example Find files collection documents by a filename.
|
61
|
+
# fs.find(filename: 'file.txt')
|
62
|
+
#
|
63
|
+
# @param [ Hash ] selector The selector to use in the find.
|
64
|
+
# @param [ Hash ] options The options for the find.
|
65
|
+
#
|
66
|
+
# @option options [ Integer ] :batch_size The number of documents returned in each batch
|
67
|
+
# of results from MongoDB.
|
68
|
+
# @option options [ Integer ] :limit The max number of docs to return from the query.
|
69
|
+
# @option options [ true, false ] :no_cursor_timeout The server normally times out idle
|
70
|
+
# cursors after an inactivity period (10 minutes) to prevent excess memory use.
|
71
|
+
# Set this option to prevent that.
|
72
|
+
# @option options [ Integer ] :skip The number of docs to skip before returning results.
|
73
|
+
# @option options [ Hash ] :sort The key and direction pairs by which the result set
|
74
|
+
# will be sorted.
|
75
|
+
#
|
76
|
+
# @return [ CollectionView ] The collection view.
|
77
|
+
#
|
78
|
+
# @since 2.1.0
|
79
|
+
def find(selector = nil, options = {})
|
80
|
+
files_collection.find(selector, options.merge(read: read_preference))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find a file in the GridFS.
|
84
|
+
#
|
85
|
+
# @example Find a file by its id.
|
86
|
+
# fs.find_one(_id: id)
|
87
|
+
#
|
88
|
+
# @example Find a file by its filename.
|
89
|
+
# fs.find_one(filename: 'test.txt')
|
90
|
+
#
|
91
|
+
# @param [ Hash ] selector The selector.
|
92
|
+
#
|
93
|
+
# @return [ Grid::File ] The file.
|
94
|
+
#
|
95
|
+
# @since 2.0.0
|
96
|
+
def find_one(selector = nil)
|
97
|
+
file_info = files_collection.find(selector).first
|
98
|
+
return nil unless file_info
|
99
|
+
chunks = chunks_collection.find(:files_id => file_info[:_id]).sort(:n => 1)
|
100
|
+
Grid::File.new(chunks.to_a, file_info)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Insert a single file into the GridFS.
|
104
|
+
#
|
105
|
+
# @example Insert a single file.
|
106
|
+
# fs.insert_one(file)
|
107
|
+
#
|
108
|
+
# @param [ Grid::File ] file The file to insert.
|
109
|
+
#
|
110
|
+
# @return [ BSON::ObjectId ] The file id.
|
111
|
+
#
|
112
|
+
# @since 2.0.0
|
113
|
+
def insert_one(file)
|
114
|
+
@indexes ||= ensure_indexes!
|
115
|
+
chunks_collection.insert_many(file.chunks)
|
116
|
+
files_collection.insert_one(file.info)
|
117
|
+
file.id
|
118
|
+
end
|
119
|
+
|
120
|
+
# Create the GridFS.
|
121
|
+
#
|
122
|
+
# @example Create the GridFS.
|
123
|
+
# Grid::FSBucket.new(database)
|
124
|
+
#
|
125
|
+
# @param [ Database ] database The database the files reside in.
|
126
|
+
# @param [ Hash ] options The GridFS options.
|
127
|
+
#
|
128
|
+
# @option options [ String ] :fs_name The prefix for the files and chunks
|
129
|
+
# collections.
|
130
|
+
# @option options [ String ] :bucket_name The prefix for the files and chunks
|
131
|
+
# collections.
|
132
|
+
# @option options [ Integer ] :chunk_size Override the default chunk
|
133
|
+
# size.
|
134
|
+
# @option options [ String ] :write The write concern.
|
135
|
+
# @option options [ String ] :read The read preference.
|
136
|
+
#
|
137
|
+
# @since 2.0.0
|
138
|
+
def initialize(database, options = {})
|
139
|
+
@database = database
|
140
|
+
@options = options
|
141
|
+
@chunks_collection = database[chunks_name]
|
142
|
+
@files_collection = database[files_name]
|
143
|
+
end
|
144
|
+
|
145
|
+
# Get the prefix for the GridFS
|
146
|
+
#
|
147
|
+
# @example Get the prefix.
|
148
|
+
# fs.prefix
|
149
|
+
#
|
150
|
+
# @return [ String ] The GridFS prefix.
|
151
|
+
#
|
152
|
+
# @since 2.0.0
|
153
|
+
def prefix
|
154
|
+
@options[:fs_name] || @options[:bucket_name]|| DEFAULT_ROOT
|
155
|
+
end
|
156
|
+
|
157
|
+
# Remove a single file from the GridFS.
|
158
|
+
#
|
159
|
+
# @example Remove a file from the GridFS.
|
160
|
+
# fs.delete_one(file)
|
161
|
+
#
|
162
|
+
# @param [ Grid::File ] file The file to remove.
|
163
|
+
#
|
164
|
+
# @return [ Result ] The result of the remove.
|
165
|
+
#
|
166
|
+
# @since 2.0.0
|
167
|
+
def delete_one(file)
|
168
|
+
delete(file.id)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Remove a single file, identified by its id from the GridFS.
|
172
|
+
#
|
173
|
+
# @example Remove a file from the GridFS.
|
174
|
+
# fs.delete(id)
|
175
|
+
#
|
176
|
+
# @param [ BSON::ObjectId, Object ] id The id of the file to remove.
|
177
|
+
#
|
178
|
+
# @return [ Result ] The result of the remove.
|
179
|
+
#
|
180
|
+
# @raise [ Error::FileNotFound ] If the file is not found.
|
181
|
+
#
|
182
|
+
# @since 2.1.0
|
183
|
+
def delete(id)
|
184
|
+
result = files_collection.find(:_id => id).delete_one
|
185
|
+
chunks_collection.find(:files_id => id).delete_many
|
186
|
+
raise Error::FileNotFound.new(id, :id) if result.n == 0
|
187
|
+
result
|
188
|
+
end
|
189
|
+
|
190
|
+
# Opens a stream from which a file can be downloaded, specified by id.
|
191
|
+
#
|
192
|
+
# @example Open a stream from which a file can be downloaded.
|
193
|
+
# fs.open_download_stream(id)
|
194
|
+
#
|
195
|
+
# @param [ BSON::ObjectId, Object ] id The id of the file to read.
|
196
|
+
#
|
197
|
+
# @return [ Stream::Read ] The stream to read from.
|
198
|
+
#
|
199
|
+
# @yieldparam [ Hash ] The read stream.
|
200
|
+
#
|
201
|
+
# @since 2.1.0
|
202
|
+
def open_download_stream(id)
|
203
|
+
read_stream(id).tap do |stream|
|
204
|
+
if block_given?
|
205
|
+
yield stream
|
206
|
+
stream.close
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Downloads the contents of the file specified by id and writes them to
|
212
|
+
# the destination io object.
|
213
|
+
#
|
214
|
+
# @example Download the file and write it to the io object.
|
215
|
+
# fs.download_to_stream(id, io)
|
216
|
+
#
|
217
|
+
# @param [ BSON::ObjectId, Object ] id The id of the file to read.
|
218
|
+
# @param [ IO ] io The io object to write to.
|
219
|
+
#
|
220
|
+
# @since 2.1.0
|
221
|
+
def download_to_stream(id, io)
|
222
|
+
open_download_stream(id) do |stream|
|
223
|
+
stream.each do |chunk|
|
224
|
+
io << chunk
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# Opens a stream from which the application can read the contents of the stored file
|
230
|
+
# specified by filename and the revision in options.
|
231
|
+
#
|
232
|
+
# Revision numbers are defined as follows:
|
233
|
+
# 0 = the original stored file
|
234
|
+
# 1 = the first revision
|
235
|
+
# 2 = the second revision
|
236
|
+
# etc…
|
237
|
+
# -2 = the second most recent revision
|
238
|
+
# -1 = the most recent revision
|
239
|
+
#
|
240
|
+
# @example Open a stream to download the most recent revision.
|
241
|
+
# fs.open_download_stream_by_name('some-file.txt')
|
242
|
+
#
|
243
|
+
# # @example Open a stream to download the original file.
|
244
|
+
# fs.open_download_stream_by_name('some-file.txt', revision: 0)
|
245
|
+
#
|
246
|
+
# @example Open a stream to download the second revision of the stored file.
|
247
|
+
# fs.open_download_stream_by_name('some-file.txt', revision: 2)
|
248
|
+
#
|
249
|
+
# @param [ String ] filename The file's name.
|
250
|
+
# @param [ Hash ] opts Options for the download.
|
251
|
+
#
|
252
|
+
# @option opts [ Integer ] :revision The revision number of the file to download.
|
253
|
+
# Defaults to -1, the most recent version.
|
254
|
+
#
|
255
|
+
# @return [ Stream::Read ] The stream to read from.
|
256
|
+
#
|
257
|
+
# @raise [ Error::FileNotFound ] If the file is not found.
|
258
|
+
# @raise [ Error::InvalidFileRevision ] If the requested revision is not found for the file.
|
259
|
+
#
|
260
|
+
# @yieldparam [ Hash ] The read stream.
|
261
|
+
#
|
262
|
+
# @since 2.1.0
|
263
|
+
def open_download_stream_by_name(filename, opts = {}, &block)
|
264
|
+
revision = opts.fetch(:revision, -1)
|
265
|
+
if revision < 0
|
266
|
+
skip = revision.abs - 1
|
267
|
+
sort = { 'uploadDate' => Mongo::Index::DESCENDING }
|
268
|
+
else
|
269
|
+
skip = revision
|
270
|
+
sort = { 'uploadDate' => Mongo::Index::ASCENDING }
|
271
|
+
end
|
272
|
+
file_doc = files_collection.find({ filename: filename} ,
|
273
|
+
projection: { _id: 1 },
|
274
|
+
sort: sort,
|
275
|
+
skip: skip,
|
276
|
+
limit: -1).first
|
277
|
+
unless file_doc
|
278
|
+
raise Error::FileNotFound.new(filename, :filename) unless opts[:revision]
|
279
|
+
raise Error::InvalidFileRevision.new(filename, opts[:revision])
|
280
|
+
end
|
281
|
+
open_download_stream(file_doc[:_id], &block)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Downloads the contents of the stored file specified by filename and by the
|
285
|
+
# revision in options and writes the contents to the destination io object.
|
286
|
+
#
|
287
|
+
# Revision numbers are defined as follows:
|
288
|
+
# 0 = the original stored file
|
289
|
+
# 1 = the first revision
|
290
|
+
# 2 = the second revision
|
291
|
+
# etc…
|
292
|
+
# -2 = the second most recent revision
|
293
|
+
# -1 = the most recent revision
|
294
|
+
#
|
295
|
+
# @example Download the most recent revision.
|
296
|
+
# fs.download_to_stream_by_name('some-file.txt', io)
|
297
|
+
#
|
298
|
+
# # @example Download the original file.
|
299
|
+
# fs.download_to_stream_by_name('some-file.txt', io, revision: 0)
|
300
|
+
#
|
301
|
+
# @example Download the second revision of the stored file.
|
302
|
+
# fs.download_to_stream_by_name('some-file.txt', io, revision: 2)
|
303
|
+
#
|
304
|
+
# @param [ String ] filename The file's name.
|
305
|
+
# @param [ IO ] io The io object to write to.
|
306
|
+
# @param [ Hash ] opts Options for the download.
|
307
|
+
#
|
308
|
+
# @option opts [ Integer ] :revision The revision number of the file to download.
|
309
|
+
# Defaults to -1, the most recent version.
|
310
|
+
#
|
311
|
+
# @raise [ Error::FileNotFound ] If the file is not found.
|
312
|
+
# @raise [ Error::InvalidFileRevision ] If the requested revision is not found for the file.
|
313
|
+
#
|
314
|
+
# @since 2.1.0
|
315
|
+
def download_to_stream_by_name(filename, io, opts = {})
|
316
|
+
download_to_stream(open_download_stream_by_name(filename, opts).file_id, io)
|
317
|
+
end
|
318
|
+
|
319
|
+
# Opens an upload stream to GridFS to which the contents of a user file came be written.
|
320
|
+
#
|
321
|
+
# @example Open a stream to which the contents of a file came be written.
|
322
|
+
# fs.open_upload_stream('a-file.txt')
|
323
|
+
#
|
324
|
+
# @param [ String ] filename The filename of the file to upload.
|
325
|
+
# @param [ Hash ] opts The options for the write stream.
|
326
|
+
#
|
327
|
+
# @option opts [ Integer ] :chunk_size Override the default chunk size.
|
328
|
+
# @option opts [ Hash ] :write The write concern.
|
329
|
+
# @option opts [ Hash ] :metadata User data for the 'metadata' field of the files
|
330
|
+
# collection document.
|
331
|
+
# @option opts [ String ] :content_type The content type of the file.
|
332
|
+
# Deprecated, please use the metadata document instead.
|
333
|
+
# @option opts [ Array<String> ] :aliases A list of aliases.
|
334
|
+
# Deprecated, please use the metadata document instead.
|
335
|
+
#
|
336
|
+
# @return [ Stream::Write ] The write stream.
|
337
|
+
#
|
338
|
+
# @yieldparam [ Hash ] The write stream.
|
339
|
+
#
|
340
|
+
# @since 2.1.0
|
341
|
+
def open_upload_stream(filename, opts = {})
|
342
|
+
write_stream(filename, opts).tap do |stream|
|
343
|
+
if block_given?
|
344
|
+
yield stream
|
345
|
+
stream.close
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
# Uploads a user file to a GridFS bucket.
|
351
|
+
# Reads the contents of the user file from the source stream and uploads it as chunks in the
|
352
|
+
# chunks collection. After all the chunks have been uploaded, it creates a files collection
|
353
|
+
# document for the filename in the files collection.
|
354
|
+
#
|
355
|
+
# @example Open a stream to which the contents of a file came be written.
|
356
|
+
# fs.open_upload_stream('a-file.txt')
|
357
|
+
#
|
358
|
+
# @param [ String ] filename The filename of the file to upload.
|
359
|
+
# @param [ IO ] io The source io stream to upload from.
|
360
|
+
# @param [ Hash ] opts The options for the write stream.
|
361
|
+
#
|
362
|
+
# @option opts [ Integer ] :chunk_size Override the default chunk size.
|
363
|
+
# @option opts [ Hash ] :write The write concern.
|
364
|
+
# @option opts [ Hash ] :metadata User data for the 'metadata' field of the files
|
365
|
+
# collection document.
|
366
|
+
# @option opts [ String ] :content_type The content type of the file. Deprecated, please
|
367
|
+
# use the metadata document instead.
|
368
|
+
# @option opts [ Array<String> ] :aliases A list of aliases. Deprecated, please use the
|
369
|
+
# metadata document instead.
|
370
|
+
#
|
371
|
+
# @return [ BSON::ObjectId ] The ObjectId file id.
|
372
|
+
#
|
373
|
+
# @since 2.1.0
|
374
|
+
def upload_from_stream(filename, io, opts = {})
|
375
|
+
open_upload_stream(filename, opts) do |stream|
|
376
|
+
begin
|
377
|
+
stream.write(io)
|
378
|
+
rescue IOError
|
379
|
+
begin
|
380
|
+
stream.abort
|
381
|
+
rescue Error::OperationFailure
|
382
|
+
end
|
383
|
+
raise
|
384
|
+
end
|
385
|
+
end.file_id
|
386
|
+
end
|
387
|
+
|
388
|
+
# Get the read preference.
|
389
|
+
#
|
390
|
+
# @example Get the read preference.
|
391
|
+
# fs.read_preference
|
392
|
+
#
|
393
|
+
# @return [ Mongo::ServerSelector ] The read preference.
|
394
|
+
#
|
395
|
+
# @since 2.1.0
|
396
|
+
def read_preference
|
397
|
+
@read_preference ||= @options[:read] ?
|
398
|
+
ServerSelector.get((@options[:read] || {}).merge(database.options)) :
|
399
|
+
database.read_preference
|
400
|
+
end
|
401
|
+
|
402
|
+
# Get the write concern.
|
403
|
+
#
|
404
|
+
# @example Get the write concern.
|
405
|
+
# stream.write_concern
|
406
|
+
#
|
407
|
+
# @return [ Mongo::WriteConcern ] The write concern.
|
408
|
+
#
|
409
|
+
# @since 2.1.0
|
410
|
+
def write_concern
|
411
|
+
@write_concern ||= @options[:write] ? WriteConcern.get(@options[:write]) :
|
412
|
+
database.write_concern
|
413
|
+
end
|
414
|
+
|
415
|
+
private
|
416
|
+
|
417
|
+
def read_stream(id)
|
418
|
+
Stream.get(self, Stream::READ_MODE, { file_id: id }.merge!(options))
|
419
|
+
end
|
420
|
+
|
421
|
+
def write_stream(filename, opts)
|
422
|
+
Stream.get(self, Stream::WRITE_MODE, { filename: filename }.merge!(options).merge!(opts))
|
423
|
+
end
|
424
|
+
|
425
|
+
def chunks_name
|
426
|
+
"#{prefix}.#{Grid::File::Chunk::COLLECTION}"
|
427
|
+
end
|
428
|
+
|
429
|
+
def files_name
|
430
|
+
"#{prefix}.#{Grid::File::Info::COLLECTION}"
|
431
|
+
end
|
432
|
+
|
433
|
+
def ensure_indexes!
|
434
|
+
if files_collection.find({}, projection: { _id: 1 }).to_a.empty?
|
435
|
+
chunks_collection.indexes.create_one(FSBucket::CHUNKS_INDEX, :unique => true)
|
436
|
+
files_collection.indexes.create_one(FSBucket::FILES_INDEX)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|