hold 1.0.0
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 +7 -0
- data/README.md +573 -0
- data/lib/hold.rb +14 -0
- data/lib/hold/file/hash_repository.rb +59 -0
- data/lib/hold/in_memory.rb +184 -0
- data/lib/hold/interfaces.rb +441 -0
- data/lib/hold/sequel.rb +41 -0
- data/lib/hold/sequel/dataset_lazy_array.rb +33 -0
- data/lib/hold/sequel/identity_set_repository.rb +565 -0
- data/lib/hold/sequel/polymorphic_repository.rb +121 -0
- data/lib/hold/sequel/property_mapper.rb +138 -0
- data/lib/hold/sequel/property_mapper/array.rb +62 -0
- data/lib/hold/sequel/property_mapper/column.rb +42 -0
- data/lib/hold/sequel/property_mapper/created_at.rb +14 -0
- data/lib/hold/sequel/property_mapper/custom_query.rb +34 -0
- data/lib/hold/sequel/property_mapper/custom_query_single_value.rb +36 -0
- data/lib/hold/sequel/property_mapper/foreign_key.rb +96 -0
- data/lib/hold/sequel/property_mapper/hash.rb +60 -0
- data/lib/hold/sequel/property_mapper/identity.rb +41 -0
- data/lib/hold/sequel/property_mapper/many_to_many.rb +158 -0
- data/lib/hold/sequel/property_mapper/one_to_many.rb +199 -0
- data/lib/hold/sequel/property_mapper/transformed_column.rb +38 -0
- data/lib/hold/sequel/property_mapper/updated_at.rb +17 -0
- data/lib/hold/sequel/query.rb +92 -0
- data/lib/hold/sequel/query_array_cell.rb +21 -0
- data/lib/hold/sequel/repository_observer.rb +28 -0
- data/lib/hold/sequel/with_polymorphic_type_column.rb +117 -0
- data/lib/hold/serialized.rb +104 -0
- data/lib/hold/serialized/json_serializer.rb +12 -0
- data/lib/hold/version.rb +3 -0
- metadata +199 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
module Hold::Sequel
|
2
|
+
# A column mapper which allows you to supply a customized pair of transformations
|
3
|
+
# between the sequel values persisted in the db, and the values used for the outward-facing
|
4
|
+
# model property
|
5
|
+
class PropertyMapper::TransformedColumn < PropertyMapper::Column
|
6
|
+
def initialize(repo, property_name, options)
|
7
|
+
super(repo, property_name, options)
|
8
|
+
@to_sequel = options[:to_sequel]
|
9
|
+
@from_sequel = options[:from_sequel]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_sequel(value)
|
13
|
+
@to_sequel.call(value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def from_sequel(value)
|
17
|
+
@from_sequel.call(value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_value(row, id=nil, properties=nil)
|
21
|
+
from_sequel(row[@column_alias])
|
22
|
+
end
|
23
|
+
|
24
|
+
def build_insert_row(entity, table, row, id=nil)
|
25
|
+
row[@column_name] = to_sequel(entity[@property_name]) if @table == table && entity.has_key?(@property_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :build_update_row :build_insert_row
|
29
|
+
|
30
|
+
def make_filter(value, columns_mapped_to=nil)
|
31
|
+
{@column_qualified => to_sequel(value)}
|
32
|
+
end
|
33
|
+
|
34
|
+
def make_multi_filter(values, columns_mapped_to=nil)
|
35
|
+
{@column_qualified => values.map {|v| to_sequel(v)}}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Hold::Sequel
|
2
|
+
class PropertyMapper::UpdatedAt < PropertyMapper::Column
|
3
|
+
def build_insert_row(entity, table, row, id=nil)
|
4
|
+
row[@column_name] = Time.now if table == @table
|
5
|
+
end
|
6
|
+
|
7
|
+
alias :build_update_row :build_insert_row
|
8
|
+
|
9
|
+
def post_insert(entity, rows, last_insert_id=nil)
|
10
|
+
entity[@property_name] = rows[@table][@column_name]
|
11
|
+
end
|
12
|
+
|
13
|
+
def post_update(id, update_entity, rows, from_pre_update)
|
14
|
+
update_entity[@property_name] = rows[@table][@column_name]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Hold::Sequel
|
2
|
+
# A query has a dataset and mappings constructed to select a particular
|
3
|
+
# set of properties on a particular Sequel::IdentitySetRepository
|
4
|
+
class Query
|
5
|
+
attr_reader :dataset, :count_dataset, :property_versions, :property_columns, :aliased_columns, :tables
|
6
|
+
|
7
|
+
# Repo: repository to query
|
8
|
+
# properties: mapping or array of properties to fetch.
|
9
|
+
# properties ::=
|
10
|
+
# nil or true = fetch the default set of properties for the given repository
|
11
|
+
# array of property names = fetch just these properties, each in their default version
|
12
|
+
# hash of property names = fetch just these properties, each in the version given in the hash
|
13
|
+
#
|
14
|
+
# can pass a block: {|dataset, property_columns| return dataset.messed_with}
|
15
|
+
def initialize(repo, properties)
|
16
|
+
@repository = repo
|
17
|
+
|
18
|
+
if properties.is_a?(::Array)
|
19
|
+
@property_versions = {}
|
20
|
+
properties.each {|p,v| @property_versions[p] = v}
|
21
|
+
else
|
22
|
+
@property_versions = properties
|
23
|
+
end
|
24
|
+
|
25
|
+
@property_columns, @aliased_columns, @tables =
|
26
|
+
@repository.columns_aliases_and_tables_for_properties(@property_versions.keys)
|
27
|
+
|
28
|
+
@dataset = @repository.dataset_to_select_tables(*@tables)
|
29
|
+
@dataset = yield @dataset, @property_columns if block_given?
|
30
|
+
|
31
|
+
id_cols = @property_columns[@repository.identity_property]
|
32
|
+
@count_dataset = @dataset.select(*id_cols)
|
33
|
+
|
34
|
+
@dataset = @dataset.select(*@aliased_columns)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def load_from_rows(rows, return_the_row_alongside_each_result=false)
|
40
|
+
return [] if rows.empty?
|
41
|
+
|
42
|
+
property_hashes = []; ids = []
|
43
|
+
@repository.identity_mapper.load_values(rows) do |id,i|
|
44
|
+
property_hashes << {@repository.identity_property => id}
|
45
|
+
ids << id
|
46
|
+
end
|
47
|
+
|
48
|
+
@property_versions.each do |prop_name, prop_version|
|
49
|
+
@repository.mapper(prop_name).load_values(rows, ids, prop_version) do |value, i|
|
50
|
+
property_hashes[i][prop_name] = value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
result = []
|
55
|
+
property_hashes.each_with_index do |h,i|
|
56
|
+
row = rows[i]
|
57
|
+
entity = @repository.construct_entity(h, row)
|
58
|
+
result << (return_the_row_alongside_each_result ? [entity, row] : entity)
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
public
|
65
|
+
|
66
|
+
def results(lazy=false)
|
67
|
+
lazy_array = DatasetLazyArray.new(@dataset, @count_dataset) {|rows| load_from_rows(rows)}
|
68
|
+
lazy ? lazy_array : lazy_array.to_a
|
69
|
+
end
|
70
|
+
|
71
|
+
alias :to_a :results
|
72
|
+
|
73
|
+
# this one is useful if you add extra selected columns onto the dataset, and you want to get
|
74
|
+
# at those extra values on the underlying rows alongside the loaded entities.
|
75
|
+
def results_with_rows
|
76
|
+
load_from_rows(@dataset.all, true)
|
77
|
+
end
|
78
|
+
|
79
|
+
def single_result
|
80
|
+
row = Hold::Sequel.translate_exceptions {@dataset.first} or return
|
81
|
+
|
82
|
+
id = @repository.identity_mapper.load_value(row)
|
83
|
+
property_hash = {@repository.identity_property => id}
|
84
|
+
|
85
|
+
@property_versions.each do |prop_name, prop_version|
|
86
|
+
property_hash[prop_name] = @repository.mapper(prop_name).load_value(row, id, prop_version)
|
87
|
+
end
|
88
|
+
|
89
|
+
@repository.construct_entity(property_hash, row)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hold::Sequel
|
2
|
+
class QueryArrayCell
|
3
|
+
include Hold::ArrayCell
|
4
|
+
|
5
|
+
def initialize(repo, *query_args, &query_block)
|
6
|
+
@repo, @query_block = repo, query_block
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(properties=nil)
|
10
|
+
@repo.query(properties, &@query_block).to_a
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_slice(start, length, properties=nil)
|
14
|
+
@repo.query(properties, &@query_block).to_a(true)[start, length]
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_length
|
18
|
+
Query.new(@repo, [], &@query_block).to_a(true).length
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# If you want to observe events on a Hold::Sequel::IdentitySetRepository
|
2
|
+
# you need to implement this interface. Stubs supplied here to save you some
|
3
|
+
# boilerplate in case you only care about certain events.
|
4
|
+
#
|
5
|
+
# The callback methods correspond to their counterparts on
|
6
|
+
# Hold::Sequel::IdentityHashRepository but with an added argument
|
7
|
+
# passing the repository instance.
|
8
|
+
#
|
9
|
+
# TODO: generalise this to SetRepositories in general
|
10
|
+
module Hold::Sequel::RepositoryObserver
|
11
|
+
def pre_insert(repo, entity)
|
12
|
+
end
|
13
|
+
|
14
|
+
def post_insert(repo, entity, insert_rows, insert_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
def pre_update(repo, entity, update_entity)
|
18
|
+
end
|
19
|
+
|
20
|
+
def post_update(repo, entity, update_entity, update_rows)
|
21
|
+
end
|
22
|
+
|
23
|
+
def pre_delete(repo, entity)
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_delete(repo, entity)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Hold::Sequel
|
2
|
+
# Subclass of Sequel::IdentitySetRepository which adds support for a polymorphic type column which
|
3
|
+
# is used to persist the class of the model.
|
4
|
+
class IdentitySetRepository::WithPolymorphicTypeColumn < IdentitySetRepository
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def type_column; @type_column ||= superclass.type_column; end
|
8
|
+
def type_column_table; @type_column_table ||= superclass.type_column_table; end
|
9
|
+
def class_to_type_mapping; @class_to_type_mapping ||= (superclass.class_to_type_mapping if superclass < IdentitySetRepository::WithPolymorphicTypeColumn); end
|
10
|
+
def type_to_class_mapping; @type_to_class_mapping ||= (superclass.type_to_class_mapping if superclass < IdentitySetRepository::WithPolymorphicTypeColumn); end
|
11
|
+
def restricted_to_types; @restricted_to_types ||= (superclass.restricted_to_types if superclass < IdentitySetRepository::WithPolymorphicTypeColumn); end
|
12
|
+
|
13
|
+
def supported_classes
|
14
|
+
if restricted_to_types
|
15
|
+
type_to_class_mapping.values_at(*restricted_to_types)
|
16
|
+
else
|
17
|
+
class_to_type_mapping.keys
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def set_type_column(column, table, mapping=nil)
|
24
|
+
unless superclass == IdentitySetRepository::WithPolymorphicTypeColumn
|
25
|
+
raise "set_type_column only on the topmost IdentitySetRepository::WithPolymorphicTypeColumn subclass"
|
26
|
+
end
|
27
|
+
table, mapping = tables.first.first, table if table.is_a?(Hash)
|
28
|
+
@type_column = column
|
29
|
+
@type_column_table = table
|
30
|
+
@class_to_type_mapping = mapping
|
31
|
+
@type_to_class_mapping = mapping.invert
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_model_class(model_class)
|
35
|
+
@model_class = model_class
|
36
|
+
raise "set_type_column before set_model_class" unless class_to_type_mapping
|
37
|
+
klasses = class_to_type_mapping.keys.select {|klass| klass <= model_class}
|
38
|
+
@restricted_to_types = if klasses.size < @class_to_type_mapping.size
|
39
|
+
class_to_type_mapping.values_at(*klasses)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(db)
|
45
|
+
super
|
46
|
+
@qualified_type_column = Sequel::SQL::QualifiedIdentifier.new(self.class.type_column_table, self.class.type_column)
|
47
|
+
@aliased_type_column = Sequel::SQL::AliasedExpression.new(@qualified_type_column, :type)
|
48
|
+
|
49
|
+
@restricted_to_types = self.class.restricted_to_types
|
50
|
+
@tables_restricting_type = {}
|
51
|
+
self.class.tables.each do |name, options|
|
52
|
+
@tables_restricting_type[name] = true if options[:restricts_type]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def can_get_class?(model_class)
|
57
|
+
self.class.supported_classes.include?(model_class)
|
58
|
+
end
|
59
|
+
|
60
|
+
def can_set_class?(model_class)
|
61
|
+
self.class.supported_classes.include?(model_class)
|
62
|
+
end
|
63
|
+
|
64
|
+
def construct_entity(property_hash, row=nil)
|
65
|
+
type_value = row && row[:type] or return super
|
66
|
+
klass = self.class.type_to_class_mapping[type_value || @restricted_to_types.first] or
|
67
|
+
raise "WithPolymorphicTypeColumn: type column value #{type_value} not found in mapping"
|
68
|
+
klass.new(property_hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
# This optimisation has to be turned off for polymorphic repositories, since even if
|
72
|
+
# we know the ID, we have to query the db to find out the appropriate class to construct
|
73
|
+
# the object as.
|
74
|
+
def can_construct_from_id_alone?(properties)
|
75
|
+
super && @restricted_to_types && @restricted_to_types.length == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# ensure we select the type column in addition to any columns for mapped properties,
|
79
|
+
# so we know which class to instantiate for each row.
|
80
|
+
#
|
81
|
+
# If we're restricted to only one class, we don't need to select the type column
|
82
|
+
def columns_aliases_and_tables_for_properties(properties)
|
83
|
+
columns_by_property, aliased_columns, tables = super
|
84
|
+
unless @restricted_to_types && @restricted_to_types.length == 1
|
85
|
+
aliased_columns << @aliased_type_column
|
86
|
+
tables << self.class.type_column_table unless tables.include?(self.class.type_column_table)
|
87
|
+
end
|
88
|
+
return columns_by_property, aliased_columns, tables
|
89
|
+
end
|
90
|
+
|
91
|
+
# Where 'restricted_to_types' has been set, ensure we add a filter to the where
|
92
|
+
# clause restricting to rows with the allowed class (or classes).
|
93
|
+
#
|
94
|
+
# Except, where one of the tables used is specified in this repo's config as
|
95
|
+
# :restricts_type => true, this is taken to mean that (inner) joining to this table
|
96
|
+
# effectively acts as this repo's restricted_to_types restriction. hence no additional
|
97
|
+
# where clause is needed in order to do this. Helps with Class Table Inheritance.
|
98
|
+
def dataset_to_select_tables(*tables)
|
99
|
+
if @restricted_to_types && !@tables_restricting_type.values_at(*tables).any?
|
100
|
+
super.filter(@qualified_type_column => @restricted_to_types)
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def insert_row_for_entity(entity, table, id=nil)
|
109
|
+
row = super
|
110
|
+
if table == self.class.type_column_table
|
111
|
+
row[self.class.type_column] = self.class.class_to_type_mapping[entity.class] or
|
112
|
+
raise "WithPolymorphicTypeColumn: class #{entity.class} not found in mapping"
|
113
|
+
end
|
114
|
+
row
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'hold/interfaces'
|
2
|
+
|
3
|
+
module Hold
|
4
|
+
|
5
|
+
module Serialized; end
|
6
|
+
|
7
|
+
# A repository which caches serialized versions of an entity in a string-based key/value cache.
|
8
|
+
#
|
9
|
+
# Wraps a string-based HashRepository, and requires a serializer responding to 'serialize' and
|
10
|
+
# 'deserialize'.
|
11
|
+
#
|
12
|
+
# May optionally have a 'key_prefix', which is a prefixed namespace added to the cache keys
|
13
|
+
# before getting/setting the serialized values in the underlying cache.
|
14
|
+
class Serialized::HashRepository
|
15
|
+
include Hold::HashRepository
|
16
|
+
|
17
|
+
attr_reader :cache, :serializer, :key_prefix
|
18
|
+
|
19
|
+
def initialize(cache, serializer, key_prefix=nil)
|
20
|
+
@cache = cache
|
21
|
+
@serializer = serializer
|
22
|
+
@key_prefix = key_prefix
|
23
|
+
end
|
24
|
+
|
25
|
+
def cache_key(key)
|
26
|
+
@key_prefix ? @key_prefix + key.to_s : key.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_with_key(key, entity)
|
30
|
+
@cache.set_with_key(cache_key(key), @serializer.serialize(entity))
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_with_key(key)
|
34
|
+
json = @cache.get_with_key(cache_key(key)) and @serializer.deserialize(json)
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_many_with_keys(keys)
|
38
|
+
jsons = @cache.get_many_with_keys(*keys.map {|key| cache_key(key)})
|
39
|
+
jsons.map {|json| json && @serializer.deserialize(json)}
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_key?(key)
|
43
|
+
@cache.has_key?(cache_key(key))
|
44
|
+
end
|
45
|
+
alias_method :key?, :has_key?
|
46
|
+
|
47
|
+
def clear_key(key)
|
48
|
+
@cache.clear_key(cache_key(key))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Serialized::IdentitySetRepository
|
53
|
+
include Hold::IdentitySetRepository
|
54
|
+
|
55
|
+
attr_reader :cache, :serializer, :key_prefix
|
56
|
+
|
57
|
+
def initialize(cache, serializer, key_prefix=nil)
|
58
|
+
@cache = cache
|
59
|
+
@serializer = serializer
|
60
|
+
@key_prefix = key_prefix
|
61
|
+
end
|
62
|
+
|
63
|
+
def cache_key(key)
|
64
|
+
@key_prefix ? @key_prefix + key.to_s : key.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
def allocates_ids?
|
68
|
+
false
|
69
|
+
end
|
70
|
+
|
71
|
+
def store(object)
|
72
|
+
id = object.id or raise MissingIdentity
|
73
|
+
@cache.set_with_key(cache_key(id), @serializer.serialize(object))
|
74
|
+
object
|
75
|
+
end
|
76
|
+
|
77
|
+
def delete(object)
|
78
|
+
id = object.id or raise MissingIdentity
|
79
|
+
delete_id(id)
|
80
|
+
end
|
81
|
+
|
82
|
+
def contains?(object)
|
83
|
+
id = object.id or raise MissingIdentity
|
84
|
+
contains_id?(id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_by_id(id)
|
88
|
+
json = @cache.get_with_key(cache_key(id))
|
89
|
+
string_hash = @serializer.deserialize(json)
|
90
|
+
string_hash = string_hash.inject({}){|memo,(k,v)|
|
91
|
+
memo[k.to_sym] = v; memo
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete_id(id)
|
96
|
+
@cache.clear_key(cache_key(id))
|
97
|
+
end
|
98
|
+
|
99
|
+
def contains_id?(id)
|
100
|
+
@cache.has_key?(cache_key(id))
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/hold/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hold
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Willson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: test-unit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.2'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-spec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mocha
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: json
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sqlite3
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sequel
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: wirer
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.4.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.4.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: thin_models
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.1.4
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.1.4
|
139
|
+
description:
|
140
|
+
email:
|
141
|
+
- matthew@playlouder.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- README.md
|
147
|
+
- lib/hold.rb
|
148
|
+
- lib/hold/file/hash_repository.rb
|
149
|
+
- lib/hold/in_memory.rb
|
150
|
+
- lib/hold/interfaces.rb
|
151
|
+
- lib/hold/sequel.rb
|
152
|
+
- lib/hold/sequel/dataset_lazy_array.rb
|
153
|
+
- lib/hold/sequel/identity_set_repository.rb
|
154
|
+
- lib/hold/sequel/polymorphic_repository.rb
|
155
|
+
- lib/hold/sequel/property_mapper.rb
|
156
|
+
- lib/hold/sequel/property_mapper/array.rb
|
157
|
+
- lib/hold/sequel/property_mapper/column.rb
|
158
|
+
- lib/hold/sequel/property_mapper/created_at.rb
|
159
|
+
- lib/hold/sequel/property_mapper/custom_query.rb
|
160
|
+
- lib/hold/sequel/property_mapper/custom_query_single_value.rb
|
161
|
+
- lib/hold/sequel/property_mapper/foreign_key.rb
|
162
|
+
- lib/hold/sequel/property_mapper/hash.rb
|
163
|
+
- lib/hold/sequel/property_mapper/identity.rb
|
164
|
+
- lib/hold/sequel/property_mapper/many_to_many.rb
|
165
|
+
- lib/hold/sequel/property_mapper/one_to_many.rb
|
166
|
+
- lib/hold/sequel/property_mapper/transformed_column.rb
|
167
|
+
- lib/hold/sequel/property_mapper/updated_at.rb
|
168
|
+
- lib/hold/sequel/query.rb
|
169
|
+
- lib/hold/sequel/query_array_cell.rb
|
170
|
+
- lib/hold/sequel/repository_observer.rb
|
171
|
+
- lib/hold/sequel/with_polymorphic_type_column.rb
|
172
|
+
- lib/hold/serialized.rb
|
173
|
+
- lib/hold/serialized/json_serializer.rb
|
174
|
+
- lib/hold/version.rb
|
175
|
+
homepage:
|
176
|
+
licenses: []
|
177
|
+
metadata: {}
|
178
|
+
post_install_message:
|
179
|
+
rdoc_options: []
|
180
|
+
require_paths:
|
181
|
+
- lib
|
182
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
|
+
requirements:
|
189
|
+
- - ">="
|
190
|
+
- !ruby/object:Gem::Version
|
191
|
+
version: '0'
|
192
|
+
requirements: []
|
193
|
+
rubyforge_project:
|
194
|
+
rubygems_version: 2.2.2
|
195
|
+
signing_key:
|
196
|
+
specification_version: 4
|
197
|
+
summary: A library geared towards separating persistence concerns from data model
|
198
|
+
classes
|
199
|
+
test_files: []
|