filemaker 0.0.8 → 0.0.9

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 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