rom-fmp 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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