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.
@@ -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
@@ -0,0 +1,18 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /vendor
16
+ .ruby-version
17
+ example*.rb
18
+ local_testing
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
@@ -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
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rom-fmp.gemspec
4
+ gemspec
@@ -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.
@@ -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
+
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rom/fmp/version"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ desc "get version"
10
+ task :version do
11
+ puts ROM::FMP::VERSION
12
+ end
@@ -0,0 +1 @@
1
+ require 'rom/fmp'
@@ -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