carton_db 1.1.1 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce323ba4a0df06b409f1b35a150a9a638740e586
4
- data.tar.gz: b2c95dca25fe7be9c0b7c8ff7ca2f8d3ea6e7ed0
3
+ metadata.gz: d16d6802fee28aa151d8eee4811d17d3a5dc00a5
4
+ data.tar.gz: 22cb133e4202c80ef89109a24163c41b666ec89c
5
5
  SHA512:
6
- metadata.gz: ed9890e79acc8c72d7005834b9ed6f8fec56ab941d9c078957cb2fa84c5e82f486ea876d981af6850bd2835ea9fc58789194e0e061087054def1a2a35ab25fdb
7
- data.tar.gz: 69de8aac4491cd13b67c3e2bb0a707961c8a359259278303a70e094c19fe7e60b3c5c3b2983f1b6268b74bc5045f762eeb7abb53b22e031049bfa6d2e962e06c
6
+ metadata.gz: 3ff1b4d0a6a5582d5903093e80051600e119f8c857b9ba32821081113b3cf90b3802c3f10f83a4fba0173b987ef55f699d3ae6289b1dfda47934b5105eb92b15
7
+ data.tar.gz: 04747d51836cc9864fc5e5245f884d42c585cb434ba7ce66441f19836c87d841ed74a60765d5b93a5767f13279ae93b3c81da2b59ec853fbda5082961841472e
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  /Gemfile.lock
4
4
  /_yardoc/
5
5
  /coverage/
6
+ /profiles/
6
7
  /doc/
7
8
  /pkg/
8
9
  /spec/reports/
data/README.md CHANGED
@@ -4,7 +4,7 @@ A pure Ruby key/value data storage system where the values may
4
4
  consist of simple data structures.
5
5
 
6
6
  The primary goals of this library are simplicity of implementation
7
- and reliable, predicatble behavior when used as intended, along
7
+ and reliable, predictable behavior when used as intended, along
8
8
  with documentation making it reasonably clear what is intended.
9
9
 
10
10
  ## Uses
@@ -53,11 +53,14 @@ filesystem containing the files that store the data.
53
53
 
54
54
  A database is accessed through an instance of a database class.
55
55
 
56
- An instance of a database class maintains no state in memory
56
+ An instance of a database class maintains no internal state
57
57
  between calls to its methods except for the database name and the
58
58
  expectation of a directory with that name existing in the
59
59
  filesystem.
60
60
 
61
+ Only instances of classes maintain any internal state. No global
62
+ internal state is maintained.
63
+
61
64
  An empty directory is a valid empty database.
62
65
 
63
66
  Concurrent reads from a database are supported and safe.
@@ -68,24 +71,25 @@ attempting to do that are unpredictable.
68
71
 
69
72
  Initializing a new database class instance creates its directory
70
73
  in the filesystem if it does not already exist. The parent of the
71
- database directory is expected to already exist, and an
72
- exception will be raised if it doesn't.
74
+ database directory is expected to already exist, and an exception
75
+ will be raised if it doesn't.
73
76
 
74
77
  The database structure is designed to effectively handle up to
