dm-filemaker-adapter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +56 -0
- data/Rakefile +15 -0
- data/dm-filemaker-adapter.gemspec +27 -0
- data/lib/dm-filemaker-adapter/adapter.rb +320 -0
- data/lib/dm-filemaker-adapter/dm-fmresultset.yml +86 -0
- data/lib/dm-filemaker-adapter/version.rb +5 -0
- data/lib/dm-filemaker-adapter.rb +7 -0
- data/spec/dm-filemaker-adapter/adapter_spec.rb +11 -0
- data/spec/spec_helper.rb +2 -0
- metadata +129 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
OTEzN2JmZDA1YjA0Yzg0ZjcxMjllNDkxZDQxM2E4NTE0NzhjYzEwZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YmI3MzhmYWEyODk0MjYwNzNlOTI0NGNhYTJhMWFiYjU1MjA4YjM4OA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjBiZTQxMmFiOWEzYmMxYWUwNzkxOTcyM2QzNThlMDgyMGJjMDA1OTNmYWNi
|
10
|
+
OGU0MmM2YTI4Yzc0Y2YxMDI2MGVmMDRiZGEwYTUyYzYzMjMwOGFiYzU2ZTAz
|
11
|
+
M2JhNzRmODE0ZjkwZGM4ZDBhZGIxNTM4YzIwYzNhNzEwM2VjZDk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MTRjNDRhYWM3NzkxMjkzNTkwOGQ1N2M0ZmNiYzdkYWU0NGJhMDMyZTc3Njgx
|
14
|
+
MmQzYzNlODE2M2UzMWFlOWQ4Y2M0OTYzOTA4NWI0OGZkNTQ2YTdkZjZlMGE1
|
15
|
+
MDllNzgxMDBhNzMxMzc0ZTNkM2U3MTg2NjQzNmQ4Mzk0N2I5ODM=
|
data/.gitignore
ADDED
data/.rspec
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,56 @@
|
|
1
|
+
# dm-filemaker-adapter
|
2
|
+
|
3
|
+
A Filemaker adapter for DataMapper, allowing DataMapper to use Filemaker Server as a datastore.
|
4
|
+
|
5
|
+
dm-filemaker-adapter uses the ginjo-rfm gem as the backend command and xml parser. Ginjo-rfm is a full featured filemaker-ruby adapter that exposes most of Filemaker's xml interface functionality in ruby. dm-filemaker-adapter doesn't tap into all of rfm's features, but rather, it provides DataMapper the ability to use Filemaker Server as a backend datastore. All of the basic functionality of DataMapper's CRUD interface is supported, including compound queries and OR queries (using Filemaker's -findquery command), query operators like :field.gt=>..., lazy-loading where possible, first & last record, aggregate queries, ranges, field mapping, and more.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'dm-filemaker-adapter'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install dm-filemaker-adapter
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
DB_CONFIG = {
|
24
|
+
adapter: 'filemaker',
|
25
|
+
host: 'my.server.com',
|
26
|
+
account_name: 'my-user-name',
|
27
|
+
password: 'xxxxxxxxxx',
|
28
|
+
database: 'db-name'
|
29
|
+
}
|
30
|
+
|
31
|
+
DataMapper.setup(:default, DB_CONFIG)
|
32
|
+
|
33
|
+
class User
|
34
|
+
include DataMapper::Resource
|
35
|
+
storage_names[:default] = 'user_xml' # This is your filemaker layout for the user table.
|
36
|
+
|
37
|
+
# Property & field names in this list must be lowercase, regardless of what they are in Filemaker.
|
38
|
+
|
39
|
+
property :userid, String, :key=>true, :required=>false
|
40
|
+
property :email, String
|
41
|
+
property :login, String, :field=>'username'
|
42
|
+
property :updated, DateTime, :field=>'updated_at'
|
43
|
+
property :encrypted_password, BCryptPassword
|
44
|
+
end
|
45
|
+
|
46
|
+
DataMapper.finalize
|
47
|
+
|
48
|
+
User.get 'usr1035'
|
49
|
+
User.first :email => 'wbr'
|
50
|
+
User.all :updated.gt => 3.days.ago
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.require
|
3
|
+
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
8
|
+
|
9
|
+
task :default => :spec
|
10
|
+
|
11
|
+
desc "version"
|
12
|
+
task :version do
|
13
|
+
require 'dm-filemaker-adapter/version'
|
14
|
+
p DataMapper::FilemakerAdapter::VERSION
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dm-filemaker-adapter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "dm-filemaker-adapter"
|
8
|
+
spec.version = DataMapper::FilemakerAdapter::VERSION
|
9
|
+
spec.authors = ["William Richardson"]
|
10
|
+
spec.email = ["https://github.com/ginjo/dm-filemaker-adapter"]
|
11
|
+
spec.summary = %q{Filemaker adapter for DataMapper}
|
12
|
+
spec.description = %q{Use Filemaker Server as a datastore for DataMapper ORM}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "data_mapper"
|
22
|
+
spec.add_dependency "ginjo-rfm"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
end
|
@@ -0,0 +1,320 @@
|
|
1
|
+
# Property & field names in dm-filemaker-adapter models must be declared lowercase, regardless of what they are in FMP.
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
[Resource, Model, Adapters]
|
5
|
+
|
6
|
+
# All this to tack on class and instance methods to the model/resource.
|
7
|
+
module Resource
|
8
|
+
class << self
|
9
|
+
alias_method :included_orig, :included
|
10
|
+
def included(klass)
|
11
|
+
included_orig(klass)
|
12
|
+
if klass.repository.adapter.to_s[/filemaker/i]
|
13
|
+
klass.instance_eval do
|
14
|
+
extend repository.adapter.class::ModelMethods
|
15
|
+
include repository.adapter.class::ResourceMethods
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Model
|
23
|
+
#attr_accessor :last_query
|
24
|
+
alias_method :finalize_orig, :finalize
|
25
|
+
def finalize(*args)
|
26
|
+
property :record_id, Integer, :lazy=>false
|
27
|
+
property :mod_id, Integer, :lazy=>false
|
28
|
+
finalize_orig
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
|
34
|
+
module Adapters
|
35
|
+
|
36
|
+
class FilemakerAdapter < AbstractAdapter
|
37
|
+
@fmresultset_template_path = File.expand_path('../dm-fmresultset.yml', __FILE__).to_s
|
38
|
+
class << self; attr_accessor :fmresultset_template_path; end
|
39
|
+
VERSION = DataMapper::FilemakerAdapter::VERSION
|
40
|
+
|
41
|
+
|
42
|
+
### UTILITY METHODS ###
|
43
|
+
|
44
|
+
# Class methods extended onto model.
|
45
|
+
module ModelMethods
|
46
|
+
def layout
|
47
|
+
Rfm.layout(storage_name, repository.adapter.options.symbolize_keys)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Instance methods included in model.
|
52
|
+
module ResourceMethods
|
53
|
+
def layout
|
54
|
+
model.layout
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
### ADAPTER CORE METHODS ###
|
61
|
+
|
62
|
+
# Persists one or many new resources
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# adapter.create(collection) # => 1
|
66
|
+
#
|
67
|
+
# Adapters provide specific implementation of this method
|
68
|
+
#
|
69
|
+
# @param [Enumerable<Resource>] resources
|
70
|
+
# The list of resources (model instances) to create
|
71
|
+
#
|
72
|
+
# @return [Integer]
|
73
|
+
# The number of records that were actually saved into the data-store
|
74
|
+
#
|
75
|
+
# @api semipublic
|
76
|
+
def create(resources)
|
77
|
+
#resources[0].model.last_query = resources
|
78
|
+
counter = 0
|
79
|
+
resources.each do |resource|
|
80
|
+
fm_params = fmp_attributes resource.dirty_attributes
|
81
|
+
rslt = layout(resource.model).create(fm_params, :template=>self.class.fmresultset_template_path)
|
82
|
+
merge_fmp_response(resource, rslt[0])
|
83
|
+
counter +=1
|
84
|
+
end
|
85
|
+
counter
|
86
|
+
end
|
87
|
+
|
88
|
+
# Reads one or many resources from a datastore
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# adapter.read(query) # => [ { 'name' => 'Dan Kubb' } ]
|
92
|
+
#
|
93
|
+
# Adapters provide specific implementation of this method
|
94
|
+
#
|
95
|
+
# @param [Query] query
|
96
|
+
# the query to match resources in the datastore
|
97
|
+
#
|
98
|
+
# @return [Enumerable<Hash>]
|
99
|
+
# an array of hashes to become resources
|
100
|
+
#
|
101
|
+
# @api semipublic
|
102
|
+
# def read(query)
|
103
|
+
# raise NotImplementedError, "#{self.class}#read not implemented"
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
def read(query)
|
107
|
+
#query.model.last_query = query
|
108
|
+
#y query
|
109
|
+
_layout = layout(query.model)
|
110
|
+
opts = fmp_options(query)
|
111
|
+
opts[:template] = self.class.fmresultset_template_path
|
112
|
+
prms = fmp_query(query.conditions) #.to_set.first)
|
113
|
+
rslt = prms.empty? ? _layout.all(opts) : _layout.find(prms, opts)
|
114
|
+
rslt.dup.each_with_index(){|r, i| rslt[i] = r.to_h}
|
115
|
+
rslt
|
116
|
+
end
|
117
|
+
|
118
|
+
# Takes a query and returns number of matched records.
|
119
|
+
# An empty query will return the total record count
|
120
|
+
def aggregate(query)
|
121
|
+
#query.model.last_query = query
|
122
|
+
#y query
|
123
|
+
_layout = layout(query.model)
|
124
|
+
opts = fmp_options(query)
|
125
|
+
opts[:template] = self.class.fmresultset_template_path
|
126
|
+
prms = fmp_query(query.conditions) #.to_set.first)
|
127
|
+
#[prms.empty? ? _layout.all(:max_records=>0).foundset_count : _layout.count(prms)]
|
128
|
+
[prms.empty? ? _layout.view.total_count : _layout.count(prms)]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Updates one or many existing resources
|
132
|
+
#
|
133
|
+
# @example
|
134
|
+
# adapter.update(attributes, collection) # => 1
|
135
|
+
#
|
136
|
+
# Adapters provide specific implementation of this method
|
137
|
+
#
|
138
|
+
# @param [Hash(Property => Object)] attributes
|
139
|
+
# hash of attribute values to set, keyed by Property
|
140
|
+
# @param [Collection] collection
|
141
|
+
# collection of records to be updated
|
142
|
+
#
|
143
|
+
# @return [Integer]
|
144
|
+
# the number of records updated
|
145
|
+
#
|
146
|
+
# @api semipublic
|
147
|
+
def update(attributes, collection)
|
148
|
+
#collection[0].model.last_query = [attributes, collection]
|
149
|
+
fm_params = fmp_attributes(attributes)
|
150
|
+
counter = 0
|
151
|
+
collection.each do |resource|
|
152
|
+
rslt = layout(resource.model).edit(resource.record_id, fm_params, :template=>self.class.fmresultset_template_path)
|
153
|
+
merge_fmp_response(resource, rslt[0])
|
154
|
+
resource.persistence_state = DataMapper::Resource::PersistenceState::Clean.new resource
|
155
|
+
counter +=1
|
156
|
+
end
|
157
|
+
counter
|
158
|
+
end
|
159
|
+
|
160
|
+
# Deletes one or many existing resources
|
161
|
+
#
|
162
|
+
# @example
|
163
|
+
# adapter.delete(collection) # => 1
|
164
|
+
#
|
165
|
+
# Adapters provide specific implementation of this method
|
166
|
+
#
|
167
|
+
# @param [Collection] collection
|
168
|
+
# collection of records to be deleted
|
169
|
+
#
|
170
|
+
# @return [Integer]
|
171
|
+
# the number of records deleted
|
172
|
+
#
|
173
|
+
# @api semipublic
|
174
|
+
def delete(collection)
|
175
|
+
counter = 0
|
176
|
+
collection.each do |resource|
|
177
|
+
rslt = layout(resource.model).delete(resource.record_id, :template=>self.class.fmresultset_template_path)
|
178
|
+
counter +=1
|
179
|
+
end
|
180
|
+
counter
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
|
185
|
+
### ADAPTER HELPER METHODS ###
|
186
|
+
|
187
|
+
# Create fmp layout object from model object.
|
188
|
+
def layout(model)
|
189
|
+
#Rfm.layout(model.storage_name, options.symbolize_keys) #query.repository.adapter.options.symbolize_keys)
|
190
|
+
model.layout
|
191
|
+
end
|
192
|
+
|
193
|
+
# Convert dm query object to fmp query params (hash)
|
194
|
+
def fmp_query(input)
|
195
|
+
#puts "CONDITIONS input #{input.class.name} (#{input})"
|
196
|
+
if input.class.name[/OrOperation/]
|
197
|
+
input.operands.collect {|o| fmp_query o}
|
198
|
+
elsif input.class.name[/AndOperation/]
|
199
|
+
h = Hash.new
|
200
|
+
input.operands.each do |k,v|
|
201
|
+
r = fmp_query(k)
|
202
|
+
#puts "CONDITIONS operand #{r}"
|
203
|
+
if r.is_a?(Hash)
|
204
|
+
h.merge!(r)
|
205
|
+
else
|
206
|
+
h=r
|
207
|
+
break
|
208
|
+
end
|
209
|
+
end
|
210
|
+
h
|
211
|
+
elsif input.class.name[/NullOperation/] || input.nil?
|
212
|
+
{}
|
213
|
+
else
|
214
|
+
#puts "FMP_QUERY OPERATION #{input.class}"
|
215
|
+
val = input.loaded_value
|
216
|
+
|
217
|
+
if val.to_s != ''
|
218
|
+
|
219
|
+
operation = input.class.name
|
220
|
+
operator = case
|
221
|
+
when operation[/EqualTo/]; '='
|
222
|
+
when operation[/GreaterThan/]; '>'
|
223
|
+
when operation[/LessThan/]; '<'
|
224
|
+
when operation[/Like/]; ''
|
225
|
+
when operation[/Null/]; ''
|
226
|
+
else ''
|
227
|
+
end
|
228
|
+
|
229
|
+
val = val._to_fm if val.respond_to? :_to_fm
|
230
|
+
{input.subject.field.to_s => "#{operator}#{val}"}
|
231
|
+
else
|
232
|
+
{}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
# Convert dm attributes hash to regular hash
|
239
|
+
# TODO: Should the result be string or symbol keys?
|
240
|
+
def fmp_attributes(attributes)
|
241
|
+
#puts "ATTRIBUTES"
|
242
|
+
y attributes
|
243
|
+
fm_params = Hash.new
|
244
|
+
attributes.to_h.each do |k,v|
|
245
|
+
fm_params[k.field] = v.respond_to?(:_to_fm) ? v._to_fm : v
|
246
|
+
end
|
247
|
+
# fm_params = Hash.new
|
248
|
+
# resource.dirty_attributes.each do |a,v|
|
249
|
+
# fm_params[a.field] = v.respond_to?(:_to_fm) ? v._to_fm : v
|
250
|
+
# end
|
251
|
+
fm_params
|
252
|
+
end
|
253
|
+
|
254
|
+
# Get fmp options hash from query
|
255
|
+
def fmp_options(query)
|
256
|
+
fm_options = {}
|
257
|
+
fm_options[:skip_records] = query.offset if query.offset
|
258
|
+
fm_options[:max_records] = query.limit if query.limit
|
259
|
+
if query.order
|
260
|
+
fm_options[:sort_field] = query.order.collect do |ord|
|
261
|
+
ord.target.field
|
262
|
+
end
|
263
|
+
fm_options[:sort_order] = query.order.collect do |ord|
|
264
|
+
ord.operator.to_s + 'end'
|
265
|
+
end
|
266
|
+
end
|
267
|
+
fm_options
|
268
|
+
end
|
269
|
+
|
270
|
+
def merge_fmp_response(resource, record)
|
271
|
+
resource.model.properties.to_a.each do |property|
|
272
|
+
if record.key?(property.field.to_s)
|
273
|
+
resource[property.name] = record[property.field.to_s]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# # This is supposed to convert property objects to field name. Not sure if it works.
|
279
|
+
# def get_field_name(field)
|
280
|
+
# return field.field if field.respond_to? :field
|
281
|
+
# field
|
282
|
+
# end
|
283
|
+
|
284
|
+
|
285
|
+
protected :fmp_query, :fmp_attributes, :fmp_options, :merge_fmp_response
|
286
|
+
|
287
|
+
end # FilemakerAdapter
|
288
|
+
end # Adapters
|
289
|
+
end # DataMapper
|
290
|
+
|
291
|
+
class Time
|
292
|
+
def _to_fm
|
293
|
+
d = strftime('%m/%d/%Y') unless Date.today == Date.parse(self.to_s)
|
294
|
+
t = strftime('%T')
|
295
|
+
d ? "#{d} #{t}" : t
|
296
|
+
end
|
297
|
+
end # Time
|
298
|
+
|
299
|
+
class DateTime
|
300
|
+
def _to_fm
|
301
|
+
d = strftime('%m/%d/%Y')
|
302
|
+
t =strftime('%T')
|
303
|
+
"#{d} #{t}"
|
304
|
+
end
|
305
|
+
end # Time
|
306
|
+
|
307
|
+
class Timestamp
|
308
|
+
def _to_fm
|
309
|
+
d = strftime('%m/%d/%Y')
|
310
|
+
t =strftime('%T')
|
311
|
+
"#{d} #{t}"
|
312
|
+
end
|
313
|
+
end # Time
|
314
|
+
|
315
|
+
class Date
|
316
|
+
def _to_fm
|
317
|
+
strftime('%m/%d/%Y')
|
318
|
+
end
|
319
|
+
end # Time
|
320
|
+
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# YAML structure defining a SAX parsing scheme for fmresultset xml.
|
3
|
+
# The initial object of this parse should be a new instance of Rfm::Resultset.
|
4
|
+
---
|
5
|
+
attach_elements: _meta
|
6
|
+
attach_attributes: _meta
|
7
|
+
create_accessors: all
|
8
|
+
elements:
|
9
|
+
- name: doctype
|
10
|
+
attach: none
|
11
|
+
attributes:
|
12
|
+
- name: value
|
13
|
+
as_name: doctype
|
14
|
+
- name: fmresultset
|
15
|
+
attach: none
|
16
|
+
- name: product
|
17
|
+
- name: error
|
18
|
+
attach: none
|
19
|
+
before_close: :check_for_errors
|
20
|
+
attributes:
|
21
|
+
- name: code
|
22
|
+
as_name: error
|
23
|
+
- name: datasource
|
24
|
+
attach: none
|
25
|
+
before_close: [object, end_datasource_element_callback, self]
|
26
|
+
attributes:
|
27
|
+
- name: total_count
|
28
|
+
accessor: none
|
29
|
+
- name: metadata
|
30
|
+
attach: none
|
31
|
+
- name: field_definition
|
32
|
+
# These two steps can be used to create the attachment to resultset-meta automatically,
|
33
|
+
# but the field-mapping translation won't happen.
|
34
|
+
# attach: [_meta, 'Rfm::Metadata::Field', allocate]
|
35
|
+
# as_name: field_meta
|
36
|
+
attach: [cursor, 'Rfm::Metadata::Field', ':allocate']
|
37
|
+
delimiter: name
|
38
|
+
attach_attributes: private
|
39
|
+
before_close: [object, field_definition_element_close_callback, self]
|
40
|
+
- name: relatedset_definition
|
41
|
+
delimiter: table
|
42
|
+
as_name: portal_meta
|
43
|
+
attach_attributes: private
|
44
|
+
elements:
|
45
|
+
- name: field_definition
|
46
|
+
attach: [cursor, 'Rfm::Metadata::Field', ':allocate']
|
47
|
+
delimiter: name
|
48
|
+
as_name: field_meta
|
49
|
+
attach_attributes: private
|
50
|
+
before_close: [object, relatedset_field_definition_element_close_callback, self]
|
51
|
+
- name: resultset
|
52
|
+
attach: none
|
53
|
+
attributes:
|
54
|
+
- name: count
|
55
|
+
accessor: none
|
56
|
+
- name: fetch_size
|
57
|
+
accessor: none
|
58
|
+
- name: record
|
59
|
+
#attach: [cursor, object, handle_new_record, _attributes]
|
60
|
+
#attach_attributes: none
|
61
|
+
attach: [array, 'Rfm::Record', new, object]
|
62
|
+
attach_attributes: hash
|
63
|
+
before_close: '@loaded=true'
|
64
|
+
elements:
|
65
|
+
- name: field
|
66
|
+
attach: [cursor, 'Rfm::Metadata::Datum', ':allocate']
|
67
|
+
compact: false
|
68
|
+
before_close: [object, field_element_close_callback, self]
|
69
|
+
- name: relatedset
|
70
|
+
attach: [private, Array, ':allocate']
|
71
|
+
as_name: portals
|
72
|
+
attach_attributes: private
|
73
|
+
create_accessors: all
|
74
|
+
delimiter: table
|
75
|
+
elements:
|
76
|
+
- name: record
|
77
|
+
#class: Rfm::Record
|
78
|
+
attach: [default, 'Rfm::Record', ':allocate']
|
79
|
+
attach_attributes: hash
|
80
|
+
before_close: '@loaded=true'
|
81
|
+
elements:
|
82
|
+
- name: field
|
83
|
+
compact: true
|
84
|
+
attach: [cursor, 'Rfm::Metadata::Datum', ':allocate']
|
85
|
+
before_close: [object, portal_field_element_close_callback, self]
|
86
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DataMapper::Adapters::FilemakerAdapter do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(DataMapper::Adapters::FilemakerAdapter::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'does something useful' do
|
9
|
+
expect(true).to eq(true)
|
10
|
+
end
|
11
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dm-filemaker-adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- William Richardson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: data_mapper
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ginjo-rfm
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Use Filemaker Server as a datastore for DataMapper ORM
|
84
|
+
email:
|
85
|
+
- https://github.com/ginjo/dm-filemaker-adapter
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- .gitignore
|
91
|
+
- .rspec
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- dm-filemaker-adapter.gemspec
|
97
|
+
- lib/dm-filemaker-adapter.rb
|
98
|
+
- lib/dm-filemaker-adapter/adapter.rb
|
99
|
+
- lib/dm-filemaker-adapter/dm-fmresultset.yml
|
100
|
+
- lib/dm-filemaker-adapter/version.rb
|
101
|
+
- spec/dm-filemaker-adapter/adapter_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
homepage: ''
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.4.5
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Filemaker adapter for DataMapper
|
127
|
+
test_files:
|
128
|
+
- spec/dm-filemaker-adapter/adapter_spec.rb
|
129
|
+
- spec/spec_helper.rb
|