rom 0.1.2 → 0.2.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.
- data/.rspec +2 -0
- data/.travis.yml +22 -0
- data/Changelog.md +16 -0
- data/Gemfile +13 -6
- data/Gemfile.devtools +71 -0
- data/Guardfile +19 -0
- data/LICENSE +1 -1
- data/README.md +52 -30
- data/Rakefile +3 -0
- data/config/devtools.yml +4 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +5 -0
- data/config/reek.yml +103 -0
- data/config/rubocop.yml +62 -0
- data/config/yardstick.yml +2 -0
- data/lib/rom.rb +13 -5
- data/lib/rom/constants.rb +16 -0
- data/lib/rom/environment.rb +105 -0
- data/lib/rom/environment/builder.rb +71 -0
- data/lib/rom/mapper.rb +176 -0
- data/lib/rom/mapper/attribute.rb +108 -0
- data/lib/rom/mapper/builder.rb +58 -0
- data/lib/rom/mapper/builder/definition.rb +162 -0
- data/lib/rom/mapper/header.rb +103 -0
- data/lib/rom/mapper/loader_builder.rb +26 -0
- data/lib/rom/relation.rb +375 -0
- data/lib/rom/repository.rb +71 -0
- data/lib/rom/schema.rb +21 -0
- data/lib/rom/schema/builder.rb +59 -0
- data/lib/rom/schema/definition.rb +84 -0
- data/lib/rom/schema/definition/relation.rb +80 -0
- data/lib/rom/schema/definition/relation/base.rb +27 -0
- data/lib/rom/session.rb +111 -0
- data/lib/rom/session/environment.rb +67 -0
- data/lib/rom/session/identity_map.rb +43 -0
- data/lib/rom/session/mapper.rb +62 -0
- data/lib/rom/session/relation.rb +140 -0
- data/lib/rom/session/state.rb +59 -0
- data/lib/rom/session/state/created.rb +22 -0
- data/lib/rom/session/state/deleted.rb +25 -0
- data/lib/rom/session/state/persisted.rb +34 -0
- data/lib/rom/session/state/transient.rb +20 -0
- data/lib/rom/session/state/updated.rb +29 -0
- data/lib/rom/session/tracker.rb +62 -0
- data/lib/rom/support/axiom/adapter.rb +111 -0
- data/lib/rom/support/axiom/adapter/data_objects.rb +38 -0
- data/lib/rom/support/axiom/adapter/memory.rb +25 -0
- data/lib/rom/support/axiom/adapter/postgres.rb +19 -0
- data/lib/rom/support/axiom/adapter/sqlite3.rb +20 -0
- data/lib/version.rb +1 -1
- data/rom.gemspec +7 -3
- data/spec/integration/environment_setup_spec.rb +24 -0
- data/spec/integration/grouped_mappers_spec.rb +87 -0
- data/spec/integration/join_and_group_spec.rb +76 -0
- data/spec/integration/join_and_wrap_spec.rb +68 -0
- data/spec/integration/mapping_embedded_relations_spec.rb +73 -0
- data/spec/integration/mapping_relations_spec.rb +120 -0
- data/spec/integration/schema_definition_spec.rb +152 -0
- data/spec/integration/session_spec.rb +87 -0
- data/spec/integration/wrapped_mappers_spec.rb +73 -0
- data/spec/shared/unit/environment_context.rb +6 -0
- data/spec/shared/unit/loader.rb +11 -0
- data/spec/shared/unit/loader_identity.rb +13 -0
- data/spec/shared/unit/mapper_context.rb +11 -0
- data/spec/shared/unit/relation_context.rb +82 -0
- data/spec/shared/unit/session_environment_context.rb +11 -0
- data/spec/shared/unit/session_relation_context.rb +18 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/support/helper.rb +34 -0
- data/spec/support/ice_nine_config.rb +10 -0
- data/spec/support/test_mapper.rb +110 -0
- data/spec/unit/rom/environment/builder/mapping_spec.rb +24 -0
- data/spec/unit/rom/environment/builder/schema_spec.rb +33 -0
- data/spec/unit/rom/environment/class_methods/setup_spec.rb +18 -0
- data/spec/unit/rom/environment/repository_spec.rb +21 -0
- data/spec/unit/rom/mapper/attribute/embedded_collection/to_ast_spec.rb +18 -0
- data/spec/unit/rom/mapper/attribute/embedded_value/to_ast_spec.rb +16 -0
- data/spec/unit/rom/mapper/attribute/rename_spec.rb +9 -0
- data/spec/unit/rom/mapper/attribute/to_ast_spec.rb +9 -0
- data/spec/unit/rom/mapper/builder/class_methods/call_spec.rb +61 -0
- data/spec/unit/rom/mapper/class_methods/build_spec.rb +55 -0
- data/spec/unit/rom/mapper/dump_spec.rb +11 -0
- data/spec/unit/rom/mapper/group_spec.rb +35 -0
- data/spec/unit/rom/mapper/header/each_spec.rb +26 -0
- data/spec/unit/rom/mapper/header/element_reader_spec.rb +21 -0
- data/spec/unit/rom/mapper/header/group_spec.rb +18 -0
- data/spec/unit/rom/mapper/header/join_spec.rb +14 -0
- data/spec/unit/rom/mapper/header/keys_spec.rb +29 -0
- data/spec/unit/rom/mapper/header/project_spec.rb +13 -0
- data/spec/unit/rom/mapper/header/rename_spec.rb +11 -0
- data/spec/unit/rom/mapper/header/to_ast_spec.rb +11 -0
- data/spec/unit/rom/mapper/header/wrap_spec.rb +18 -0
- data/spec/unit/rom/mapper/identity_from_tuple_spec.rb +11 -0
- data/spec/unit/rom/mapper/identity_spec.rb +11 -0
- data/spec/unit/rom/mapper/join_spec.rb +15 -0
- data/spec/unit/rom/mapper/load_spec.rb +11 -0
- data/spec/unit/rom/mapper/new_object_spec.rb +14 -0
- data/spec/unit/rom/mapper/project_spec.rb +11 -0
- data/spec/unit/rom/mapper/rename_spec.rb +16 -0
- data/spec/unit/rom/mapper/wrap_spec.rb +35 -0
- data/spec/unit/rom/relation/delete_spec.rb +15 -0
- data/spec/unit/rom/relation/drop_spec.rb +11 -0
- data/spec/unit/rom/relation/each_spec.rb +23 -0
- data/spec/unit/rom/relation/first_spec.rb +19 -0
- data/spec/unit/rom/relation/group_spec.rb +29 -0
- data/spec/unit/rom/relation/inject_mapper_spec.rb +17 -0
- data/spec/unit/rom/relation/insert_spec.rb +13 -0
- data/spec/unit/rom/relation/last_spec.rb +19 -0
- data/spec/unit/rom/relation/one_spec.rb +49 -0
- data/spec/unit/rom/relation/rename_spec.rb +21 -0
- data/spec/unit/rom/relation/replace_spec.rb +13 -0
- data/spec/unit/rom/relation/restrict_spec.rb +25 -0
- data/spec/unit/rom/relation/sort_by_spec.rb +25 -0
- data/spec/unit/rom/relation/take_spec.rb +11 -0
- data/spec/unit/rom/relation/to_a_spec.rb +20 -0
- data/spec/unit/rom/relation/update_spec.rb +25 -0
- data/spec/unit/rom/relation/wrap_spec.rb +29 -0
- data/spec/unit/rom/repository/class_methods/build_spec.rb +27 -0
- data/spec/unit/rom/repository/element_reader_spec.rb +21 -0
- data/spec/unit/rom/repository/element_writer_spec.rb +18 -0
- data/spec/unit/rom/schema/builder/class_methods/build_spec.rb +103 -0
- data/spec/unit/rom/schema/element_reader_spec.rb +15 -0
- data/spec/unit/rom/session/class_methods/start_spec.rb +23 -0
- data/spec/unit/rom/session/clean_predicate_spec.rb +21 -0
- data/spec/unit/rom/session/environment/element_reader_spec.rb +13 -0
- data/spec/unit/rom/session/flush_spec.rb +58 -0
- data/spec/unit/rom/session/mapper/load_spec.rb +47 -0
- data/spec/unit/rom/session/relation/delete_spec.rb +28 -0
- data/spec/unit/rom/session/relation/dirty_predicate_spec.rb +35 -0
- data/spec/unit/rom/session/relation/identity_spec.rb +11 -0
- data/spec/unit/rom/session/relation/new_spec.rb +50 -0
- data/spec/unit/rom/session/relation/save_spec.rb +50 -0
- data/spec/unit/rom/session/relation/state_spec.rb +23 -0
- data/spec/unit/rom/session/relation/track_spec.rb +23 -0
- data/spec/unit/rom/session/relation/tracking_predicate_spec.rb +23 -0
- data/spec/unit/rom/session/relation/update_attributes_spec.rb +45 -0
- data/spec/unit/rom/session/state_spec.rb +79 -0
- metadata +212 -11
data/lib/rom.rb
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
end
|
|
1
|
+
# encoding: utf-8
|
|
3
2
|
|
|
4
|
-
require '
|
|
5
|
-
require '
|
|
6
|
-
require '
|
|
3
|
+
require 'adamantium'
|
|
4
|
+
require 'concord'
|
|
5
|
+
require 'equalizer'
|
|
6
|
+
require 'charlatan'
|
|
7
|
+
require 'morpher'
|
|
8
|
+
require 'axiom'
|
|
9
|
+
require 'axiom-optimizer'
|
|
10
|
+
|
|
11
|
+
require 'rom/environment'
|
|
12
|
+
require 'rom/relation'
|
|
13
|
+
require 'rom/mapper'
|
|
14
|
+
require 'rom/session'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module ROM
|
|
2
|
+
# Raised when the returned tuples are unexpectedly empty
|
|
3
|
+
NoTuplesError = Class.new(RuntimeError)
|
|
4
|
+
|
|
5
|
+
# Raised when the returned tuples are unexpectedly too many
|
|
6
|
+
ManyTuplesError = Class.new(RuntimeError)
|
|
7
|
+
|
|
8
|
+
# Represent an undefined argument
|
|
9
|
+
Undefined = Class.new.freeze
|
|
10
|
+
|
|
11
|
+
# An empty frozen Hash useful for parameter default values
|
|
12
|
+
EMPTY_HASH = {}.freeze
|
|
13
|
+
|
|
14
|
+
# An empty frozen Array useful for parameter default values
|
|
15
|
+
EMPTY_ARRAY = [].freeze
|
|
16
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'rom/environment/builder'
|
|
4
|
+
|
|
5
|
+
module ROM
|
|
6
|
+
|
|
7
|
+
# The environment configures repositories and loads schema with relations
|
|
8
|
+
#
|
|
9
|
+
class Environment
|
|
10
|
+
# @api private
|
|
11
|
+
attr_reader :repositories, :relations
|
|
12
|
+
|
|
13
|
+
# Return schema registry
|
|
14
|
+
#
|
|
15
|
+
# @return [Schema]
|
|
16
|
+
#
|
|
17
|
+
# @api public
|
|
18
|
+
attr_reader :schema
|
|
19
|
+
|
|
20
|
+
# Return mapper registry
|
|
21
|
+
#
|
|
22
|
+
# @return [Hash]
|
|
23
|
+
#
|
|
24
|
+
# @api public
|
|
25
|
+
attr_reader :mappers
|
|
26
|
+
|
|
27
|
+
# @api private
|
|
28
|
+
def initialize(repositories, schema, relations, mappers)
|
|
29
|
+
@repositories = repositories
|
|
30
|
+
@schema = schema
|
|
31
|
+
@relations = relations
|
|
32
|
+
@mappers = mappers
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Setup ROM environment
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
#
|
|
39
|
+
# env = ROM::Environment.setup(test: 'memory://test') do
|
|
40
|
+
# schema do
|
|
41
|
+
# base_relation(:users) do
|
|
42
|
+
# repository :test
|
|
43
|
+
#
|
|
44
|
+
# attribute :id, Integer
|
|
45
|
+
# attribute :name, String
|
|
46
|
+
#
|
|
47
|
+
# key :id
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# mapping do
|
|
52
|
+
# relation(:users) do
|
|
53
|
+
# model User
|
|
54
|
+
#
|
|
55
|
+
# map :id, :name
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# @param [Environment, Hash<#to_sym, String>] config
|
|
62
|
+
# an environment or a hash of adapter uri strings,
|
|
63
|
+
# keyed by repository name
|
|
64
|
+
#
|
|
65
|
+
# @return [Environment::Builder]
|
|
66
|
+
#
|
|
67
|
+
# @api public
|
|
68
|
+
def self.setup(config, &block)
|
|
69
|
+
builder = Builder.call(config)
|
|
70
|
+
|
|
71
|
+
if block
|
|
72
|
+
builder.instance_eval(&block)
|
|
73
|
+
builder.finalize
|
|
74
|
+
else
|
|
75
|
+
builder
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Return registered relation
|
|
80
|
+
#
|
|
81
|
+
# @example
|
|
82
|
+
#
|
|
83
|
+
# env[:users]
|
|
84
|
+
#
|
|
85
|
+
# @param [Symbol] relation name
|
|
86
|
+
#
|
|
87
|
+
# @return [Relation]
|
|
88
|
+
#
|
|
89
|
+
# @api public
|
|
90
|
+
def [](name)
|
|
91
|
+
relations[name]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The repository with the given +name+
|
|
95
|
+
#
|
|
96
|
+
# @return [Repository]
|
|
97
|
+
#
|
|
98
|
+
# @api public
|
|
99
|
+
def repository(name)
|
|
100
|
+
repositories[name]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end # Environment
|
|
104
|
+
|
|
105
|
+
end # ROM
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'addressable/uri'
|
|
4
|
+
|
|
5
|
+
require 'rom/environment'
|
|
6
|
+
require 'rom/repository'
|
|
7
|
+
require 'rom/schema/builder'
|
|
8
|
+
require 'rom/mapper/builder'
|
|
9
|
+
|
|
10
|
+
module ROM
|
|
11
|
+
|
|
12
|
+
# The environment configures repositories and loads schema with relations
|
|
13
|
+
#
|
|
14
|
+
class Environment
|
|
15
|
+
|
|
16
|
+
# Environment builder DSL
|
|
17
|
+
#
|
|
18
|
+
class Builder
|
|
19
|
+
attr_reader :repositories, :relations, :mappers
|
|
20
|
+
|
|
21
|
+
# @api private
|
|
22
|
+
def self.call(config)
|
|
23
|
+
repositories = config.each_with_object({}) { |(name, uri), hash|
|
|
24
|
+
hash[name.to_sym] = Repository.build(name, Addressable::URI.parse(uri))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
new(repositories)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @api private
|
|
31
|
+
def initialize(repositories)
|
|
32
|
+
@repositories = repositories
|
|
33
|
+
@relations = {}
|
|
34
|
+
@schema = Schema::Builder.build(repositories)
|
|
35
|
+
@mappers = Mapper::Builder.new(schema)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @api private
|
|
39
|
+
def schema(&block)
|
|
40
|
+
@schema.call(&block) if block
|
|
41
|
+
@schema
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @api private
|
|
45
|
+
def mapping(&block)
|
|
46
|
+
mappers.call(&block)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @api private
|
|
50
|
+
def [](name)
|
|
51
|
+
relations[name]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @api private
|
|
55
|
+
def []=(name, relation)
|
|
56
|
+
relations[name] = relation
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @api private
|
|
60
|
+
def finalize
|
|
61
|
+
mappers.each do |name, mapper|
|
|
62
|
+
relations[name] = Relation.new(schema[name], mapper)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
Environment.new(repositories, schema.finalize, relations, mappers.finalize)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end # Builder
|
|
69
|
+
|
|
70
|
+
end # Environment
|
|
71
|
+
end # ROM
|
data/lib/rom/mapper.rb
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
|
|
5
|
+
require 'rom/constants'
|
|
6
|
+
require 'rom/mapper/header'
|
|
7
|
+
require 'rom/mapper/loader_builder'
|
|
8
|
+
|
|
9
|
+
module ROM
|
|
10
|
+
|
|
11
|
+
# Mappers load tuples into objects and dump objects back into tuples
|
|
12
|
+
#
|
|
13
|
+
class Mapper
|
|
14
|
+
include Equalizer.new(:header, :options)
|
|
15
|
+
|
|
16
|
+
DEFAULT_LOADER = :load_instance_variables
|
|
17
|
+
|
|
18
|
+
attr_reader :header, :loader, :dumper, :model, :type, :options
|
|
19
|
+
|
|
20
|
+
# Build a mapper
|
|
21
|
+
#
|
|
22
|
+
# @example
|
|
23
|
+
#
|
|
24
|
+
# User = Class.new { attr_reader :id, :name }
|
|
25
|
+
#
|
|
26
|
+
# mapper = ROM::Mapper.build([[:id, from: :user_id], [:name, from: :user_name]], model: User)
|
|
27
|
+
#
|
|
28
|
+
# user = mapper.load(user_id: 1, user_name: 'Jane')
|
|
29
|
+
# # => #<User:0x007fee3b8bf2c8 @id=1, @name="Jane">
|
|
30
|
+
#
|
|
31
|
+
# tuple = mapper.dump(user)
|
|
32
|
+
# # => [1, "Jane"]
|
|
33
|
+
#
|
|
34
|
+
# @return [Mapper]
|
|
35
|
+
#
|
|
36
|
+
# @api public
|
|
37
|
+
def self.build(attributes, options = EMPTY_HASH)
|
|
38
|
+
defaults = { type: DEFAULT_LOADER, model: OpenStruct }.update(options)
|
|
39
|
+
|
|
40
|
+
header = Header.build(attributes)
|
|
41
|
+
loader = LoaderBuilder.call(header, defaults[:model], defaults[:type])
|
|
42
|
+
|
|
43
|
+
new(header, loader, defaults)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# @api private
|
|
47
|
+
def initialize(header, loader, options)
|
|
48
|
+
@header = header
|
|
49
|
+
@loader = loader
|
|
50
|
+
@dumper = loader.inverse
|
|
51
|
+
@model = options.fetch(:model)
|
|
52
|
+
@type = options.fetch(:type)
|
|
53
|
+
@options = options
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Retrieve identity from the given object
|
|
57
|
+
#
|
|
58
|
+
# @example
|
|
59
|
+
#
|
|
60
|
+
# mapper.identity(user) # => [1]
|
|
61
|
+
#
|
|
62
|
+
# @param [Object]
|
|
63
|
+
#
|
|
64
|
+
# @return [Array]
|
|
65
|
+
#
|
|
66
|
+
# @api public
|
|
67
|
+
def identity(object)
|
|
68
|
+
header.keys.map { |key| object.send(key.name) }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Return identity from the given tuple
|
|
72
|
+
#
|
|
73
|
+
# @example
|
|
74
|
+
#
|
|
75
|
+
# mapper.identity_from_tuple({id: 1}) # => [1]
|
|
76
|
+
#
|
|
77
|
+
# @param [Axiom::Tuple,Hash]
|
|
78
|
+
#
|
|
79
|
+
# @return [Array]
|
|
80
|
+
#
|
|
81
|
+
# @api public
|
|
82
|
+
def identity_from_tuple(tuple)
|
|
83
|
+
header.keys.map { |key| tuple[key.name] }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Build a new model instance
|
|
87
|
+
#
|
|
88
|
+
# @example
|
|
89
|
+
#
|
|
90
|
+
# mapper = Mapper.build(header, User)
|
|
91
|
+
# mapper.new_object(id: 1, name: 'Jane') # => #<User @id=1 @name="Jane">
|
|
92
|
+
#
|
|
93
|
+
# @api public
|
|
94
|
+
def new_object(*args, &block)
|
|
95
|
+
model.new(*args, &block)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Load an object instance from the tuple
|
|
99
|
+
#
|
|
100
|
+
# @api public
|
|
101
|
+
def load(tuple)
|
|
102
|
+
loader.call(tuple)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Dump an object into a tuple
|
|
106
|
+
#
|
|
107
|
+
# @api public
|
|
108
|
+
#
|
|
109
|
+
# TODO: it's not clear how a tuple should look like for grouped/wrapped
|
|
110
|
+
# relation. the current implementation is temporary
|
|
111
|
+
def dump(object)
|
|
112
|
+
ary = dumper.call(object)
|
|
113
|
+
|
|
114
|
+
ary.each_with_object([]) do |(name, value), tuple|
|
|
115
|
+
attribute = header.detect { |attr| attr.tuple_key == name }
|
|
116
|
+
|
|
117
|
+
if attribute.respond_to?(:header)
|
|
118
|
+
names = attribute.header.attribute_names
|
|
119
|
+
|
|
120
|
+
if value.is_a?(Hash)
|
|
121
|
+
tuple << value.values_at(*names)
|
|
122
|
+
elsif value.is_a?(Array)
|
|
123
|
+
tuple << value.map { |v| v.values_at(*names) }
|
|
124
|
+
else
|
|
125
|
+
raise NotImplementedError
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
tuple << value
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# TODO: this should map the wrapping hash into {Symbol => Mapper::Header}
|
|
134
|
+
# otherwise header is coupled to mapper
|
|
135
|
+
#
|
|
136
|
+
# @api public
|
|
137
|
+
def wrap(other)
|
|
138
|
+
new(header.wrap(other))
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# TODO: this should map the grouping hash into {Symbol => Mapper::Header}
|
|
142
|
+
# otherwise header is coupled to mapper
|
|
143
|
+
#
|
|
144
|
+
# @api public
|
|
145
|
+
def group(other)
|
|
146
|
+
new(header.group(other))
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# @api public
|
|
150
|
+
def join(other)
|
|
151
|
+
new(header.join(other.header))
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# @api public
|
|
155
|
+
def project(names)
|
|
156
|
+
new(header.project(names))
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# @api public
|
|
160
|
+
def rename(names)
|
|
161
|
+
new(header.rename(names))
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @api private
|
|
165
|
+
def attribute(type, name)
|
|
166
|
+
type.build(name, type: model, header: header, node: loader.node)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# @api private
|
|
170
|
+
def new(new_header)
|
|
171
|
+
self.class.build(new_header, options)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
end # Mapper
|
|
175
|
+
|
|
176
|
+
end # ROM
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module ROM
|
|
4
|
+
class Mapper
|
|
5
|
+
|
|
6
|
+
# Represents a mapping attribute
|
|
7
|
+
#
|
|
8
|
+
# @private
|
|
9
|
+
class Attribute
|
|
10
|
+
include Adamantium, Concord::Public.new(:name, :options), Morpher::NodeHelpers
|
|
11
|
+
|
|
12
|
+
class EmbeddedValue < Attribute
|
|
13
|
+
|
|
14
|
+
# @api private
|
|
15
|
+
def to_ast
|
|
16
|
+
s(:key_transform, name, name, node)
|
|
17
|
+
end
|
|
18
|
+
memoize :to_ast
|
|
19
|
+
|
|
20
|
+
# @api private
|
|
21
|
+
def header
|
|
22
|
+
options.fetch(:header)
|
|
23
|
+
end
|
|
24
|
+
memoize :header
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
# @api private
|
|
29
|
+
def node
|
|
30
|
+
options.fetch(:node)
|
|
31
|
+
end
|
|
32
|
+
memoize :node
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class EmbeddedCollection < Attribute
|
|
36
|
+
|
|
37
|
+
# @api private
|
|
38
|
+
def to_ast
|
|
39
|
+
s(:key_transform, name, name, s(:map, node))
|
|
40
|
+
end
|
|
41
|
+
memoize :to_ast
|
|
42
|
+
|
|
43
|
+
# @api private
|
|
44
|
+
def header
|
|
45
|
+
options.fetch(:header)
|
|
46
|
+
end
|
|
47
|
+
memoize :header
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# @api private
|
|
52
|
+
def node
|
|
53
|
+
options.fetch(:node)
|
|
54
|
+
end
|
|
55
|
+
memoize :node
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# @api private
|
|
59
|
+
def self.build(*args)
|
|
60
|
+
input = args.first
|
|
61
|
+
|
|
62
|
+
if input.kind_of?(self)
|
|
63
|
+
input
|
|
64
|
+
else
|
|
65
|
+
name, options = args
|
|
66
|
+
new(name, options || {})
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @api private
|
|
71
|
+
def to_ast
|
|
72
|
+
s(:block, s(:key_fetch, tuple_key), s(:key_dump, name))
|
|
73
|
+
end
|
|
74
|
+
memoize :to_ast
|
|
75
|
+
|
|
76
|
+
# @api private
|
|
77
|
+
def key?
|
|
78
|
+
options.fetch(:key, false)
|
|
79
|
+
end
|
|
80
|
+
memoize :key?
|
|
81
|
+
|
|
82
|
+
# @api private
|
|
83
|
+
def mapping
|
|
84
|
+
{ tuple_key => name }
|
|
85
|
+
end
|
|
86
|
+
memoize :mapping
|
|
87
|
+
|
|
88
|
+
# @api private
|
|
89
|
+
def tuple_key
|
|
90
|
+
options[:from] || name
|
|
91
|
+
end
|
|
92
|
+
memoize :tuple_key
|
|
93
|
+
|
|
94
|
+
# @api private
|
|
95
|
+
def type
|
|
96
|
+
options[:type] || Object
|
|
97
|
+
end
|
|
98
|
+
memoize :type
|
|
99
|
+
|
|
100
|
+
# @api private
|
|
101
|
+
def rename(new_name)
|
|
102
|
+
self.class.new(new_name, options)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end # Attribute
|
|
106
|
+
|
|
107
|
+
end # Mapper
|
|
108
|
+
end # ROM
|