75
- several million elements with entries containing up to 1 or 2
76
- thousand elements each.
78
+ several million elements with any entry containing up to around
79
+ 50 thousand characters (elements ⨉ chars in an entry's content).
77
80
 
78
- The speed of database operations is relatively good, but this is
79
- not a high performance database management system. See the
80
- code documentation in the classes for more details about the
81
- performance of particular database operations.
81
+ The speed of database operations is good, but this is not a high
82
+ performance database management system. See the code
83
+ documentation in the classes for more details about the
84
+ performance of each kind of database operation.
82
85
 
83
86
  ## Usage
84
87
 
85
- Currently, this gem includes only one kind of database, which is
86
- implemented by the `CartonDB::ListMapDb` class. It is a map of
87
- lists where each entry has a string for a key and a list of of 0
88
- or more string elements as content.
88
+ The primary kind of database provided by this gem is the one
89
+ implemented by `CartonDB::ListMapDb`. It is a map of lists where
90
+ each entry has a string for a key and a list of of 0 or more
91
+ string elements as content. Other kinds of database are
92
+ implemented on top of that and share the same storage format.
89
93
 
90
94
  The name of the database is the path of a directory in the
91
95
  filesystem that either already exists or shall be created as
data/carton_db.gemspec CHANGED
@@ -14,6 +14,8 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/stevecj/carton_db.rb"
15
15
  spec.license = "MIT"
16
16
 
17
+ spec.required_ruby_version = '>= 2.3.0'
18
+
17
19
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
20
  f.match(%r{^(test|spec|features)/})
19
21
  end
@@ -24,4 +26,5 @@ Gem::Specification.new do |spec|
24
26
  spec.add_development_dependency "bundler", "~> 1.14"
25
27
  spec.add_development_dependency "rake", "~> 10.0"
26
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "rspec-prof", "~> 0.0"
27
30
  end
@@ -71,6 +71,18 @@ module CartonDb
71
71
  end
72
72
  end
73
73
 
74
+ def each_first_element
75
+ first_entries = nil
76
+ each_entry_element_line do |key_d, elem_d, _line|
77
+ first_entries ||= {}
78
+ first_entries[key_d] ||= elem_d.plain
79
+ end
80
+ return unless first_entries
81
+ first_entries.each do |key_d, element|
82
+ yield key_d.plain, element
83
+ end
84
+ end
85
+
74
86
  def each_entry_element_line
75
87
  return if empty?
76
88
  each_line do |line|
@@ -6,7 +6,7 @@ require 'carton_db/list_map_db/segment_group'
6
6
 
7
7
  module CartonDb
8
8
 
9
- # A map with string keys lists of strings as contents.
9
+ # A map with strings as keys and lists of strings as contents.
10
10
  #
11
11
  # This is suitable for storing a total number of elements as
12
12
  # large as the low millions, with each entry containing a
@@ -215,6 +215,23 @@ module CartonDb
215
215
  end
216
216
  end
217
217
 
218
+ # For each entry in the database, yields the first element
219
+ # in the entry's content or nil if the content is an empty
220
+ # list.
221
+ #
222
+ # Performance is pretty much identical to that of #each.
223
+ #
224
+ # @yieldparam key [String] The key of the entry.
225
+ # @yeildparam array [String, nil] The first element of the
226
+ # entry's content.
227
+ def each_first_element
228
+ ListMapDb::Segment.each_in_db name do |segment|
229
+ segment.each_first_element do |key, element|
230
+ yield key, element
231
+ end
232
+ end
233
+ end
234
+
218
235
  # Removes an entry from the database. Has no effect if the
219
236
  # entry already does not exist.
220
237
  #
@@ -322,9 +339,13 @@ module CartonDb
322
339
  # necessary so the content has an element corresponding to
323
340
  # each of the given elements.
324
341
  #
342
+ # Performance is similar to #[] when no new elements need to
343
+ # be added and similar to #[] followed by #concat_elements
344
+ # when one or more new elements needs to be added.
345
+ #
325
346
  # @param key [String] The key identifying the entry.
326
347
  # @param elements [Array<String>] An array or other
327
- # enumerable collection of elements to appended as
348
+ # enumerable collection of elements to be appended as
328
349
  # applicable.
329
350
  def merge_elements(key, elements)
330
351
  key_d = CartonDb::Datum.for_plain(key)
@@ -0,0 +1,111 @@
1
+ require 'set'
2
+ require 'forwardable'
3
+
4
+ module CartonDb
5
+
6
+ class SetMapDb
7
+ extend Forwardable
8
+
9
+ def initialize(name)
10
+ self.list_map_db = CartonDb::ListMapDb.new(name)
11
+ end
12
+
13
+ # Creates a new entry or replaces the contents of the
14
+ # existing entry identified by the given key.
15
+ #
16
+ # The is a fairly fast operation, but can be somewhat
17
+ # slower in a large database.
18
+ #
19
+ # @param key [String] The key identifying the entry.
20
+ # @param content [Set<String>] A set or other enumerable
21
+ # collection of 0 or more list element string values to be
22
+ # stored.
23
+ def []=(key, content)
24
+ content = Set.new(content) unless content.is_a?(Set)
25
+ list_map_db[key] = content
26
+ end
27
+
28
+ # Returns the content of the entry identified by the given
29
+ # key or nil if no such entry exists.
30
+ #
31
+ # This operation is fast, but may be slower for a larger
32
+ # database.
33
+ #
34
+ # @param key [String] The key identifying the entry.
35
+ # @return [Set<String>] if a matching entry exists.
36
+ # @return [nil] if no matching entry exists.
37
+ def [](key)
38
+ list = list_map_db[key]
39
+ list && Set.new(list)
40
+ end
41
+
42
+ # See CartonDb::ListMapDb#empty?
43
+ def_delegator :list_map_db, :empty?
44
+
45
+ # see cartondb::listmapdb#count
46
+ def_delegator :list_map_db, :count
47
+
48
+ # See CartonDb::ListMapDb#Key?
49
+ def_delegator :list_map_db, :key?
50
+
51
+ # See CartonDb::ListMapDb#touch_element
52
+ def_delegator :list_map_db, :touch_element
53
+
54
+ # See CartonDb::ListMapDb#delete
55
+ def_delegator :list_map_db, :delete
56
+
57
+ # Creates an entry with an empty set as its content if no
58
+ # entry exists for the given key. Has no effect on the content
59
+ # of the entry if it already exists.
60
+ #
61
+ # See the documentation for CartonDb::ListMapDb#touch for
62
+ # performance characteristics.
63
+ #
64
+ # @param key [String] The key identifying the entry.
65
+ # @param optimization[:small, :fast] The optimization mode.
66
+ def_delegator :list_map_db, :touch
67
+
68
+ # See CartonDb::ListMapDb#clear
69
+ def_delegator :list_map_db, :clear
70
+
71
+ # Performs a set-wise merge of the given elements with the
72
+ # content of an entry. Adds whatever elements are necessary
73
+ # so the content has an element corresponding to unique
74
+ # given element.
75
+ #
76
+ # See the documentation for
77
+ # CartonDb::ListMapDb#merge_elements for performance
78
+ # characteristics.
79
+ #
80
+ # @param key [String] The key identifying the entry.
81
+ # @param elements [Set<String>] A set or other enumerable
82
+ # collection of elements to be added as applicable.
83
+ def merge_elements(key, elements)
84
+ elements = Set.new(content) unless elements.is_a?(Set)
85
+ list_map_db.merge_elements key, elements
86
+ end
87
+
88
+ # See CartonDb::ListMapDb#element?
89
+ def_delegator :list_map_db, :element?
90
+
91
+ # Yields each entry in the database as a key/array pair.
92
+ #
93
+ # See the documentation for CartonDb::ListMapDb#each for
94
+ # performance characteristics.
95
+ #
96
+ # @yieldparam key [String] The key of the entry.
97
+ # @yeildparam array [Array<String>] The elements of the list
98
+ # entry's content.
99
+ def each
100
+ list_map_db.each do |key, list|
101
+ yield key, Set.new(list)
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ attr_accessor :list_map_db
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,102 @@
1
+ require 'forwardable'
2
+
3
+ module CartonDb
4
+
5
+ # A map with strings as keys and values that can each be either
6
+ # a string or nil.
7
+ #
8
+ # Data storage is in the same form as ListMapDb, but string
9
+ # values are stored as single-element lists and nil values are
10
+ # stored as empty lists. Only the first element in an entry's
11
+ # content is significant when retrieving a value from a
12
+ # multi-element underlying entry.
13
+ #
14
+ # See the documentation for CartonDb::ListMapDb for additional
15
+ # details.
16
+ class SimpleMapDb
17
+ extend Forwardable
18
+ include Enumerable
19
+
20
+ # Initializes an instance that interacts with the database
21
+ # identified by the given name, which is the full path to a
22
+ # directory in the filesystem.
23
+ #
24
+ # See the documentation for CartonDb::ListMapDb#initialize
25
+ # for additional details.
26
+ #
27
+ # @param name [String] The full path of the directory in the
28
+ # filesystem in which the data is stored or will be stored.
29
+ def initialize(name)
30
+ self.list_map_db = CartonDb::ListMapDb.new(name)
31
+ end
32
+
33
+ # Creates a new entry or replaces the contents of the
34
+ # existing entry identified by the given key.
35
+ #
36
+ # See the documentation for CartonDb::ListMapDb#initialize
37
+ # for performance characteristics.
38
+ #
39
+ # @param key [String] The key identifying the entry.
40
+ # @param value [String, nil] The value to be stored.
41
+ def []=(key, value)
42
+ content = value.nil? ? [] : [value.to_s]
43
+ list_map_db[key] = content
44
+ end
45
+
46
+ # Returns the content of the entry identified by the given
47
+ # key or nil if no such entry exists.
48
+ #
49
+ # See the documentation for CartonDb::ListMapDb#initialize
50
+ # for performance characteristics.
51
+ #
52
+ # @param key [String] The key identifying the entry.
53
+ # @return [String, nil] if a matching entry exists.
54
+ # @return [nil] if no matching entry exists.
55
+ def [](key)
56
+ content = list_map_db[key]
57
+ content&.first
58
+ end
59
+
60
+ # See CartonDb::ListMapDb#empty?
61
+ def_delegator :list_map_db, :empty?
62
+
63
+ # see cartondb::listmapdb#count
64
+ def_delegator :list_map_db, :count
65
+
66
+ # See CartonDb::ListMapDb#Key?
67
+ def_delegator :list_map_db, :key?
68
+
69
+ # See CartonDb::ListMapDb#delete
70
+ def_delegator :list_map_db, :delete
71
+
72
+ # Creates an entry with a nil value if no entry exists for
73
+ # the given key. Has no effect on the value of the entry if
74
+ # it already exists.
75
+ #
76
+ # See the documentation for CartonDb::ListMapDb#touch for
77
+ # performance characteristics.
78
+ #
79
+ # @param key [String] The key identifying the entry.
80
+ # @param optimization[:small, :fast] The optimization mode.
81
+ def_delegator :list_map_db, :touch
82
+
83
+ # See CartonDb::ListMapDb#clear
84
+ def_delegator :list_map_db, :clear
85
+
86
+ # Yields each entry in the database as a key/value pair.
87
+ #
88
+ # See the documentation for CartonDb::ListMapDb#yield for
89
+ # performance characteristics.
90
+ #
91
+ # @yieldparam key [String] The key of the entry.
92
+ # @yeildparam array [Array<String>] The elements of the list
93
+ # entry's content.
94
+ def_delegator :list_map_db, :each_first_element, :each
95
+
96
+ private
97
+
98
+ attr_accessor :list_map_db
99
+
100
+ end
101
+
102
+ end
@@ -1,4 +1,4 @@
1
1
  # -*- coding: UTF-8 -*-
2
2
  module CartonDb
3
- VERSION = "1.1.1"
3
+ VERSION = "1.1.2"
4
4
  end
data/lib/carton_db.rb CHANGED
@@ -3,6 +3,8 @@ require "carton_db/version"
3
3
  require "carton_db/escaping"
4
4
  require "carton_db/datum"
5
5
  require "carton_db/list_map_db"
6
+ require "carton_db/simple_map_db"
7
+ require "carton_db/set_map_db"
6
8
 
7
9
  module CartonDb
8
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: carton_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jorgensen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-05-06 00:00:00.000000000 Z
11
+ date: 2017-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-prof
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.0'
55
69
  description:
56
70
  email:
57
71
  - stevej@stevej.name
@@ -76,6 +90,8 @@ files:
76
90
  - lib/carton_db/list_map_db.rb
77
91
  - lib/carton_db/list_map_db/segment.rb
78
92
  - lib/carton_db/list_map_db/segment_group.rb
93
+ - lib/carton_db/set_map_db.rb
94
+ - lib/carton_db/simple_map_db.rb
79
95
  - lib/carton_db/version.rb
80
96
  - tmp/.gitkeep
81
97
  homepage: https://github.com/stevecj/carton_db.rb
@@ -90,7 +106,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
106
  requirements:
91
107
  - - ">="
92
108
  - !ruby/object:Gem::Version
93
- version: '0'
109
+ version: 2.3.0
94
110
  required_rubygems_version: !ruby/object:Gem::Requirement
95
111
  requirements:
96
112
  - - ">="