carton_db 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
- - ">="
|