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 +4 -4
- data/.gitignore +1 -0
- data/README.md +18 -14
- data/carton_db.gemspec +3 -0
- data/lib/carton_db/list_map_db/segment.rb +12 -0
- data/lib/carton_db/list_map_db.rb +23 -2
- data/lib/carton_db/set_map_db.rb +111 -0
- data/lib/carton_db/simple_map_db.rb +102 -0
- data/lib/carton_db/version.rb +1 -1
- data/lib/carton_db.rb +2 -0
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d16d6802fee28aa151d8eee4811d17d3a5dc00a5
|
4
|
+
data.tar.gz: 22cb133e4202c80ef89109a24163c41b666ec89c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ff1b4d0a6a5582d5903093e80051600e119f8c857b9ba32821081113b3cf90b3802c3f10f83a4fba0173b987ef55f699d3ae6289b1dfda47934b5105eb92b15
|
7
|
+
data.tar.gz: 04747d51836cc9864fc5e5245f884d42c585cb434ba7ce66441f19836c87d841ed74a60765d5b93a5767f13279ae93b3c81da2b59ec853fbda5082961841472e
|
data/.gitignore
CHANGED
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,
|
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
|
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
|
72
|
-
|
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
|
76
|
-
thousand elements
|
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
|
79
|
-
|
80
|
-
|
81
|
-
performance of
|
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
|
-
|
86
|
-
implemented by
|
87
|
-
|
88
|
-
|
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
|
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
|
data/lib/carton_db/version.rb
CHANGED
data/lib/carton_db.rb
CHANGED
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.
|
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-
|
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:
|
109
|
+
version: 2.3.0
|
94
110
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
111
|
requirements:
|
96
112
|
- - ">="
|