fmrest 0.12.0 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -0
  3. data/CHANGELOG.md +31 -0
  4. data/README.md +252 -851
  5. metadata +71 -108
  6. data/.gitignore +0 -26
  7. data/.rspec +0 -3
  8. data/.travis.yml +0 -5
  9. data/Gemfile +0 -3
  10. data/Rakefile +0 -6
  11. data/UPGRADING +0 -15
  12. data/fmrest.gemspec +0 -49
  13. data/lib/fmrest.rb +0 -36
  14. data/lib/fmrest/connection_settings.rb +0 -124
  15. data/lib/fmrest/errors.rb +0 -30
  16. data/lib/fmrest/spyke.rb +0 -21
  17. data/lib/fmrest/spyke/base.rb +0 -9
  18. data/lib/fmrest/spyke/container_field.rb +0 -59
  19. data/lib/fmrest/spyke/model.rb +0 -33
  20. data/lib/fmrest/spyke/model/associations.rb +0 -86
  21. data/lib/fmrest/spyke/model/attributes.rb +0 -163
  22. data/lib/fmrest/spyke/model/auth.rb +0 -43
  23. data/lib/fmrest/spyke/model/connection.rb +0 -163
  24. data/lib/fmrest/spyke/model/container_fields.rb +0 -40
  25. data/lib/fmrest/spyke/model/global_fields.rb +0 -40
  26. data/lib/fmrest/spyke/model/http.rb +0 -77
  27. data/lib/fmrest/spyke/model/orm.rb +0 -256
  28. data/lib/fmrest/spyke/model/record_id.rb +0 -78
  29. data/lib/fmrest/spyke/model/serialization.rb +0 -99
  30. data/lib/fmrest/spyke/model/uri.rb +0 -29
  31. data/lib/fmrest/spyke/portal.rb +0 -55
  32. data/lib/fmrest/spyke/relation.rb +0 -359
  33. data/lib/fmrest/spyke/spyke_formatter.rb +0 -273
  34. data/lib/fmrest/spyke/validation_error.rb +0 -25
  35. data/lib/fmrest/string_date.rb +0 -220
  36. data/lib/fmrest/token_store.rb +0 -12
  37. data/lib/fmrest/token_store/active_record.rb +0 -74
  38. data/lib/fmrest/token_store/base.rb +0 -25
  39. data/lib/fmrest/token_store/memory.rb +0 -26
  40. data/lib/fmrest/token_store/moneta.rb +0 -41
  41. data/lib/fmrest/token_store/null.rb +0 -20
  42. data/lib/fmrest/token_store/redis.rb +0 -45
  43. data/lib/fmrest/v1.rb +0 -23
  44. data/lib/fmrest/v1/auth.rb +0 -30
  45. data/lib/fmrest/v1/connection.rb +0 -115
  46. data/lib/fmrest/v1/container_fields.rb +0 -114
  47. data/lib/fmrest/v1/dates.rb +0 -81
  48. data/lib/fmrest/v1/paths.rb +0 -47
  49. data/lib/fmrest/v1/raise_errors.rb +0 -57
  50. data/lib/fmrest/v1/token_session.rb +0 -133
  51. data/lib/fmrest/v1/token_store/active_record.rb +0 -13
  52. data/lib/fmrest/v1/token_store/memory.rb +0 -13
  53. data/lib/fmrest/v1/type_coercer.rb +0 -192
  54. data/lib/fmrest/v1/utils.rb +0 -94
  55. data/lib/fmrest/version.rb +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 725c8356fc5933f0484f7d04a4458ecc85c638838c8d9869d039a6e09b0b15f6
4
- data.tar.gz: 2a8047594d93d13b0f6d9981159c16b1afdcaa19713c054391fc08ca1fa68633
3
+ metadata.gz: c0740eb9d2b42cd5fb5b8fad3ed5d3d9b74edd9ec3da0b5aec23c000357d11f8
4
+ data.tar.gz: 612229666f1c67ede1549870d7f1f6abe0c1f3d7773b30161c21033767346f05
5
5
  SHA512:
6
- metadata.gz: 7a41a3e747bf6ccfe0de7e5541b0db35d30d9723b7a0eeb895fbe9e21f4c2c7e6f08ccd3012c1e6f4edaa5403966e2a7563b74490327c721990fbdd4ab79608a
7
- data.tar.gz: 16fb2868c102905a58632b1183581dcf4617d4e6c9f7529abad12916b78b3c692d21a469eaf7b23101d53ff55e8c9ccbfc1167556cc09855516647ce00565ea8
6
+ metadata.gz: d0ea144d5f62269ea55d418d16f95109f42925fa49b3ed9f89b9371ad7b386bf5bd97ad1e04bb7d854a53117e948ea8be4c4fb0052a3fd8fdd7d057ac8d00433
7
+ data.tar.gz: c4ea03c0c8cab5bfe18b8c25889c76edaa0d2269b06f3c6f92d4559c4b4ed2cfac72a9925ef143ad5dae2c68a33b03a9984ba05056e4ebb9d96495abb12653ba
data/.yardopts CHANGED
@@ -1,2 +1,5 @@
1
1
  --markup markdown
2
2
  --plugin activesupport-concern
