filemaker 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1a0fc57ed0ca37fe2baa601b0e3de5c4f269a087
4
- data.tar.gz: 4dcbee5913ba864cbdbb45744e678d7a22de9730
3
+ metadata.gz: 87dee5e465c260a70cc59492b12fb5a8a9f74dce
4
+ data.tar.gz: dec6305d44d0eac91f95ba7f5def8ddb8a179292
5
5
  SHA512:
6
- metadata.gz: 08a4d7aaccb0fa6e22091422e7df6c7499ba3072cc815750944791aab70a28de3ac680eab3f3a0fa99b865305955055969602110ff1106aea9c55a535dc7fc20
7
- data.tar.gz: ff5323e65f4a4184dc8bd46909081c2f07cfe75112f2447097452140f9aa317b0cff72f62ad3c6bcdd6e86598fe9e3918049b562d8f71bf026f8fff9f6378d87
6
+ metadata.gz: 182382127660a2e3d081d4b12e80defbeca9db11042a29d4cb626f99ce8bebf016d3b89d16ec1392d4375035d77b5a2ca5450d2c623e6fb7bf3ab4f8b06a5cef
7
+ data.tar.gz: 3fbc5b636c7fda5f4d8f72b29305844d7777969adeea0b446cd72c6cbfcad98fb404b70e4029ebeb74a1fcd22f2bd1ae4be1a5cde69be9593f82b9a76bd3113e
data/.rubocop.yml CHANGED
@@ -3,6 +3,7 @@ AllCops:
3
3
  - .bundle/**
4
4
  - filemaker.gemspec
5
5
  - lib/filemaker/errors.rb
6
+ - lib/generators/filemaker/model/templates/model.rb
6
7
 
7
8
  Documentation:
8
9
  Enabled: false
@@ -14,4 +15,10 @@ MethodLength:
14
15
  Enabled: false
15
16
 
16
17
  LineLength:
17
- Max: 80
18
+ Max: 80
19
+
20
+ SpecialGlobalVars:
21
+ Enabled: false
22
+
23
+ PredicateName:
24
+ Enabled: false
@@ -0,0 +1,28 @@
1
+ module Filemaker
2
+ module Elasticsearch
3
+ module FilemakerAdapter
4
+ module Records
5
+ def records
6
+ criteria = klass.in(klass.identity.name => ids)
7
+
8
+ criteria.instance_exec(response.response['hits']['hits']) do |hits|
9
+ define_singleton_method :to_a do
10
+ self.entries.sort_by do |e|
11
+ hits.index { |hit| hit['_id'].to_s == e.id.to_s }
12
+ end
13
+ end
14
+ end
15
+
16
+ criteria
17
+ end
18
+ end
19
+
20
+ module Callbacks
21
+ # noop
22
+ end
23
+
24
+ module Importing
25
+ end
26
+ end
27
+ end
28
+ end
@@ -80,7 +80,7 @@ module Filemaker
80
80
  end
81
81
 
82
82
  def self.error_message_by_code(code)
83
- "FileMaker Error: #{code} (#{DESCRIPTION.fetch(code.to_s) { '??' }})"
83
+ "#{code} (#{DESCRIPTION.fetch(code.to_s) { '??' }})"
84
84
  end
85
85
 
86
86
  def self.find_error_class_by_code(code)
@@ -49,7 +49,7 @@ module Filemaker
49
49
  rescue
50
50
  # We could be getting back these date:
51
51
  # '17.12.95', '19/05/99', '27/11 /1981'
52
- # '1959-07-03' will be beyong us, so consider returning nil
52
+ # '1959-07-03' will be beyond us, so consider returning exact value
53
53
  value = value.gsub(/-|\./, '/')
54
54
  split = value.split('/').map(&:strip)
55
55
  split[2] = "19#{split[2]}" if split[2].size == 2
@@ -21,7 +21,8 @@ module Filemaker
21
21
  field = klass.find_field_by_name(fm_field_name)
22
22
  next unless field
23
23
 
24
- object.public_send("#{field.name}=", record[fm_field_name])
24
+ # Because we are using ActiveModel::Dirty, so we hydrate directly.
25
+ object.attributes[field.name] = field.coerce(record[fm_field_name])
25
26
  end
26
27
 
27
28
  models << object
@@ -14,6 +14,7 @@ module Filemaker
14
14
  end
15
15
 
16
16
  include ActiveModel::Model
17
+ include ActiveModel::Dirty
17
18
  include ActiveModel::Serializers::JSON
18
19
  include ActiveModel::Serializers::Xml
19
20
  include ActiveModel::Validations::Callbacks
@@ -13,9 +13,13 @@ module Filemaker
13
13
  @fm_name = (options.fetch(:fm_name) { name }).to_s.downcase
14
14
  end
15
15
 
16
- # From FileMaker to Ruby
16
+ # From FileMaker to Ruby.
17
+ #
18
+ # If the value is `==` (match empty) or `=*` (match record), then we will
19
+ # skip coercion.
17
20
  def coerce(value)
18
21
  return nil if value.nil?
22
+ return value if value == '==' || value == '=*'
19
23
 
20
24
  if @type == String
21
25
  value.to_s
@@ -32,6 +36,9 @@ module Filemaker
32
36
  else
33
37
  value
34
38
  end
39
+ rescue
40
+ warn "Could not coerce #{name}: #{value}"
41
+ value
35
42
  end
36
43
  end
37
44
  end
@@ -2,16 +2,29 @@ require 'filemaker/model/field'
2
2
 
3
3
  module Filemaker
4
4
  module Model
5
+ # `Fields` help to give `Model` their perceived schema. To find out your
6
+ # fields, use `Model.fm_fields` or use Rails generator like:
7
+ #
8
+ # rails generate filemaker:model filename database layout
9
+ #
10
+ # @example
11
+ # class Model
12
+ # include Filemaker::Model
13
+ #
14
+ # string :id, identity: true
15
+ # string :title, fm_name: 'A_Title', default: 'Untitled'
16
+ # money :salary
17
+ # end
5
18
  module Fields
6
19
  extend ActiveSupport::Concern
7
20
 
8
21
  TYPE_MAPPINGS = {
9
- string: String,
10
- date: Date,
22
+ string: String,
23
+ date: Date,
11
24
  datetime: DateTime,
12
- money: BigDecimal,
13
- integer: Integer,
14
- number: BigDecimal
25
+ money: BigDecimal,
26
+ number: BigDecimal,
27
+ integer: Integer
15
28
  }
16
29
 
17
30
  included do
@@ -19,6 +32,8 @@ module Filemaker
19
32
  self.fields = {}
20
33
  end
21
34
 
35
+ # Apply default value when you instantiate a new model.
36
+ # @See Model.new
22
37
  def apply_defaults
23
38
  attribute_names.each do |name|
24
39
  field = fields[name]
@@ -53,15 +68,27 @@ module Filemaker
53
68
  end
54
69
 
55
70
  def add_field(name, type, options)
71
+ name = name.to_s
56
72
  fields[name] = Filemaker::Model::Field.new(name, type, options)
57
73
  self.identity = fields[name] if options[:identity]
58
74
  end
59
75
 
60
76
  def create_accessors(name)
77
+ name = name.to_s # Normalize it so ActiveModel::Serialization can work
78
+
79
+ define_attribute_methods name
80
+
81
+ # Reader
61
82
  define_method(name) { attributes[name] }
83
+
84
+ # Writer - We try to map to the correct type, if not we just return
85
+ # original.
62
86
  define_method("#{name}=") do |value|
87
+ public_send("#{name}_will_change!") unless value == attributes[name]
63
88
  attributes[name] = fields[name].coerce(value)
64
89
  end
90
+
91
+ # Predicate
65
92
  define_method("#{name}?") do
66
93
  attributes[name] == true || attributes[name].present?
67
94
  end
@@ -70,8 +97,9 @@ module Filemaker
70
97
  # Find FileMaker's real name given either the attribute name or the real
71
98
  # FileMaker name.
72
99
  def find_field_by_name(name)
100
+ name = name.to_s
73
101
  fields.values.find do |f|
74
- f.name == name.to_sym || f.fm_name == name.to_s
102
+ f.name == name || f.fm_name == name
75
103
  end
76
104
  end
77
105
  end
@@ -35,12 +35,14 @@ module Filemaker
35
35
 
36
36
  def update
37
37
  return false unless valid?
38
+ return true if dirty_attributes.empty?
38
39
 
39
40
  run_callbacks :update do
40
41
  # Will raise `RecordModificationIdMismatchError` if does not match
41
42
  options = { modid: mod_id } # Always pass in?
42
43
  yield options if block_given?
43
- resultset = api.edit(record_id, fm_attributes, options)
44
+ resultset = api.edit(record_id, dirty_attributes, options)
45
+ changes_applied
44
46
  replace_new_data(resultset)
45
47
  end
46
48
  self
@@ -70,11 +72,21 @@ module Filemaker
70
72
  # `fm_attributes`
71
73
  def assign_attributes(new_attributes)
72
74
  return if new_attributes.blank?
75
+
73
76
  new_attributes.each_pair do |key, value|
74
- public_send("#{key}=", (value || '')) if respond_to?("#{key}=")
77
+ next unless respond_to?("#{key}=")
78
+
79
+ public_send("#{key}=", (value || ''))
75
80
  end
76
81
  end
77
82
 
83
+ def reload!
84
+ reset_changes
85
+ resultset = api.find(record_id)
86
+ replace_new_data(resultset)
87
+ self
88
+ end
89
+
78
90
  private
79
91
 
80
92
  # If you have calculated field from FileMaker, it will be replaced.
@@ -90,7 +102,8 @@ module Filemaker
90
102
  field = self.class.find_field_by_name(fm_field_name)
91
103
  next unless field
92
104
 
93
- public_send("#{field.name}=", record[fm_field_name])
105
+ # Because we are using ActiveModel::Dirty, so we hydrate directly.
106
+ attributes[field.name] = field.coerce(record[fm_field_name])
94
107
  end
95
108
  end
96
109
  end
@@ -49,6 +49,14 @@ module Filemaker
49
49
  self.class.with_model_fields(attributes)
50
50
  end
51
51
 
52
+ def dirty_attributes
53
+ dirty = {}
54
+ changed.each do |attr_name|
55
+ dirty[attr_name] = attributes[attr_name]
56
+ end
57
+ self.class.with_model_fields(dirty)
58
+ end
59
+
52
60
  private
53
61
 
54
62
  def process_attributes(attrs)
@@ -9,7 +9,7 @@ module Rails
9
9
  if config_file.file?
10
10
  ::Filemaker.load!(config_file, Rails.env)
11
11
  else
12
- fail ::Filemaker::Errors::ConfigurationError, 'No config file provided'
12
+ fail ::Filemaker::Errors::ConfigurationError, 'No config file'
13
13
  end
14
14
  end
15
15
  end
@@ -1,3 +1,3 @@
1
1
  module Filemaker
2
- VERSION = '0.0.8'
2
+ VERSION = '0.0.9'
3
3
  end
data/lib/filemaker.rb CHANGED
@@ -58,3 +58,15 @@ module Filemaker
58
58
  end
59
59
 
60
60
  require 'filemaker/railtie' if defined?(Rails)
61
+
62
+ if defined?(Elasticsearch::Model)
63
+ require 'filemaker/elasticsearch/filemaker_adapter'
64
+
65
+ Elasticsearch::Model::Adapter.register(
66
+ ::Filemaker::Elasticsearch::FilemakerAdapter,
67
+ lambda do |klass|
68
+ !!defined?(::Filemaker::Model) && \
69
+ klass.ancestors.include?(::Filemaker::Model)
70
+ end
71
+ )
72
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails/generators'
2
+
3
+ module Filemaker
4
+ module Generators
5
+ class ModelGenerator < ::Rails::Generators::NamedBase
6
+ desc 'Create FileMaker model.'
7
+ argument :db, type: :string, required: true
8
+ argument :lay, type: :string, required: true
9
+ argument :registry, type: :string, required: false
10
+
11
+ def self.source_root
12
+ @source_root ||= File.expand_path(
13
+ File.join(File.dirname(__FILE__), 'templates')
14
+ )
15
+ end
16
+
17
+ def create_model_file
18
+ server = Filemaker.registry[registry || 'default']
19
+ api = server.db[db][lay]
20
+ @fields = api.view.fields.values.map do |field|
21
+ [field.name, field.data_type]
22
+ end
23
+
24
+ @type_mappings = {
25
+ 'text' => 'string',
26
+ 'number' => 'number',
27
+ 'date' => 'date',
28
+ 'time' => 'datetime',
29
+ 'timestamp' => 'datetime'
30
+ }
31
+
32
+ template(
33
+ 'model.rb',
34
+ File.join('app/models', class_path, "#{file_name}.rb")
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %>
3
+ include Filemaker::Model
4
+
5
+ database '<%= db %>'
6
+ layout '<%= lay %>'
7
+
8
+ <% @fields.map do |name, type| -%>
9
+ <%= @type_mappings[type] %> :<%= name.parameterize.underscore %>, fm_name: '<%= name %>'
10
+ <% end -%>
11
+ end
12
+ <% end %>
@@ -11,7 +11,7 @@ describe Filemaker::Layout do
11
11
 
12
12
  before do
13
13
  @server = Filemaker::Server.new do |config|
14
- config.host = 'host'
14
+ config.host = 'example'
15
15
  config.account_name = 'account_name'
16
16
  config.password = 'password'
17
17
  end
@@ -53,7 +53,7 @@ describe Filemaker::Model::Relations do
53
53
 
54
54
  context 'when using default reference_key' do
55
55
  it 'will use owner identity name' do
56
- expect(@model.posts.reference_key).to eq :candidate_id
56
+ expect(@model.posts.reference_key).to eq 'candidate_id'
57
57
  end
58
58
 
59
59
  it 'target class should be Post' do
@@ -12,10 +12,10 @@ describe Filemaker::Model do
12
12
  it 'sets up server and api' do
13
13
  expect(MyModel.api.default_params).to eq \
14
14
  ({ '-db' => :candidates, '-lay' => :profile })
15
- expect(MyModel.server.host).to eq 'host'
15
+ expect(MyModel.server.host).to eq 'example'
16
16
  expect(model.api.default_params).to eq \
17
17
  ({ '-db' => :candidates, '-lay' => :profile })
18
- expect(model.server.host).to eq 'host'
18
+ expect(model.server.host).to eq 'example'
19
19
  end
20
20
 
21
21
  it 'is a new record' do
@@ -78,4 +78,17 @@ describe Filemaker::Model do
78
78
  end
79
79
  end
80
80
 
81
+ context 'dirty attributes' do
82
+ it 'does not track changes for new model' do
83
+ expect(model.changed?).to be false
84
+ end
85
+
86
+ it 'tracks changes' do
87
+ model.name = 'Bob'
88
+ expect(model.changed?).to be true
89
+ expect(model.changed).to eq ['name']
90
+ expect(model.dirty_attributes).to eq({'name' => 'Bob'})
91
+ end
92
+ end
93
+
81
94
  end
@@ -3,13 +3,13 @@ describe Filemaker::Server do
3
3
  context 'initializing a server' do
4
4
  it 'provides a host, account_name, and password' do
5
5
  server = Filemaker::Server.new do |config|
6
- config.host = 'host'
6
+ config.host = 'example'
7
7
  config.account_name = 'account_name'
8
8
  config.password = 'password'
9
9
  end
10
10
 
11
- expect(server.host).to eq 'host'
12
- expect(server.url).to eq 'http://host'
11
+ expect(server.host).to eq 'example'
12
+ expect(server.url).to eq 'http://example'
13
13
  expect(server.account_name).to eq 'account_name'
14
14
  expect(server.password).to eq 'password'
15
15
  expect(server.connection).to be_a Faraday::Connection
@@ -21,13 +21,13 @@ describe Filemaker::Server do
21
21
 
22
22
  it 'specifically ask for no SSL' do
23
23
  server = Filemaker::Server.new do |config|
24
- config.host = 'host'
24
+ config.host = 'example'
25
25
  config.account_name = 'account_name'
26
26
  config.password = 'password'
27
27
  config.ssl = false
28
28
  end
29
29
 
30
- expect(server.url).to eq 'http://host'
30
+ expect(server.url).to eq 'http://example'
31
31
  end
32
32
 
33
33
  it 'did not provide host, account_name, and password' do
@@ -36,7 +36,7 @@ describe Filemaker::Server do
36
36
  end.to raise_error ArgumentError
37
37
 
38
38
  expect do
39
- Filemaker::Server.new { |config| config.host = 'host' }
39
+ Filemaker::Server.new { |config| config.host = 'example' }
40
40
  end.to raise_error ArgumentError
41
41
  end
42
42
  end
@@ -44,13 +44,13 @@ describe Filemaker::Server do
44
44
  context 'initializing a server with SSL' do
45
45
  it 'indicates secured connection' do
46
46
  server = Filemaker::Server.new do |config|
47
- config.host = 'host'
47
+ config.host = 'example'
48
48
  config.account_name = 'account_name'
49
49
  config.password = 'password'
50
50
  config.ssl = { verify: false }
51
51
  end
52
52
 
53
- expect(server.url).to eq 'https://host'
53
+ expect(server.url).to eq 'https://example'
54
54
  expect(server.connection.ssl[:verify]).to be false
55
55
  end
56
56
  end
@@ -58,7 +58,7 @@ describe Filemaker::Server do
58
58
  describe 'databases is a store to track encountered -db' do
59
59
  it 'stores database object and can be accessed with db and database' do
60
60
  server = Filemaker::Server.new do |config|
61
- config.host = 'host'
61
+ config.host = 'example'
62
62
  config.account_name = 'account_name'
63
63
  config.password = 'password'
64
64
  end
@@ -72,7 +72,7 @@ describe Filemaker::Server do
72
72
  context 'HTTP errors' do
73
73
  before do
74
74
  @server = Filemaker::Server.new do |config|
75
- config.host = 'host'
75
+ config.host = 'example'
76
76
  config.account_name = 'account_name'
77
77
  config.password = 'password'
78
78
  end
@@ -16,7 +16,7 @@ describe Filemaker::Store::DatabaseStore do
16
16
  describe 'all' do
17
17
  it 'returns all databases' do
18
18
  server = Filemaker::Server.new do |config|
19
- config.host = 'host'
19
+ config.host = 'example'
20
20
  config.account_name = 'account_name'
21
21
  config.password = 'password'
22
22
  end
@@ -16,7 +16,7 @@ describe Filemaker::Store::LayoutStore do
16
16
  describe 'all' do
17
17
  it 'returns all layouts for a database' do
18
18
  server = Filemaker::Server.new do |config|
19
- config.host = 'host'
19
+ config.host = 'example'
20
20
  config.account_name = 'account_name'
21
21
  config.password = 'password'
22
22
  end
@@ -16,7 +16,7 @@ describe Filemaker::Store::ScriptStore do
16
16
  describe 'all' do
17
17
  it 'returns all scripts for a database' do
18
18
  server = Filemaker::Server.new do |config|
19
- config.host = 'host'
19
+ config.host = 'example'
20
20
  config.account_name = 'account_name'
21
21
  config.password = 'password'
22
22
  end
@@ -1,5 +1,5 @@
1
1
  Filemaker.registry['default'] = Filemaker::Server.new do |config|
2
- config.host = 'host'
2
+ config.host = 'example'
3
3
  config.account_name = 'account_name'
4
4
  config.password = 'password'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: filemaker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - mech
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-17 00:00:00.000000000 Z
11
+ date: 2014-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -167,6 +167,7 @@ files:
167
167
  - lib/filemaker/configuration.rb
168
168
  - lib/filemaker/core_ext/hash.rb
169
169
  - lib/filemaker/database.rb
170
+ - lib/filemaker/elasticsearch/filemaker_adapter.rb
170
171
  - lib/filemaker/errors.rb
171
172
  - lib/filemaker/layout.rb
172
173
  - lib/filemaker/metadata/field.rb
@@ -195,6 +196,8 @@ files:
195
196
  - lib/filemaker/store/layout_store.rb
196
197
  - lib/filemaker/store/script_store.rb
197
198
  - lib/filemaker/version.rb
199
+ - lib/generators/filemaker/model/model_generator.rb
200
+ - lib/generators/filemaker/model/templates/model.rb
198
201
  - spec/filemaker/api/query_commands/compound_find_spec.rb
199
202
  - spec/filemaker/configuration_spec.rb
200
203
  - spec/filemaker/error_spec.rb