rom-fmp 0.0.4
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/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +60 -0
- data/Rakefile +12 -0
- data/lib/rom-fmp.rb +1 -0
- data/lib/rom/fmp.rb +21 -0
- data/lib/rom/fmp/commands.rb +19 -0
- data/lib/rom/fmp/commands/create.rb +29 -0
- data/lib/rom/fmp/commands/delete.rb +18 -0
- data/lib/rom/fmp/commands/update.rb +54 -0
- data/lib/rom/fmp/dataset.rb +121 -0
- data/lib/rom/fmp/gateway.rb +28 -0
- data/lib/rom/fmp/header.rb +57 -0
- data/lib/rom/fmp/micro01.rb +55 -0
- data/lib/rom/fmp/micro02.rb +161 -0
- data/lib/rom/fmp/mini.rb +91 -0
- data/lib/rom/fmp/relation.rb +18 -0
- data/lib/rom/fmp/relation/associations.rb +104 -0
- data/lib/rom/fmp/relation/class_methods.rb +48 -0
- data/lib/rom/fmp/relation/inspection.rb +16 -0
- data/lib/rom/fmp/rfm/fmresultset.yml +86 -0
- data/lib/rom/fmp/rfm/layout.rb +8 -0
- data/lib/rom/fmp/version.rb +5 -0
- data/rom-fmp.gemspec +28 -0
- data/spec/rom/fmp_spec.rb +12 -0
- data/spec/rom/gateway_spec.rb +53 -0
- data/spec/rom/relation_spec.rb +17 -0
- data/spec/spec_helper.rb +15 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 03a589c1294de76a28b2e07762205c329356ae90
|
4
|
+
data.tar.gz: 754d5e2f884652cfaf214b64a638192c1c445089
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d0ccd25e0f13e3e7587a0d8d76191fa37ff905321a59fe651921fb7146a3593c0e412840b3168f027a5568ab07cc4bb8875dd24e5657ed97056d372ae4d50a5c
|
7
|
+
data.tar.gz: f3bd10a8bdd7e7bee0391e69b0e75443f56f544d51072b7f6e5152756cc0ca79a457e86ab39e795de1e7c6f3ab062de0eeda15faf5a7a7b2c149cd219b817b18
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# rom-fmp changelog
|
2
|
+
|
3
|
+
## v0.0.4 2015-09-17
|
4
|
+
|
5
|
+
* Rewrite gateway, dataset, relation.
|
6
|
+
* Basic relation support for :find, :all, :count, :create, :update, :delete.
|
7
|
+
* Supports command composition/chaining and command currying.
|
8
|
+
|
9
|
+
## v0.0.1 2015-03-30
|
10
|
+
|
11
|
+
* Initial commit.
|
12
|
+
* Basic reads using relations.
|
13
|
+
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 wbr
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# rom-fmp
|
2
|
+
|
3
|
+
A filemaker adapter for the rom-rb data mapping & persistence gem.
|
4
|
+
See [rom-rb](https://github.com/rom-rb) on github or [rom-rb.org](http://rom-rb.org)
|
5
|
+
for more information about Ruby Object Mapper.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'rom-fmp'
|
12
|
+
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install rom-fmp
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
require 'rom/fmp'
|
25
|
+
|
26
|
+
DB_CONFIG = {
|
27
|
+
adapter: 'fmp',
|
28
|
+
host: 'my.fm.server.com',
|
29
|
+
account_name: 'my_account',
|
30
|
+
password: '12345',
|
31
|
+
database: 'MyFmpDatabase',
|
32
|
+
}
|
33
|
+
|
34
|
+
ROM.use(:auto_registration)
|
35
|
+
ROM.setup(:fmp, DB_CONFIG)
|
36
|
+
|
37
|
+
class Users < ROM::Relation[:fmp]
|
38
|
+
register_as :users
|
39
|
+
dataset :user_xml # Filemaker layout name.
|
40
|
+
|
41
|
+
def by_login(name)
|
42
|
+
find(:login=>name.to_s)
|
43
|
+
end
|
44
|
+
|
45
|
+
def activated
|
46
|
+
find(:activated_at=>'>1/1/2000')
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
rom_env = ROM.finalize.env
|
52
|
+
|
53
|
+
rom_users_relation = rom_env.relation(:users)
|
54
|
+
|
55
|
+
activated_users_by_login = rom_users_relation.activated.by_login
|
56
|
+
|
57
|
+
activated_users_by_login.call('bill').to_a
|
58
|
+
activated_users_by_login.('bill').to_a
|
59
|
+
activated_users_by_login['bill'].to_a
|
60
|
+
|
data/Rakefile
ADDED
data/lib/rom-fmp.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rom/fmp'
|
data/lib/rom/fmp.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rfm'
|
2
|
+
require 'rom'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module FMP
|
7
|
+
ConstraintError = Class.new(ROM::CommandError)
|
8
|
+
FMRESULTSET_TEMPLATE = {:template=>YAML.load_file(File.expand_path("../fmp/rfm/fmresultset.yml", __FILE__))}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rom/fmp/version"
|
13
|
+
require "rom/fmp/dataset"
|
14
|
+
require "rom/fmp/gateway"
|
15
|
+
require "rom/fmp/relation"
|
16
|
+
|
17
|
+
#require "rom/fmp/mini"
|
18
|
+
#require "rom/fmp/micro01"
|
19
|
+
#require "rom/fmp/micro02"
|
20
|
+
|
21
|
+
ROM.register_adapter(:fmp, ROM::FMP)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
### NOT USED YET ###
|
2
|
+
|
3
|
+
require 'rom/commands'
|
4
|
+
|
5
|
+
module ROM
|
6
|
+
module FMP
|
7
|
+
module Commands
|
8
|
+
ERRORS = [
|
9
|
+
# Sequel::UniqueConstraintViolation,
|
10
|
+
# Sequel::NotNullConstraintViolation
|
11
|
+
].freeze
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'rom/fmp/commands/create'
|
17
|
+
require 'rom/fmp/commands/update'
|
18
|
+
require 'rom/fmp/commands/delete'
|
19
|
+
#require 'rom/fmp/commands_ext/postgres'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rom/fmp/commands'
|
2
|
+
#require 'rom/fmp/commands/transaction'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module FMP
|
6
|
+
module Commands
|
7
|
+
class Create < ROM::Commands::Create
|
8
|
+
#include Transaction
|
9
|
+
|
10
|
+
def execute(tuples)
|
11
|
+
insert_tuples = Array([tuples]).flatten.map do |tuple|
|
12
|
+
attributes = input[tuple]
|
13
|
+
validator.call(attributes)
|
14
|
+
attributes.to_h
|
15
|
+
end
|
16
|
+
|
17
|
+
insert(insert_tuples)
|
18
|
+
rescue *ERRORS => e
|
19
|
+
raise ConstraintError, e.message
|
20
|
+
end
|
21
|
+
|
22
|
+
def insert(tuples)
|
23
|
+
pks = tuples.map { |tuple| relation.insert(tuple) }
|
24
|
+
relation.where(relation.primary_key => pks)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rom/fmp/commands'
|
2
|
+
#require 'rom/fmp/commands/transaction'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module FMP
|
6
|
+
module Commands
|
7
|
+
class Delete < ROM::Commands::Delete
|
8
|
+
# include Transaction
|
9
|
+
|
10
|
+
def execute
|
11
|
+
deleted = target.to_a
|
12
|
+
target.delete
|
13
|
+
deleted
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rom/fmp/commands'
|
2
|
+
#require 'rom/fmp/commands/transaction'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module FMP
|
6
|
+
module Commands
|
7
|
+
class Update < ROM::Commands::Update
|
8
|
+
#include Transaction
|
9
|
+
|
10
|
+
option :original, type: Hash, reader: true
|
11
|
+
|
12
|
+
alias_method :to, :call
|
13
|
+
|
14
|
+
def execute(tuple)
|
15
|
+
attributes = input[tuple]
|
16
|
+
validator.call(attributes)
|
17
|
+
|
18
|
+
changed = diff(attributes.to_h)
|
19
|
+
|
20
|
+
if changed.any?
|
21
|
+
update(changed)
|
22
|
+
else
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def change(original)
|
28
|
+
self.class.new(relation, options.merge(original: original))
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(tuple)
|
32
|
+
pks = relation.map { |t| t[primary_key] }
|
33
|
+
dataset = relation.dataset
|
34
|
+
dataset.update(tuple)
|
35
|
+
dataset.unfiltered.where(primary_key => pks).to_a
|
36
|
+
end
|
37
|
+
|
38
|
+
def primary_key
|
39
|
+
relation.primary_key
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def diff(tuple)
|
45
|
+
if original
|
46
|
+
Hash[tuple.to_a - (tuple.to_a & original.to_a)]
|
47
|
+
else
|
48
|
+
tuple
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
#require 'rom/support/array_dataset'
|
2
|
+
require 'rom'
|
3
|
+
require 'rfm'
|
4
|
+
require 'rom/fmp/rfm/layout'
|
5
|
+
require 'charlatan'
|
6
|
+
|
7
|
+
module ROM
|
8
|
+
module FMP
|
9
|
+
|
10
|
+
class Dataset
|
11
|
+
# This was used but is not now.
|
12
|
+
# include Rom::ArrayDataset
|
13
|
+
|
14
|
+
# Used to compile compound queries from chained relations.
|
15
|
+
include ::Rfm::Scope
|
16
|
+
|
17
|
+
DEFAULT_REQUEST_OPTIONS = {}
|
18
|
+
|
19
|
+
# Dataset instance expects to hold Array of data in @data,
|
20
|
+
# but it will also hold a FM Layout instance.
|
21
|
+
# If any call to Dataset instance returns Array instance,
|
22
|
+
# it will be wrapped in a new Dataset instance.
|
23
|
+
include Charlatan.new(:data, kind: Array)
|
24
|
+
attr_reader :layout, :data, :queries
|
25
|
+
|
26
|
+
# Store layout, data, query in new dataset.
|
27
|
+
def initialize(_layout, _data=[], _queries=[])
|
28
|
+
@layout = _layout
|
29
|
+
@queries = _queries
|
30
|
+
#puts "DATASET NEW queries:#{@queries}"
|
31
|
+
super(_data)
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
|
36
|
+
# Creates new dataset with current args and resultset. Not lazy.
|
37
|
+
# This may not be how rom or sql uses 'where'. Find out more.
|
38
|
+
def where(*args)
|
39
|
+
#self.class.new(layout, layout.find(*args), args)
|
40
|
+
get_results(:find, args)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Creates new dataset with existing data & queries, plus new query
|
44
|
+
def find(*args)
|
45
|
+
#self.class.new(layout, data, (queries.dup << args))
|
46
|
+
wrap_data(data, (queries.dup << args))
|
47
|
+
end
|
48
|
+
|
49
|
+
def any(options={})
|
50
|
+
wrap_data(layout.any(options))
|
51
|
+
end
|
52
|
+
|
53
|
+
def all(options={})
|
54
|
+
wrap_data(layout.all(DEFAULT_REQUEST_OPTIONS.merge(options)))
|
55
|
+
end
|
56
|
+
|
57
|
+
def count(*args)
|
58
|
+
compiled_query = compile_query
|
59
|
+
compiled_query ? layout.count(*compiled_query) : layout.total_count
|
60
|
+
end
|
61
|
+
|
62
|
+
def create(args={})
|
63
|
+
get_results(:create, [args]) unless args.empty?
|
64
|
+
end
|
65
|
+
|
66
|
+
def update(record_id, args={})
|
67
|
+
get_results(:edit, [record_id, args]) unless args.empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def delete(record_id)
|
71
|
+
get_results(:delete, record_id)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
# Triggers actual fm action.
|
77
|
+
def to_a
|
78
|
+
(data.nil? || data.empty?) ? call.data.to_a : data.to_a
|
79
|
+
end
|
80
|
+
|
81
|
+
# Triggers actual fm action.
|
82
|
+
def each
|
83
|
+
# passes block - if any - to upstream each.
|
84
|
+
to_a.each(&Proc.new)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Combines all queries, sends to FM, returns result in new dataset.
|
88
|
+
def call
|
89
|
+
compiled_query = compile_query
|
90
|
+
wrap_data(compiled_query ? layout.find(*compiled_query) : layout.all(DEFAULT_REQUEST_OPTIONS))
|
91
|
+
end
|
92
|
+
|
93
|
+
# Mixes chained queries together into single query.
|
94
|
+
# Now works with multiple-request queries (using new rfm scope feature).
|
95
|
+
# Other ways: consider mixing multi-request queries with intersection: (result1 & result2),
|
96
|
+
# or with the new scope feature: query1(scope:query2(scope:query3))
|
97
|
+
def compile_query
|
98
|
+
#puts "DATASET COMPILE self #{self}"
|
99
|
+
#puts "DATASET COMPILE queries #{queries}"
|
100
|
+
|
101
|
+
# Old way: works but doesn't handle fmp compound queries.
|
102
|
+
#query.each_with_object([{},{}]){|x,o| o[0].merge!(x[0] || {}); o[1].merge!(x[1] || {})}
|
103
|
+
|
104
|
+
# New way: handles compound queries. Reqires ginjo-rfm 3.0.11.
|
105
|
+
return unless queries # This should help introspecting dataset that results from record deletion. TODO: test this.
|
106
|
+
queries.inject {|new_query,scope| apply_scope(new_query, scope)} ##puts "SCOPE INJECTION scope:#{scope} new_query:#{new_query}";
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns new dataset containing, data, layout, query.
|
110
|
+
def wrap_data(_data=data, _queries=queries, _layout=layout)
|
111
|
+
self.class.new(_layout, _data, _queries)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Send method & query to layout, and wrap results in new dataset.
|
115
|
+
def get_results(_method, query=queries, _layout=layout)
|
116
|
+
wrap_data(_layout.send(_method, *query), query, _layout)
|
117
|
+
end
|
118
|
+
|
119
|
+
end # Dataset
|
120
|
+
end # FMP
|
121
|
+
end # ROM
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rom'
|
2
|
+
require 'rfm'
|
3
|
+
|
4
|
+
module ROM
|
5
|
+
module FMP
|
6
|
+
|
7
|
+
class Gateway < ROM::Gateway
|
8
|
+
attr_reader :datasets, :database
|
9
|
+
|
10
|
+
def initialize(*options)
|
11
|
+
@database = Rfm.database(options[0].to_h.merge(FMRESULTSET_TEMPLATE).to_h)
|
12
|
+
@datasets = Hash.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def dataset(name)
|
16
|
+
datasets[name.to_s] ||= Dataset.new(@database[name.to_s])
|
17
|
+
end
|
18
|
+
|
19
|
+
# This is required per lint specs
|
20
|
+
alias_method :[], :dataset
|
21
|
+
|
22
|
+
def dataset?(name)
|
23
|
+
datasets.key?(name.to_s)
|
24
|
+
end
|
25
|
+
end # Gateway
|
26
|
+
|
27
|
+
end # FMP
|
28
|
+
end # ROM
|