3
+ lib/**/*.rb
4
+ -
5
+ docs/*
data/CHANGELOG.md CHANGED
@@ -1,9 +1,40 @@
1
1
  ## Changelog
2
2
 
3
+ ### 0.15.1
4
+
5
+ * Fix autoloading of `FmRest::Layout`
6
+
7
+ ### 0.15.0
8
+
9
+ * Much improved querying API (see documentation on querying), adding new
10
+ `.query` capabilities, as well as two new methods: `.match` and `.or`
11
+
12
+ ### 0.14.0
13
+
14
+ * Aliased `FmRest::Spyke::Base` as `FmRest::Layout` (now preferred), and
15
+ provided a shortcut version for setting the layout name (e.g. `class Foo <
16
+ FmRest::Layout("LayoutName")`)
17
+ * Made `layout` class setting subclass-inheritable
18
+
19
+ ### 0.13.1
20
+
21
+ * Fix downloading of container field data from FMS19+
22
+
23
+ ### 0.13.0
24
+
25
+ * Split `fmrest` gem into `fmrest-core` and `fmrest-spyke`. `fmrest` becomes a
26
+ wrapper for the two new gems.
27
+ * Fix bug preventing connection databases with spaces in their names.
28
+ * Improved portal support with ability to delete portal records, and better
29
+ refreshing of portal records after saving the parent.
30
+ * `FmRest::Spyke::Base#__record_id` and `FmRest::Spyke::Base#__mod_id` now
31
+ always return integers if set.
32
+
3
33
  ### 0.12.0
4
34
 
5
35
  * Rename `FmRest::Spyke::Base#id=` to `FmRest::Spyke::Base#__record_id=` to
6
36
  prevent clobbering of FileMaker layout-defined fields
37
+ * Removed previously deprecated `FmRest::Spyke::Base(config)` syntax
7
38
  * Better yard documentation
8
39
 
9
40
  ### 0.11.1
data/README.md CHANGED
@@ -2,122 +2,157 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/fmrest.svg?style=flat)](https://rubygems.org/gems/fmrest)
4
4
  ![CI](https://github.com/beezwax/fmrest-ruby/workflows/CI/badge.svg)
5
+ [![Yard Docs](http://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/beezwax/fmrest-ruby)
5
6
 
6
7
  A Ruby client for
7
8
  [FileMaker 18 and 19's Data API](https://help.claris.com/en/data-api-guide)
8
9
  using
9
10
  [Faraday](https://github.com/lostisland/faraday) and with optional
10
- [Spyke](https://github.com/balvig/spyke) support (ActiveRecord-ish models).
11
+ ActiveRecord-ish ORM features through [Spyke](https://github.com/balvig/spyke).
11
12
 
12
- If you're looking for a Ruby client for the legacy XML/Custom Web Publishing
13
- API try the fabulous [ginjo-rfm gem](https://github.com/ginjo/rfm) instead.
14
-
15
- fmrest-ruby only partially implements FileMaker 18's Data API.
13
+ fmrest-ruby only partially implements FileMaker 19's Data API.
16
14
  See the [implementation completeness table](#api-implementation-completeness-table)
17
15
  to see if a feature you need is natively supported by the gem.
18
16
 
17
+ ## Gems
18
+
19
+ The `fmrest` gem is a wrapper for two other gems:
20
+
21
+ * `fmrest-spyke`, providing an ActiveRecord-like ORM library built on top
22
+ of `fmrest-core` and [Spyke](https://github.com/balvig/spyke).
23
+ * `fmrest-core`, providing the core Faraday connection builder, session
24
+ management, and other core utilities.
25
+
19
26
  ## Installation
20
27
 
21
- Add this line to your Gemfile:
28
+ Add this to your Gemfile:
22
29
 
23
30
  ```ruby
24
31
  gem 'fmrest'
25
-
26
- # Optional but recommended (for ORM features)
27
- gem 'spyke'
28
32
  ```
29
33
 
30
- ## Basic usage (without ORM)
31
-
32
- To get a Faraday connection that can handle FM's Data API auth workflow:
34
+ Or if you just want to use the Faraday connection without the ORM features:
33
35
 
34
36
  ```ruby
35
- connection = FmRest::V1.build_connection(
36
- host: "example.com",
37
- database: "database name",
38
- username: "username",
39
- password: "password"
40
- )
37
+ gem 'fmrest-core'
41
38
  ```
42
39
 
43
- The returned connection will prefix any non-absolute paths with
44
- `"/fmi/data/v1/databases/:database/"`, so you only need to supply the
45
- meaningful part of the path.
40
+ ## Simple examples
41
+
42
+ ### ORM example
46
43
 
47
- To send a request to the Data API use Faraday's standard methods, e.g.:
44
+ Most people would want to use the ORM features:
48
45
 
49
46
  ```ruby
50
- # Get all records
51
- connection.get("layouts/MyFancyLayout/records")
47
+ # A Layout model connecting to the "Honeybees Web" FileMaker layout
48
+ class Honeybee < FmRest::Layout("Honeybees Web")
49
+ # Connection settings
50
+ self.fmrest_config = {
51
+ host: "…",
52
+ database: "…",
53
+ username: "…",
54
+ password: "…"
55
+ }
52
56
 
53
- # Create new record
54
- connection.post do |req|
55
- req.url "layouts/MyFancyLayout/records"
57
+ # Mapped attributes
58
+ attributes name: "Bee Name", age: "Bee Age", created_on: "Created On"
56
59
 
57
- # You can just pass a hash for the JSON body
58
- req.body = { ... }
60
+ # Portal associations
61
+ has_portal :tasks
62
+
63
+ # File containers
64
+ container :photo, field_name: "Bee Photo"
65
+
66
+ # Scopes
67
+ scope :can_legally_fly, -> { query(age: ">18") }
68
+
69
+ # Client-side validations
70
+ validates :name, presence: true
71
+
72
+ # Callbacks
73
+ before_save :set_created_on
74
+
75
+ private
76
+
77
+ def set_created_on
78
+ self.created_on = Date.today
79
+ end
59
80
  end
60
- ```
61
81
 
62
- For each request fmrest-ruby will first request a session token (using the
63
- provided username and password) if it doesn't yet have one in store.
82
+ # Find a record by id
83
+ bee = Honeybee.find(9)
64
84
 
65
- ### Logging out of the database session
85
+ bee.name = "Hutch"
86
+
87
+ # Add a new record to portal
88
+ bee.tasks.build(urgency: "Today")
66
89
 
67
- The Data API requires sending a DELETE request to
68
- `/fmi/data/:version/databases/:database_name/sessions/:session_token`
69
- in order to log out from the session
70
- ([see docs](https://fmhelp.filemaker.com/docs/18/en/dataapi/#connect-database_log-out)).
90
+ bee.save
91
+ ```
71
92
 
72
- Since fmrest-ruby handles the storage of session tokens internally, and the
73
- token is required to build the logout URL, this becomes a non-trivial action.
93
+ ### Barebones connection example (without ORM)
74
94
 
75
- To remedy this, fmrest-ruby connections recognize when you're trying to logout
76
- and substitute whatever is in the `:session_token` section of the logout path
77
- with the actual session token:
95
+ In case you don't need the advanced ORM features (e.g. if you only need minimal
96
+ Data API interaction and just want a lightweight solution) you can simply use
97
+ the Faraday connection provided by `fmrest-core`:
78
98
 
79
99
  ```ruby
80
- # Logout from the database session
81
- connection.delete "sessions/this-will-be-replaced-with-the-actual-token"
100
+ connection = FmRest::V1.build_connection(
101
+ host: "",
102
+ database: "…",
103
+ username: "…",
104
+ password: "…"
105
+ )
106
+
107
+ # Get all records (as parsed JSON)
108
+ connection.get("layouts/FancyLayout/records")
109
+
110
+ # Create new record
111
+ connection.post do |req|
112
+ req.url "layouts/FancyLayout/records"
113
+
114
+ # You can just pass a hash for the JSON body
115
+ req.body = { … }
116
+ end
82
117
  ```
83
118
 
84
- If you're using the ORM features this becomes much easier, see
85
- [Model.logout](#modellogout) below.
119
+ See the [main document on using the base
120
+ connection](docs/BaseConnectionUsage.md) for more.
86
121
 
87
122
  ## Connection settings
88
123
 
89
- In addition to the required `:host`, `:database`, `:username` and `:password`
90
- connection options, you can also pass `:ssl` and `:proxy`, which are passed to
91
- the underlying [Faraday](https://github.com/lostisland/faraday) connection.
124
+ The minimum required connection settings are `:host`, `:database`, `:username`
125
+ and `:password`, but fmrest-ruby has many other options you can pass when
126
+ setting up a connection (see [full list](#full-list-of-available-options) below).
92
127
 
93
- You can use this to, for instance, disable SSL verification:
128
+ `:ssl` and `:proxy` are forwarded to the underlying
129
+ [Faraday](https://github.com/lostisland/faraday) connection. You can use this
130
+ to, for instance, disable SSL verification:
94
131
 
95
132
  ```ruby
96
- FmRest::V1.build_connection(
97
- host: "example.com",
98
- ...
99
- ssl: { verify: false }
100
- )
133
+ {
134
+ host: "",
135
+
136
+ ssl: { verify: false }
137
+ }
101
138
  ```
102
139
 
103
140
  You can also pass a `:log` option for basic request logging, see the section on
104
141
  [Logging](#Logging) below.
105
142
 
106
- `:username` is also aliased as `:account_name` to provide cross-compatibility
107
- with the ginjo-rfm gem.
108
-
109
143
  ### Full list of available options
110
144
 
111
145
  Option | Description | Format | Default
112
146
  --------------------|--------------------------------------------|-----------------------------|--------
113
147
  `:host` | Hostname with optional port, e.g. `"example.com:9000"` | String | None
114
- `:database` | | String | None
115
- `:username` | | String | None
116
- `:password` | | String | None
148
+ `:database` | The name of the database to connect to | String | None
149
+ `:username` | A Data API-ready account | String | None
150
+ `:password` | Your password | String | None
151
+ `:account_name` | Alias of `:username` | String | None
117
152
  `:ssl` | SSL options to be forwarded to Faraday | Faraday SSL options | None
118
153
  `:proxy` | Proxy options to be forwarded to Faraday | Faraday proxy options | None
119
154
  `:log` | Log JSON responses to STDOUT | Boolean | `false`
120
- `:coerce_dates` | See section on [date fields](#date-fields) | Boolean \| `:hybrid` \| `:full` | `false`
155
+ `:coerce_dates` | See section on [date fields](#date-fields-and-timezones) | Boolean \| `:hybrid` \| `:full` | `false`
121
156
  `:date_format` | Date parsing format | String (FM date format) | `"MM/dd/yyyy"`
122
157
  `:timestamp_format` | Timestmap parsing format | String (FM date format) | `"MM/dd/yyyy HH:mm:ss"`
123
158
  `:time_format` | Time parsing format | String (FM date format) | `"HH:mm:ss"`
@@ -132,232 +167,62 @@ through `FmRest.default_connection_settings=`. E.g.:
132
167
 
133
168
  ```ruby
134
169
  FmRest.default_connection_settings = {
135
- host: "example.com",
136
- database: "database name",
137
- username: "username",
138
- password: "password"
170
+ host: "",
171
+ database: "",
172
+ username: "",
173
+ password: ""
139
174
  }
140
175
  ```
141
176
 
142
- This configuration will be used by default by `FmRest::V1.build_connection` as
143
- well as your models whenever you don't pass a configuration hash explicitly.
144
-
177
+ These settings will be used by default by `FmRest::Layout` models whenever you
178
+ don't set `fmrest_config=` explicitly, as well as by
179
+ `FmRest::V1.build_connection` in case you're setting up your Faraday connection
180
+ manually.
145
181
 
146
182
  ## Session token store
147
183
 
148
- By default fmrest-ruby will use a memory-based store for the session tokens.
149
- This is generally good enough for development, but not good enough for
150
- production, as in-memory tokens aren't shared across threads/processes.
151
-
152
- Besides the default token store the following token stores are bundled with fmrest-ruby:
153
-
154
- ### ActiveRecord
155
-
156
- On Rails apps already using ActiveRecord setting up this token store should be
157
- dead simple:
158
-
159
- ```ruby
160
- # config/initializers/fmrest.rb
161
- require "fmrest/token_store/active_record"
162
-
163
- FmRest.token_store = FmRest::TokenStore::ActiveRecord
164
- ```
165
-
166
- No migrations are needed, the token store table will be created automatically
167
- when needed, defaulting to the table name "fmrest_session_tokens". If you want
168
- to change the table name you can do so by initializing the token store and
169
- passing it the `:table_name` option:
170
-
171
- ```ruby
172
- FmRest.token_store = FmRest::TokenStore::ActiveRecord.new(table_name: "my_token_store")
173
- ```
174
-
175
- ### Redis
176
-
177
- To use the Redis token store do:
178
-
179
- ```ruby
180
- require "fmrest/token_store/redis"
181
-
182
- FmRest.token_store = FmRest::TokenStore::Redis
183
- ```
184
-
185
- You can also initialize it with the following options:
186
-
187
- * `:redis` - A `Redis` object to use as connection, if ommited a new `Redis`
188
- object will be created with remaining options
189
- * `:prefix` - The prefix to use for token keys, by default `"fmrest-token:"`
190
- * Any other options will be passed to `Redis.new` if `:redis` isn't provided
191
-
192
- Examples:
193
-
194
- ```ruby
195
- # Passing a Redis connection explicitly
196
- FmRest.token_store = FmRest::TokenStore::Redis.new(redis: Redis.new, prefix: "my-fancy-prefix:")
197
-
198
- # Passing options for Redis.new
199
- FmRest.token_store = FmRest::TokenStore::Redis.new(prefix: "my-fancy-prefix:", host: "10.0.1.1", port: 6380, db: 15)
200
- ```
201
-
202
- NOTE: redis-rb is not included as a gem dependency of fmrest-ruby, so you'll
203
- have to add it to your Gemfile.
204
-
205
- ### Moneta
206
-
207
- [Moneta](https://github.com/moneta-rb/moneta) is a key/value store wrapper
208
- around many different storage backends. If ActiveRecord or Redis don't suit
209
- your needs, chances are Moneta will.
210
-
211
- To use it:
212
-
213
- ```ruby
214
- # config/initializers/fmrest.rb
215
- require "fmrest/token_store/moneta"
216
-
217
- FmRest.token_store = FmRest::TokenStore::Moneta
218
- ```
219
-
220
- By default the `:Memory` moneta backend will be used.
221
-
222
- You can also initialize it with the following options:
223
-
224
- * `:backend` - The moneta backend to initialize the store with
225
- * `:prefix` - The prefix to use for token keys, by default `"fmrest-token:"`
226
- * Any other options will be passed to `Moneta.new`
227
-
228
- Examples:
229
-
230
- ```ruby
231
- # Using YAML as a backend with a custom prefix
232
- FmRest.token_store = FmRest::TokenStore::Moneta.new(
233
- backend: :YAML,
234
- file: "tmp/tokens.yml",
235
- prefix: "my-tokens"
236
- )
237
- ```
238
-
239
- NOTE: the moneta gem is not included as a dependency of fmrest-ruby, so
240
- you'll have to add it to your Gemfile.
241
-
242
-
243
- ## Date fields
244
-
245
- Since the Data API uses JSON (wich doesn't provide a native date/time object),
246
- dates and timestamps are received in string format. By default fmrest-ruby
247
- leaves those string fields untouched, but it provides an opt-in feature to try
248
- to automatically "coerce" them into Ruby date objects.
249
-
250
- The connection option `:coerce_dates` controls this feature. Possible values
251
- are:
252
-
253
- * `:full` - whenever a string matches the given date/timestamp/time format,
254
- convert them to `Date` or `DateTime` objects as appropriate
255
- * `:hybrid` or `true` - similar as above, but instead of converting to regular
256
- `Date`/`DateTime` it converts strings to `FmRest::StringDate` and
257
- `FmRest::StringDateTime`, "hybrid" classes provided by fmrest-ruby that
258
- retain the functionality of `String` while also providing most the
259
- functionality of `Date`/`DateTime` (more on this below)
260
- * `false` - disable date coercion entirely (default), leave original string
261
- values untouched
262
-
263
- Enabling date coercion works with both basic fmrest-ruby connections and Spyke
264
- models (ORM).
184
+ fmrest-ruby includes a number of options for storing session tokens:
265
185
 
266
- The connection options `:date_format`, `:timestamp_format` and `:time_format`
267
- control how to match and parse dates. You only need to provide these if you use
268
- a date/time localization different from American format (the default).
186
+ * Memory
187
+ * ActiveRecord
188
+ * Redis
189
+ * Moneta
269
190
 
270
- Future versions of fmrest-ruby will provide better (and less heuristic) ways of
271
- specifying and/or detecting date fields (e.g. by requesting layout metadata or
272
- a DSL in model classes).
191
+ See the [main document on token stores](docs/TokenStore.md) for detailed info
192
+ on how to set up each store.
273
193
 
274
- ### Hybrid string/date objects
194
+ ## Date fields and timezones
275
195
 
276
- `FmRest::StringDate` and `FmRest::StringDateTime` are special classes that
277
- inherit from `String`, but internally parse and store a `Date` or `DateTime`,
278
- and delegate any methods not provided by `String` to those objects. In other
279
- words, they quack like a duck *and* bark like a dog.
196
+ fmrest-ruby has automatic detection and coercion of date fields to and from
197
+ Ruby date/time objects. Basic timezone support is also provided.
280
198
 
281
- You can use these when you want fmrest-ruby to provide you with date objects,
282
- but you don't want to worry about date coercion of false positives (i.e. a
283
- string field that gets converted to `Date` because it just so matched the given
284
- date format).
199
+ See the [main document on date fields](docs/DateFields.md) for more info.
285
200
 
286
- Be warned however that these classes come with a fair share of known gotchas
287
- (see GitHub wiki for more info). Some of those gothas can be removed by calling
288
-
289
- ```ruby
290
- FmRest::StringDateAwareness.enable
291
- ```
292
-
293
- Which will extend the core `Date` and `DateTime` classes to be aware of
294
- `FmRest::StringDate`, especially when calling `Date.===`, `Date.parse` or
295
- `Date._parse`.
296
-
297
- If you're working with ActiveRecord models this will also make them accept
298
- `FmRest::StringDate` values for date fields.
299
-
300
- ### Timezones
301
-
302
- fmrest-ruby has basic timezone support. You can set the `:timezone` option in
303
- your connection settings to one of the following values:
304
-
305
- * `:local` - dates will be converted to your system local time offset (as
306
- defined by `ENV["TZ"]`), or the timezone set by `Time.zone` if you're using
307
- ActiveSupport
308
- * `:utc` - dates will be converted to UTC offset
309
- * `nil` - (default) ignore timezones altogether
310
-
311
-
312
- ## Spyke support (ActiveRecord-like ORM)
201
+ ## ActiveRecord-like ORM (fmrest-spyke)
313
202
 
314
203
  [Spyke](https://github.com/balvig/spyke) is an ActiveRecord-like gem for
315
- building REST models. fmrest-ruby has Spyke support out of the box, although
316
- Spyke itself is not a dependency of fmrest-ruby, so you'll need to add it to
317
- your Gemfile yourself:
318
-
319
- ```ruby
320
- gem 'spyke'
321
- ```
322
-
323
- Then require fmrest-ruby's Spyke support:
324
-
325
- ```ruby
326
- # Put this in config/initializers/fmrest.rb if it's a Rails project
327
- require "fmrest/spyke"
328
- ```
204
+ building REST ORM models. fmrest-ruby builds its ORM features atop Spyke,
205
+ bundled in the `fmrest-spyke` gem (already included if you're using the
206
+ `fmrest` gem).
329
207
 
330
- And finally extend your Spyke models with `FmRest::Spyke`:
208
+ To create a model you can inherit directly from `FmRest::Layout` (itself a
209
+ subclass of `Spyke::Base`).
331
210
 
332
211
  ```ruby
333
- class Honeybee < Spyke::Base
334
- include FmRest::Spyke
212
+ class Honeybee < FmRest::Layout
335
213
  end
336
214
  ```
337
215
 
338
- This will make your Spyke model send all its requests in Data API format, with
339
- token session auth. Find, create, update and destroy actions should all work
340
- as expected.
341
-
342
- Alternatively you can inherit directly from the shorthand
343
- `FmRest::Spyke::Base`, which is in itself a subclass of `Spyke::Base` with
344
- `FmRest::Spyke` already included:
345
-
346
- ```ruby
347
- class Honeybee < FmRest::Spyke::Base
348
- end
349
- ```
350
-
351
- All of Spyke's basic ORM operations work:
216
+ All of Spyke's basic ORM operations work as expected:
352
217
 
353
218
  ```ruby
354
219
  bee = Honeybee.new
355
220
 
356
221
  bee.name = "Hutch"
357
- bee.save # POST request
222
+ bee.save # POST request (creates new record)
358
223
 
359
224
  bee.name = "ハッチ"
360
- bee.save # PATCH request
225
+ bee.save # PATCH request (updates existing record)
361
226
 
362
227
  bee.reload # GET request
363
228
 
@@ -366,54 +231,44 @@ bee.destroy # DELETE request
366
231
  bee = Honeybee.find(9) # GET request
367
232
  ```
368
233
 
369
- Read Spyke's documentation for more information on these basic features.
234
+ It's recommended that you read Spyke's documentation for more information on
235
+ these basic features. If you've used ActiveRecord or similar ORM libraries
236
+ you'll find it quite familiar.
237
+
238
+ Notice that `FmRest::Layout` is aliased as `FmRest::Spyke::Base`. Previous
239
+ versions of fmrest-ruby only provided the latter version, so if you're already
240
+ using `FmRest::Spyke::Base` there's no need to rename your classes to
241
+ `FmRest::Layout`, both will continue to work interchangeably.
370
242
 
371
- In addition `FmRest::Spyke` extends `Spyke::Base` subclasses with the following
243
+ In addition, `FmRest::Layout` extends `Spyke::Base` with the following
372
244
  features:
373
245
 
374
- ### Model.fmrest_config=
246
+ ### FmRest::Layout.fmrest_config=
375
247
 
376
- Usually to tell a Spyke object to use a certain Faraday connection you'd use:
248
+ This allows you to set Data API connection settings specific to your model
249
+ class:
377
250
 
378
251
  ```ruby
379
- class Honeybee < Spyke::Base
380
- self.connection = Faraday.new(...)
381
- end
382
- ```
383
-
384
- fmrest-ruby simplfies the process of setting up your Spyke model with a Faraday
385
- connection by allowing you to just set your Data API connection settings:
386
-
387
- ```ruby
388
- class Honeybee < Spyke::Base
389
- include FmRest::Spyke
390
-
252
+ class Honeybee < FmRest::Layout
391
253
  self.fmrest_config = {
392
- host: "example.com",
393
- database: "My Database",
394
- username: "...",
395
- password: "..."
254
+ host: "",
255
+ database: "",
256
+ username: "",
257
+ password: ""
396
258
  }
397
259
  end
398
260
  ```
399
261
 
400
- This will automatically create a proper Faraday connection for those connection
401
- settings.
262
+ This will automatically create a proper Faraday connection using those
263
+ connection settings, so you don't have to worry about setting that up.
402
264
 
403
265
  Note that these settings are inheritable, so you could create a base class that
404
266
  does the initial connection setup and then inherit from it in models using that
405
267
  same connection. E.g.:
406
268
 
407
269
  ```ruby
408
- class BeeBase < Spyke::Base
409
- include FmRest::Spyke
410
-
411
- self.fmrest_config = {
412
- host: "example.com",
413
- database: "My Database",
414
- username: "...",
415
- password: "..."
416
- }
270
+ class BeeBase < FmRest::Layout
271
+ self.fmrest_config = { host: "…", database: "…", … }
417
272
  end
418
273
 
419
274
  class Honeybee < BeeBase
@@ -421,76 +276,46 @@ class Honeybee < BeeBase
421
276
  end
422
277
  ```
423
278
 
424
- ### Model.fmrest_config_overlay=
425
-
426
- There may be cases where you want to use different connection settings
427
- depending on context, for example if you want to use username and password
428
- provided by the user in a web application. Since `Model.fmrest_config` is
429
- global, changing the username/password for one context would also change it for
430
- all other contexts, leading to security issues.
431
-
432
- `Model.fmrest_config_overlay=` solves that issue by allowing you to override
433
- some settings in a thread-local and reversible manner. That way, using the same
434
- example as above, you could connect to the Data API with user-provided
435
- credentials without having them leak into other users of your web application.
436
-
437
- E.g.:
438
-
439
- ```ruby
440
- class BeeBase < Spyke::Base
441
- include FmRest::Spyke
442
-
443
- # Host and database provided as base settings
444
- self.fmrest_config = {
445
- host: "example.com",
446
- database: "My Database"
447
- }
448
- end
449
-
450
- # E.g. in a controller-action of a Rails application:
279
+ Also, if not set, your model will try to use
280
+ `FmRest.default_connection_settings` instead.
451
281
 
452
- # User-provided credentials
453
- BeeBase.fmrest_config_overlay = {
454
- username: params[:username],
455
- password: params[:password]
456
- }
282
+ #### Connection settings overlays
457
283
 
458
- # Perform some Data API requests ...
459
- ```
284
+ There may be cases where you want to use a different set of connection settings
285
+ depending on context. For example, if you want to use username and password
286
+ provided by the user in a web application. Since `.fmrest_config`
287
+ is set at the class level, changing the username/password for the model in one
288
+ context would also change it in all other contexts, leading to security issues.
460
289
 
461
- ### Model.clear_fmrest_config_overlay
290
+ To solve this scenario, fmrest-ruby provides a way of defining thread-local and
291
+ reversible connection settings overlays through
292
+ `.fmrest_config_overlay=`.
462
293
 
463
- Clears the thread-local settings provided to `fmrest_config_overaly=`.
294
+ See the [main document on connection setting overlays](docs/ConfigOverlays.md)
295
+ for details on how it works.
464
296
 
465
- ### Model.with_overlay
297
+ ### FmRest::Layout.layout
466
298
 
467
- Runs a block with the given settings overlay, resetting them after the block
468
- finishes running. It wraps execution in its own fiber, so it doesn't affect the
469
- overlay of the currently-running thread.
299
+ Use `layout` to set the layout name for your model.
470
300
 
471
301
  ```ruby
472
- Honeybee.with_overlay(username: "...", password: "...") do
473
- Honeybee.query(...)
302
+ class Honeybee < FmRest::Layout
303
+ layout "Honeybees Web"
474
304
  end
475
305
  ```
476
306
 
477
- ### Model.layout
478
-
479
- Use `layout` to set the `:layout` part of API URLs, e.g.:
307
+ Alternatively, if you're inheriting from `FmRest::Layout` directly you can set
308
+ the layout name in the class definition line:
480
309
 
481
310
  ```ruby
482
- class Honeybee < FmRest::Spyke::Base
483
- layout "Honeybees Web" # uri path will be "layouts/Honeybees%20Web/records(/:id)"
484
- end
311
+ class Honeybee < FmRest::Layout("Honeybees Web")
485
312
  ```
486
313
 
487
- This is much preferred over using Spyke's `uri` to set custom URLs for your
488
- Data API models.
489
-
490
- Note that you only need to set this if the name of the model and the name of
491
- the layout differ, otherwise the default will just work.
314
+ Note that you only need to manually set the layout name if the name of the
315
+ class and the name of the layout differ, otherwise fmrest-ruby will just use
316
+ the name of the class.
492
317
 
493
- ### Model.request_auth_token
318
+ ### FmRest::Layout.request_auth_token
494
319
 
495
320
  Requests a Data API session token using the connection settings in
496
321
  `fmrest_config` and returns it if successful, otherwise returns `false`.
@@ -499,16 +324,16 @@ You normally don't need to use this method as fmrest-ruby will automatically
499
324
  request and store session tokens for you (provided that `:autologin` is
500
325
  `true`).
501
326
 
502
- ### Model.logout
327
+ ### FmRest::Layout.logout
503
328
 
504
- Use `logout` to log out from the database session (you may call it on any model
505
- that uses the database session you want to log out from).
329
+ Use `.logout` to log out from the database session (you may call it on any
330
+ model that uses the database session you want to log out from).
506
331
 
507
332
  ```ruby
508
333
  Honeybee.logout
509
334
  ```
510
335
 
511
- ### Mapped Model.attributes
336
+ ### Mapped FmRest::Layout.attributes
512
337
 
513
338
  Spyke allows you to define your model's attributes using `attributes`, however
514
339
  sometimes FileMaker's field names aren't very Ruby-ORM-friendly, especially
@@ -517,7 +342,7 @@ fmrest-ruby extends `attributes`' functionality to allow you to map
517
342
  Ruby-friendly attribute names to FileMaker field names. E.g.:
518
343
 
519
344
  ```ruby
520
- class Honeybee < FmRest::Spyke::Base
345
+ class Honeybee < FmRest::Layout
521
346
  attributes first_name: "First Name", last_name: "Last Name"
522
347
  end
523
348
  ```
@@ -536,62 +361,21 @@ bee.first_name = "Queen"
536
361
  bee.attributes # => { "First Name": "Queen", "Last Name": "Buzz" }
537
362
  ```
538
363
 
539
- ### Model.has_portal
364
+ ### FmRest::Layout.has_portal
540
365
 
541
- You can define portal associations on your model as such:
366
+ You can define portal associations on your model wth `has_portal`, as such:
542
367
 
543
368
  ```ruby
544
- class Honeybee < FmRest::Spyke::Base
369
+ class Honeybee < FmRest::Layout
545
370
  has_portal :flowers
546
371
  end
547
372
 
548
- class Flower < FmRest::Spyke::Base
373
+ class Flower < FmRest::Layout
549
374
  attributes :color, :species
550
375
  end
551
376
  ```
552
377
 
553
- In this case fmrest-ruby will expect the portal table name and portal object
554
- name to be both "flowers", i.e. the expected portal JSON portion should look
555
- like this:
556
-
557
- ```json
558
- ...
559
- "portalData": {
560
- "flowers": [
561
- {
562
- "flowers::color": "red",
563
- "flowers::species": "rose"
564
- }
565
- ]
566
- }
567
- ```
568
-
569
- If you need to specify different values for them you can do so with
570
- `portal_key` for the portal table name, and `attribute_prefix` for the portal
571
- object name, and `class_name`, e.g.:
572
-
573
- ```ruby
574
- class Honeybee < FmRest::Spyke::Base
575
- has_portal :pollinated_flowers, portal_key: "Bee Flowers",
576
- attribute_prefix: "Flower",
577
- class_name: "Flower"
578
- end
579
- ```
580
-
581
- The above will use the `Flower` model class and expects the following portal JSON
582
- portion:
583
-
584
- ```json
585
- ...
586
- "portalData": {
587
- "Bee Flowers": [
588
- {
589
- "Flower::color": "white",
590
- "Flower::species": "rose"
591
- }
592
- ]
593
- }
594
- ```
378
+ See the [main document on portal associations](docs/Portals.md) for details.
595
379
 
596
380
  ### Dirty attributes
597
381
 
@@ -621,208 +405,11 @@ Guides](https://guides.rubyonrails.org/active_model_basics.html#dirty).
621
405
  Since Spyke is API-agnostic it only provides a wide-purpose `.where` method for
622
406
  passing arbitrary parameters to the REST backend. fmrest-ruby however is well
623
407
  aware of its backend API, so it extends Spkye models with a bunch of useful
624
- querying methods.
625
-
626
- #### .limit
627
-
628
- `.limit` sets the limit for get and find request:
629
-
630
- ```ruby
631
- Honeybee.limit(10)
632
- ```
633
-
634
- NOTE: You can also set a default limit value for a model class, see
635
- [other notes on querying](#other-notes-on-querying).
636
-
637
- You can also use `.limit` to set limits on portals:
638
-
639
- ```ruby
640
- Honeybee.limit(hives: 3, flowers: 2)
641
- ```
642
-
643
- To remove the limit on a portal set it to `nil`:
644
-
645
- ```ruby
646
- Honeybee.limit(flowers: nil)
647
- ```
648
-
649
- #### .offset
650
-
651
- `.offset` sets the offset for get and find requests:
652
-
653
- ```ruby
654
- Honeybee.offset(10)
655
- ```
656
-
657
- You can also use `.offset` to set offsets on portals:
658
-
659
- ```ruby
660
- Honeybee.offset(hives: 3, flowers: 2)
661
- ```
662
-
663
- To remove the offset on a portal set it to `nil`:
664
-
665
- ```ruby
666
- Honeybee.offset(flowers: nil)
667
- ```
668
-
669
- #### .sort
670
-
671
- `.sort` (or `.order`) sets sorting options for get and find requests:
672
-
673
- ```ruby
674
- Honeybee.sort(:name, :age)
675
- Honeybee.order(:name, :age) # alias method
676
- ```
677
-
678
- You can set descending sort order by appending either `!` or `__desc` to a sort
679
- attribute (defaults to ascending order):
680
-
681
- ```ruby
682
- Honeybee.sort(:name, :age!)
683
- Honeybee.sort(:name, :age__desc)
684
- ```
685
-
686
- NOTE: You can also set default sort values for a model class, see
687
- [Other notes on querying](#other-notes-on-querying).
688
-
689
- #### .portal
690
-
691
- `.portal` (aliased as `.includes` and `.portals`) sets which portals to fetch
692
- (if any) for get and find requests (this recognizes portals defined with
693
- `has_portal`):
694
-
695
- ```ruby
696
- Honeybee.portal(:hives) # include just the :hives portal
697
- Honeybee.includes(:hives) # alias method
698
- Honeybee.portals(:hives, :flowers) # alias for pluralization fundamentalists
699
- ```
700
-
701
- Chaining calls to `.portal` will add portals to the existing included list:
702
-
703
- ```ruby
704
- Honeybee.portal(:flowers).portal(:hives) # include both portals
705
- ```
706
-
707
- If you want to disable portals for the scope call `.portal(false)`:
708
-
709
- ```ruby
710
- Honeybee.portal(false) # disable portals for this scope
711
- ```
712
-
713
- If you want to include all portals call `.portal(true)`:
714
-
715
- ```ruby
716
- Honeybee.portal(true) # include all portals
717
- ```
718
-
719
- For convenience you can also use `.with_all_portals` and `.without_portals`,
720
- which behave just as calling `.portal(true)` and `portal(false)` respectively.
721
-
722
- NOTE: By default all portals are included.
723
-
724
- #### .query
725
-
726
- `.query` sets query conditions for a find request (and supports attributes as
727
- defined with `attributes`):
728
-
729
- ```ruby
730
- Honeybee.query(name: "Hutch")
731
- # JSON -> {"query": [{"Bee Name": "Hutch"}]}
732
- ```
733
-
734
- Passing multiple attributes to `.query` will group them in the same JSON object:
735
-
736
- ```ruby
737
- Honeybee.query(name: "Hutch", age: 4)
738
- # JSON -> {"query": [{"Bee Name": "Hutch", "Bee Age": 4}]}
739
- ```
740
-
741
- Calling `.query` multiple times or passing it multiple hashes creates separate
742
- JSON objects (so you can define OR queries):
743
-
744
- ```ruby
745
- Honeybee.query(name: "Hutch").query(name: "Maya")
746
- Honeybee.query({ name: "Hutch" }, { name: "Maya" })
747
- # JSON -> {"query": [{"Bee Name": "Hutch"}, {"Bee Name": "Maya"}]}
748
- ```
749
-
750
- #### .omit
751
-
752
- `.omit` works like `.query` but excludes matches:
753
-
754
- ```ruby
755
- Honeybee.omit(name: "Hutch")
756
- # JSON -> {"query": [{"Bee Name": "Hutch", "omit": "true"}]}
757
- ```
758
-
759
- You can get the same effect by passing `omit: true` to `.query`:
760
-
761
- ```ruby
762
- Honeybee.query(name: "Hutch", omit: true)
763
- # JSON -> {"query": [{"Bee Name": "Hutch", "omit": "true"}]}
764
- ```
765
-
766
- #### .script
767
-
768
- `.script` enables the execution of scripts during query requests.
769
-
770
- ```ruby
771
- Honeybee.script("My script").find_some # Fetch records and execute a script
772
- ```
773
-
774
- See section on [script execution](#script-execution) below for more info.
775
-
776
- #### Other notes on querying
777
-
778
- You can chain all query methods together:
779
-
780
- ```ruby
781
- Honeybee.limit(10).offset(20).sort(:name, :age!).portal(:hives).query(name: "Hutch")
782
- ```
783
-
784
- You can also set default values for limit and sort on the class:
785
-
786
- ```ruby
787
- class Honeybee < FmRest::Spyke::Base
788
- self.default_limit = 1000
789
- self.default_sort = [:name, :age!]
790
- end
791
- ```
792
-
793
- Calling any `Enumerable` method on the resulting scope object will trigger a
794
- server request, so you can treat the scope as a collection:
795
-
796
- ```ruby
797
- Honeybee.limit(10).sort(:name).each { |bee| ... }
798
- ```
799
-
800
- If you want to explicitly run the request instead you can use `.find_some` on
801
- the scope object:
802
-
803
- ```ruby
804
- Honeybee.limit(10).sort(:name).find_some # => [<Honeybee...>, ...]
805
- ```
806
-
807
- If you want just a single result you can use `.first` instead (this will
808
- force `.limit(1)`):
809
-
810
- ```ruby
811
- Honeybee.query(name: "Hutch").first # => <Honeybee...>
812
- ```
813
-
814
- If you know the id of the record you should use `.find(id)` instead of
815
- `.query(id: id).first` (so that the sent request is
816
- `GET ../:layout/records/:id` instead of `POST ../:layout/_find`).
817
-
818
- ```ruby
819
- Honeybee.find(89) # => <Honeybee...>
820
- ```
821
-
822
- Note also that if you use `.find(id)` your `.query()` parameters (as well as
823
- limit, offset and sort parameters) will be discarded as they're not supported
824
- by the single record endpoint.
408
+ querying methods: `.query`, `.match`, `.omit`, `.limit`, `.offset`, `.sort`,
409
+ `.portal`, `.script`, etc.
825
410
 
411
+ See the [main document on querying](docs/Querying.md) for detailed information
412
+ on the query API methods.
826
413
 
827
414
  ### Finding records in batches
828
415
 
@@ -830,249 +417,63 @@ Sometimes you want to iterate over a very large number of records to do some
830
417
  processing, but requesting them all at once would result in one huge request to
831
418
  the Data API, and loading too many records in memory all at once.
832
419
 
833
- To mitigate this problem you can use `.find_in_batches` and `.find_each`. If
834
- you've used ActiveRecord you're probably familiar with how they operate:
835
-
836
- ```ruby
837
- # Find records in batches of 100 each
838
- Honeybee.query(hive: "Queensville").find_in_batches(batch_size: 100) do |batch|
839
- dispatch_bees(batch)
840
- end
841
-
842
- # Iterate over all records using batches
843
- Honeybee.query(hive: "Queensville").find_each(batch_size: 100) do |bee|
844
- bee.dispatch
845
- end
846
- ```
847
-
848
- `.find_in_batches` yields collections of records (batches), while `.find_each`
849
- yields individual records, but using batches behind the scenes.
850
-
851
- Both methods accept a block-less form in which case they return an
852
- `Enumerator`:
853
-
854
- ```ruby
855
- batch_enum = Honeybee.find_in_batches
856
-
857
- batch = batch_enum.next # => Spyke::Collection
858
-
859
- batch_enum.each do |batch|
860
- process_batch(batch)
861
- end
862
-
863
- record_enum = Honeybee.find_each
864
-
865
- record_enum.next # => Honeybee
866
- ```
867
-
868
- NOTE: By its nature, batch processing is subject to race conditions if other
869
- processes are modifying the database.
420
+ To mitigate this problem you can use `.find_in_batches` and `.find_each`.
870
421
 
422
+ See the [main document on finding in batches](docs/FindInBatches.md) for
423
+ detailed information on how those work.
871
424
 
872
425
  ### Container fields
873
426
 
874
427
  You can define container fields on your model class with `container`:
875
428
 
876
429
  ```ruby
877
- class Honeybee < FmRest::Spyke::Base
430
+ class Honeybee < FmRest::Layout
878
431
  container :photo, field_name: "Beehive Photo ID"
879
432
  end
880
433
  ```
881
434
 
882
- `:field_name` specifies the original field in the FM layout and is optional, if
883
- not given it will default to the name of your attribute (just `:photo` in this
884
- example).
885
-
886
- (Note that you don't need to define container fields with `attributes` in
887
- addition to the `container` definition.)
888
-
889
- This will provide you with the following instance methods:
890
-
891
- ```ruby
892
- bee = Honeybee.new
893
-
894
- bee.photo.url # The URL of the container file on the FileMaker server
895
-
896
- bee.photo.download # Download the contents of the container as an IO object
897
-
898
- bee.photo.upload(filename_or_io) # Upload a file to the container
899
- ```
900
-
901
- `upload` also accepts an options hash with the following options:
902
-
903
- * `:repetition` - Sets the field repetition
904
- * `:filename` - The filename to use when uploading (defaults to
905
- `filename_or_io.original_filename` if available)
906
- * `:content_type` - The MIME content type to use (defaults to
907
- `application/octet-stream`)
908
-
435
+ See the [main document on container fields](docs/ContainerFields.md) for
436
+ details on how to use it.
909
437
 
910
438
  ### Script execution
911
439
 
912
- The Data API allows running scripts as part of many types of requests.
913
-
914
- #### Model.execute_script
915
- As of FM18 you can execute scripts directly. To do that for a specific model
916
- use `Model.execute_script`:
917
-
918
- ```ruby
919
- result = Honeybee.execute_script("My Script", param: "optional parameter")
920
- ```
921
-
922
- This will return a `Spyke::Result` object containing among other things the
923
- result of the script execution:
924
-
925
- ```ruby
926
- result.metadata[:script][:after]
927
- # => { result: "oh hi", error: "0" }
928
- ```
929
-
930
- #### Script options object format
931
-
932
- All other script-capable requests take one or more of three possible script
933
- execution options: `script.prerequest`, `script.presort` and plain `script`
934
- (which fmrest-ruby dubs `after` for convenience).
935
-
936
- Because of that fmrest-ruby uses a common object format for specifying script options
937
- across multiple methods. That object format is as follows:
938
-
939
- ```ruby
940
- # Just a string means to execute that `after' script without a parameter
941
- "My Script"
942
-
943
- # A 2-elemnent array means [script name, script parameter]
944
- ["My Script", "parameter"]
945
-
946
- # A hash with keys :prerequest, :presort and/or :after sets those scripts for
947
- {
948
- prerequest: "My Prerequest Script",
949
- presort: "My Presort Script",
950
- after: "My Script"
951
- }
952
-
953
- # Using 2-element arrays as objects in the hash allows specifying parameters
954
- {
955
- prerequest: ["My Prerequest Script", "parameter"],
956
- presort: ["My Presort Script", "parameter"],
957
- after: ["My Script", "parameter"]
958
- }
959
- ```
960
-
961
- #### Script execution on record save, destroy and reload
962
-
963
- A record instance's `.save` and `.destroy` methods both accept a `script:`
964
- option to which you can pass a script options object with
965
- [the above format](#script-options-object-format):
966
-
967
- ```ruby
968
- # Save the record and execute an `after' script called "My Script"
969
- bee.save(script: "My Script")
970
-
971
- # Same as above but with an added parameter
972
- bee.save(script: ["My Script", "parameter"])
973
-
974
- # Save the record and execute a presort script and an `after' script
975
- bee.save(script: { presort: "My Presort Script", after: "My Script" })
976
-
977
- # Destroy the record and execute a prerequest script with a parameter
978
- bee.destroy(script: { prerequest: ["My Prerequest Script", "parameter"] })
979
-
980
- # Reload the record and execute a prerequest script with a parameter
981
- bee.reload(script: { prerequest: ["My Prerequest Script", "parameter"] })
982
- ```
983
-
984
- #### Retrieving script execution results
985
-
986
- Every time a request is ran on a model or record instance of a model, a
987
- thread-local `Model.last_request_metadata` attribute is set on that model,
988
- which is a hash containing the results of script executions, if any were
989
- performed, among other metadata.
990
-
991
- The results for `:after`, `:prerequest` and `:presort` scripts are stored
992
- separately, under their matching key.
993
-
994
- ```ruby
995
- bee.save(script: { presort: "My Presort Script", after: "My Script" })
996
-
997
- Honeybee.last_request_metadata.script
998
- # => { after: { result: "oh hi", error: "0" }, presort: { result: "lo", error: "0" } }
999
- ```
1000
-
1001
- #### Executing scripts through query requests
1002
-
1003
- As mentioned under the [Query API](#query-api) section, you can use the
1004
- `.script` query method to specify that you want scripts executed when a query
1005
- is performed on that scope.
1006
-
1007
- `.script` takes the same options object specified [above](#script-options-object-format):
1008
-
1009
- ```ruby
1010
- # Find one Honeybee record executing a presort and after script
1011
- Honeybee.script(presort: ["My Presort Script", "parameter"], after: "My Script").first
1012
- ```
1013
-
1014
- The model class' `.last_request_metadata` will be set in case you need to get the result.
1015
-
1016
- In the case of retrieving multiple results (i.e. via `.find_some`) the
1017
- resulting collection will have a `.metadata` attribute method containing the
1018
- same metadata hash with script execution results. Note that this does not apply
1019
- to retrieving single records, in that case you'll have to use
1020
- `.last_request_metadata`.
440
+ The FM Data API allows running scripts as part of many types of requests, and
441
+ `fmrest-spyke` provides mechanisms for all of them.
1021
442
 
443
+ See the [main document on script execution](docs/ScriptExecution.md) for
444
+ details.
1022
445
 
1023
446
  ### Setting global field values
1024
447
 
1025
- You can call `.set_globals` on any `FmRest::Spyke::Base` model to set glabal
448
+ You can call `.set_globals` on any `FmRest::Layout` model to set global
1026
449
  field values on the database that model is configured for.
1027
450
 
1028
- You can pass it either a hash of fully qualified field names
1029
- (table_name::field_name), or 1-level-deep nested hashes, with the outer being a
1030
- table name and the inner keys being the field names:
1031
-
1032
- ```ruby
1033
- Honeybee.set_globals(
1034
- "beeTable::myVar" => "value",
1035
- "beeTable::myOtherVar" => "also a value"
1036
- )
1037
-
1038
- # Equivalent to the above example
1039
- Honeybee.set_globals(beeTable: { myVar: "value", myOtherVar: "also a value" })
1040
-
1041
- # Combined
1042
- Honeybee.set_globals(
1043
- "beeTable::myVar" => "value",
1044
- beeTable: { myOtherVar: "also a value" }
1045
- )
1046
- ```
1047
-
451
+ See the [main document on setting global field values](docs/GlobalFields.md)
452
+ for details.
1048
453
 
1049
454
  ## Logging
1050
455
 
1051
- If using fmrest-ruby + Spyke in a Rails app pretty log output will be set up
1052
- for you automatically by Spyke (see [their
456
+ If using `fmrest-spyke` with Rails then pretty log output will be set up for
457
+ you automatically by Spyke (see [their
1053
458
  README](https://github.com/balvig/spyke#log-output)).
1054
459
 
1055
- You can also enable simple STDOUT logging (useful for debugging) by passing
1056
- `log: true` in the options hash for either
460
+ You can also enable simple Faraday STDOUT logging of raw requests (useful for
461
+ debugging) by passing `log: true` in the options hash for either
1057
462
  `FmRest.default_connection_settings=` or your models' `fmrest_config=`, e.g.:
1058
463
 
1059
464
  ```ruby
1060
465
  FmRest.default_connection_settings = {
1061
- host: "example.com",
1062
- database: "My Database",
1063
- username: "z3r0c00l",
1064
- password: "abc123",
1065
- log: true
466
+ host: "",
467
+
468
+ log: true
1066
469
  }
1067
470
 
1068
471
  # Or in your model
1069
- class LoggyBee < FmRest::Spyke::Base
472
+ class LoggyBee < FmRest::Layout
1070
473
  self.fmrest_config = {
1071
- host: "example.com",
1072
- database: "My Database",
1073
- username: "...",
1074
- password: "...",
1075
- log: true
474
+ host: "",
475
+
476
+ log: true
1076
477
  }
1077
478
  end
1078
479
  ```
@@ -1082,7 +483,7 @@ If you need to set up more complex logging for your models can use the
1082
483
  Faraday connection, e.g.:
1083
484
 
1084
485
  ```ruby
1085
- class LoggyBee < FmRest::Spyke::Base
486
+ class LoggyBee < FmRest::Layout
1086
487
  faraday do |conn|
1087
488
  conn.response :logger, MyApp.logger, bodies: true
1088
489
  end
@@ -1093,33 +494,43 @@ end
1093
494
 
1094
495
  FM Data API reference: https://fmhelp.filemaker.com/docs/18/en/dataapi/
1095
496
 
1096
- | FM 18 Data API feature | Supported by basic connection | Supported by FmRest::Spyke::Base |
1097
- |-------------------------------------|-------------------------------|----------------------------------|
1098
- | Log in using HTTP Basic Auth | Yes | Yes |
1099
- | Log in using OAuth | No | No |
1100
- | Log in to an external data source | No | No |
1101
- | Log in using a FileMaker ID account | No | No |
1102
- | Log out | Yes | Yes |
1103
- | Get product information | Manual* | No |
1104
- | Get database names | Manual* | No |
1105
- | Get script names | Manual* | No |
1106
- | Get layout names | Manual* | No |
1107
- | Get layout metadata | Manual* | No |
1108
- | Create a record | Manual* | Yes |
1109
- | Edit a record | Manual* | Yes |
1110
- | Duplicate a record | Manual* | No |
1111
- | Delete a record | Manual* | Yes |
1112
- | Get a single record | Manual* | Yes |
1113
- | Get a range of records | Manual* | Yes |
1114
- | Get container data | Manual* | Yes |
1115
- | Upload container data | Manual* | Yes |
1116
- | Perform a find request | Manual* | Yes |
1117
- | Set global field values | Manual* | Yes
1118
- | Run a script | Manual* | Yes |
1119
- | Run a script with another request | Manual* | Yes |
497
+ | FM 18 Data API feature | Supported by basic connection | Supported by FmRest::Layout |
498
+ |-------------------------------------|-------------------------------|-----------------------------|
499
+ | Log in using HTTP Basic Auth | Yes | Yes |
500
+ | Log in using OAuth | No | No |
501
+ | Log in to an external data source | No | No |
502
+ | Log in using a FileMaker ID account | No | No |
503
+ | Log out | Yes | Yes |
504
+ | Get product information | Manual* | No |
505
+ | Get database names | Manual* | No |
506
+ | Get script names | Manual* | No |
507
+ | Get layout names | Manual* | No |
508
+ | Get layout metadata | Manual* | No |
509
+ | Create a record | Manual* | Yes |
510
+ | Edit a record | Manual* | Yes |
511
+ | Duplicate a record | Manual* | No |
512
+ | Delete a record | Manual* | Yes |
513
+ | Edit portal records | Manual* | Yes |
514
+ | Get a single record | Manual* | Yes |
515
+ | Get a range of records | Manual* | Yes |
516
+ | Get container data | Manual* | Yes |
517
+ | Upload container data | Manual* | Yes |
518
+ | Perform a find request | Manual* | Yes |
519
+ | Set global field values | Manual* | Yes |
520
+ | Run a script | Manual* | Yes |
521
+ | Run a script with another request | Manual* | Yes |
1120
522
 
1121
523
  \* You can manually supply the URL and JSON to a `FmRest` connection.
1122
524
 
525
+ ## Supported Ruby versions
526
+
527
+ fmrest-ruby aims to support and is [tested against](https://github.com/beezwax/fmrest-ruby/actions?query=workflow%3ACI)
528
+ the following Ruby implementations:
529
+
530
+ * Ruby 2.5
531
+ * Ruby 2.6
532
+ * Ruby 2.7
533
+ * Ruby 3.0
1123
534
 
1124
535
  ## Gem development
1125
536
 
@@ -1128,20 +539,11 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
1128
539
  prompt that will allow you to experiment (it will auto-load all fixtures in
1129
540
  spec/fixtures).
1130
541
 
1131
- To install this gem onto your local machine, run `bundle exec rake install`. To
1132
- release a new version, update the version number in `version.rb`, and then run
1133
- `bundle exec rake release`, which will create a git tag for the version, push
1134
- git commits and tags, and push the `.gem` file to
1135
- [rubygems.org](https://rubygems.org).
1136
-
1137
-
1138
- ## Contributing
1139
-
1140
- Bug reports and pull requests are welcome. This project is intended to be a
1141
- safe, welcoming space for collaboration, and contributors are expected to
1142
- adhere to the [Contributor Covenant](http://contributor-covenant.org) code of
1143
- conduct.
1144
-
542
+ To install all gems onto your local machine, run
543
+ `bundle exec rake all:install`. To release a new version, update the version
544
+ number in `lib/fmrest/version.rb`, and then run `bundle exec rake all:release`,
545
+ which will create a git tag for the version, push git commits and tags, and
546
+ push the `.gem` files to [rubygems.org](https://rubygems.org).
1145
547
 
1146
548
  ## License
1147
549
 
@@ -1149,9 +551,8 @@ The gem is available as open source under the terms of the
1149
551
  [MIT License](https://opensource.org/licenses/MIT).
1150
552
  See [LICENSE.txt](LICENSE.txt).
1151
553
 
1152
-
1153
554
  ## Disclaimer
1154
555
 
1155
- This project is not sponsored by or otherwise affiliated with FileMaker, Inc,
1156
- an Apple subsidiary. FileMaker is a trademark of FileMaker, Inc., registered in
1157
- the U.S. and other countries.
556
+ This project is not sponsored by or otherwise affiliated with Claris
557
+ International Inc., an Apple Inc. subsidiary. FileMaker is a trademark of
558
+ Claris International Inc., registered in the U.S. and other countries.