automodel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +81 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +5 -0
  7. data/.yardopts +1 -0
  8. data/Gemfile +6 -0
  9. data/Gemfile.lock +75 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +216 -0
  12. data/Rakefile +6 -0
  13. data/automodel.gemspec +37 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/docs/Automodel.html +161 -0
  17. data/docs/Automodel/AdapterAlreadyRegistered.html +144 -0
  18. data/docs/Automodel/AdapterAlreadyRegisteredError.html +144 -0
  19. data/docs/Automodel/CannotFindOnCompoundPrimaryKey.html +144 -0
  20. data/docs/Automodel/Connectors.html +117 -0
  21. data/docs/Automodel/Error.html +139 -0
  22. data/docs/Automodel/FindOnCompoundPrimaryKeyError.html +144 -0
  23. data/docs/Automodel/Helpers.html +722 -0
  24. data/docs/Automodel/NameCollisionError.html +143 -0
  25. data/docs/Automodel/SchemaInspector.html +1046 -0
  26. data/docs/Automodel/UnregisteredAdapter.html +144 -0
  27. data/docs/_index.html +206 -0
  28. data/docs/class_list.html +51 -0
  29. data/docs/css/common.css +1 -0
  30. data/docs/css/full_list.css +58 -0
  31. data/docs/css/style.css +496 -0
  32. data/docs/file.README.html +312 -0
  33. data/docs/file_list.html +56 -0
  34. data/docs/frames.html +17 -0
  35. data/docs/index.html +312 -0
  36. data/docs/js/app.js +292 -0
  37. data/docs/js/full_list.js +216 -0
  38. data/docs/js/jquery.js +4 -0
  39. data/docs/method_list.html +155 -0
  40. data/docs/top-level-namespace.html +477 -0
  41. data/lib/automodel.rb +132 -0
  42. data/lib/automodel/automodel.rb +4 -0
  43. data/lib/automodel/connectors.rb +8 -0
  44. data/lib/automodel/errors.rb +24 -0
  45. data/lib/automodel/helpers.rb +141 -0
  46. data/lib/automodel/schema_inspector.rb +218 -0
  47. data/lib/automodel/version.rb +10 -0
  48. data/samples/database.yml +38 -0
  49. metadata +231 -0
@@ -0,0 +1,312 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.9.14
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="file_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'>
61
+ <h1 id="label-Automodel+rdoc-image-3Ahttps-3A-2F-2Fbadge.fury.io-2Frb-2Fautomodel.svg">Automodel <a href="https://badge.fury.io/rb/automodel"><img src="https://badge.fury.io/rb/automodel.svg"></a></h1>
62
+
63
+ <p>Connecting your Rails application to a database created outside of the
64
+ Rails environment usually means either spending hours writing up class
65
+ files for every table, or giving up on using the ActiveRecord query DSL and
66
+ resigning yourself to building SQL strings and making
67
+ <code>execute</code>/<code>exec_query</code> calls.</p>
68
+
69
+ <p>Are those SQL strings you&#39;re building even injection-safe? Hmm… 😟</p>
70
+
71
+ <p><em>With a single command</em>, <strong>Automodel</strong> lets you connect
72
+ to any database and access all of its tables via the ActiveRecord DSL
73
+ you&#39;ve grown to love!</p>
74
+
75
+ <p>It does this by analyzing the table structures and: - automatically
76
+ defining all of the corresponding model classes - declaring column aliases
77
+ so you can use Railsy names an idioms - constructing model relations based
78
+ on foreign key definitions</p>
79
+
80
+ <h2 id="label-Installation">Installation</h2>
81
+
82
+ <p>Add this line to your application&#39;s Gemfile:</p>
83
+
84
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>automodel</span><span class='tstring_end'>&#39;</span></span>
85
+ </code></pre>
86
+
87
+ <p>And then execute:</p>
88
+
89
+ <pre class="code ruby"><code class="ruby">$ bundle
90
+ </code></pre>
91
+
92
+ <p>Or install it yourself as:</p>
93
+
94
+ <pre class="code ruby"><code class="ruby">$ gem install automodel
95
+ </code></pre>
96
+
97
+ <h2 id="label-Using+Automodel">Using Automodel</h2>
98
+
99
+ <p>The following examples all assume a Postgres database with the following
100
+ tables: “`sql – Create Table: Authors CREATE TABLE public.“Authors” (
101
+ “Author ID” serial NOT NULL , “Name” varchar NOT NULL DEFAULT &#39;&#39;,
102
+ “Birthday” date NULL , “Address” varchar NOT NULL DEFAULT &#39;&#39;,</p>
103
+
104
+ <p>CONSTRAINT authors__pk PRIMARY KEY (“Author ID”) ) WITH ( OIDS=FALSE );</p>
105
+
106
+ <p>– Create Table: Publishers CREATE TABLE public.“Publishers” ( “Publisher
107
+ ID” serial NOT NULL , “Name” varchar NOT NULL DEFAULT &#39;&#39;,
108
+ “Address” varchar NOT NULL DEFAULT &#39;&#39;, “Website” varchar NOT NULL
109
+ DEFAULT &#39;&#39;,</p>
110
+
111
+ <p>CONSTRAINT publishers__pk PRIMARY KEY (“Publisher ID”) ) WITH ( OIDS=FALSE
112
+ );</p>
113
+
114
+ <p>– Create Table: Books CREATE TABLE public.“Books” ( “Book ID” serial NOT
115
+ NULL , “Title” varchar NOT NULL DEFAULT &#39;&#39; , “Edition” int NOT
116
+ NULL DEFAULT 1 , “ISBN Number” varchar NOT NULL DEFAULT &#39;&#39; ,
117
+ “Published On” date NOT NULL , “Is Out Of Print” bool NOT NULL DEFAULT
118
+ FALSE, “Author ID” bigint NOT NULL , “Publisher ID” bigint NOT NULL ,</p>
119
+
120
+ <p>CONSTRAINT books__pk PRIMARY KEY (“Book ID”),</p>
121
+
122
+ <p>CONSTRAINT books_authors_fk FOREIGN KEY (“Author ID”) REFERENCES
123
+ public.“Authors”(“Author ID”),</p>
124
+
125
+ <p>CONSTRAINT books_publishers_fk FOREIGN KEY (“Publisher ID”) REFERENCES
126
+ public.“Publishers”(“Publisher ID”) ) WITH ( OIDS=FALSE ); “`</p>
127
+ <hr>
128
+
129
+ <h4 id="label-Connecting+To+The+External+Database">Connecting To The External Database</h4>
130
+
131
+ <p>You can provide the connection spec inline …</p>
132
+
133
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='label'>adapter:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>postgresql</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
134
+ <span class='label'>encoding:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>unicode</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
135
+ <span class='label'>host:</span> <span class='id identifier rubyid_hostname'>hostname</span> <span class='comma'>,</span>
136
+ <span class='label'>port:</span> <span class='id identifier rubyid_port_number'>port_number</span> <span class='comma'>,</span>
137
+ <span class='label'>username:</span> <span class='id identifier rubyid_username'>username</span> <span class='comma'>,</span>
138
+ <span class='label'>password:</span> <span class='id identifier rubyid_password'>password</span> <span class='comma'>,</span>
139
+ <span class='label'>database:</span> <span class='id identifier rubyid_database_name'>database_name</span>
140
+ </code></pre>
141
+
142
+ <p>… or you can use a connection spec defined in “config/database.yml” …</p>
143
+
144
+ <pre class="code ruby"><code class="ruby">## In &quot;database.yml&quot; ...
145
+
146
+ ## ... (your application&#39;s own db connection stuff) ...
147
+
148
+
149
+ external_db:
150
+ adapter: postgresql
151
+ pool: &lt;%= ENV.fetch(&#39;RAILS_MAX_THREADS&#39;) { 5 } %&gt;
152
+ timeouts: 5000
153
+ encoding: unicode
154
+ host: name_or_ip
155
+ port: port_number
156
+ username: username
157
+ password: password
158
+ database: sample_db
159
+ </code></pre>
160
+
161
+ <pre class="code ruby"><code class="ruby"><span class='comment'>## In &quot;config/puma.rb&quot; or &quot;config/unicorn.rb&quot; ...
162
+ </span>
163
+ <span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='symbol'>:external_db</span>
164
+ </code></pre>
165
+ <hr>
166
+
167
+ <h4 id="label-Using+The+Automodel-27ed+Objects">Using The Automodel&#39;ed Objects</h4>
168
+
169
+ <p>Connecting via either method above will allow you to issue all of the
170
+ following expressions, just as if these were your own models:</p>
171
+
172
+ <pre class="code ruby"><code class="ruby"><span class='comment'>## ISBNs for all non-first-edition books.
173
+ </span><span class='id identifier rubyid_isbn_list'>isbn_list</span> <span class='op'>=</span> <span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='period'>.</span><span class='id identifier rubyid_not'>not</span><span class='lparen'>(</span><span class='label'>edition:</span> <span class='int'>1</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_pluck'>pluck</span><span class='lparen'>(</span><span class='symbol'>:isbn_number</span><span class='rparen'>)</span>
174
+
175
+ <span class='comment'>## Take any book and look up some values.
176
+ </span><span class='id identifier rubyid_book'>book</span> <span class='op'>=</span> <span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_take'>take</span>
177
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_title'>title</span>
178
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_out_of_print?'>out_of_print?</span>
179
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_publisher'>publisher</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span>
180
+
181
+
182
+ <span class='comment'>## Note that some ActiveRecord constructs surface real table names,
183
+ </span><span class='comment'>## which can look awkward in code when working with tables with non-Railsy names:
184
+ </span><span class='comment'>## (the uppercase &quot;P&quot; in &quot;Publishers&quot; below makes it look like a class reference)
185
+ </span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_joins'>joins</span><span class='lparen'>(</span><span class='symbol'>:Publishers</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='label'>Publishers:</span> <span class='lbrace'>{</span> <span class='label'>name:</span> <span class='id identifier rubyid_test_value'>test_value</span> <span class='rbrace'>}</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
186
+ </code></pre>
187
+ <hr>
188
+
189
+ <h4 id="label-Automodel+With+Namespacing">Automodel With Namespacing</h4>
190
+
191
+ <p>If you&#39;re worried about model name collisions (or just want to keep the
192
+ global namespace tidy), Automodel can define all of the new model classes
193
+ under a module.</p>
194
+
195
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='label'>adapter:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>postgresql</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
196
+ <span class='label'>encoding:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>unicode</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
197
+ <span class='label'>host:</span> <span class='id identifier rubyid_hostname'>hostname</span> <span class='comma'>,</span>
198
+ <span class='label'>port:</span> <span class='id identifier rubyid_port_number'>port_number</span> <span class='comma'>,</span>
199
+ <span class='label'>username:</span> <span class='id identifier rubyid_username'>username</span> <span class='comma'>,</span>
200
+ <span class='label'>password:</span> <span class='id identifier rubyid_password'>password</span> <span class='comma'>,</span>
201
+ <span class='label'>database:</span> <span class='id identifier rubyid_database_name'>database_name</span><span class='comma'>,</span>
202
+ <span class='label'>namespace:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>ExternalDB</span><span class='tstring_end'>&#39;</span></span>
203
+
204
+ <span class='comment'>## Now you can do everything you&#39;d expect, but the models are namespaced under ExternalDB.
205
+ </span><span class='const'>ExternalDB</span><span class='op'>::</span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'>## =&gt; Book #5
206
+ </span><span class='const'>ExternalDB</span><span class='op'>::</span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_take'>take</span><span class='period'>.</span><span class='id identifier rubyid_author'>author</span><span class='period'>.</span><span class='id identifier rubyid_class'>class</span> <span class='comment'>## =&gt; ExternalDB::Author
207
+ </span></code></pre>
208
+ <hr>
209
+
210
+ <p><a href="http://nestor-custodio.github.io/automodel/Automodel.html">Consult
211
+ the repo docs for the full Automodel documentation.</a></p>
212
+
213
+ <h2 id="label-FAQs">FAQs</h2>
214
+ <ul><li>
215
+ <h5 id="label-Do+I+have+to+add+anything+to+my+Gemfile+besides+-27automodel-27-3F">Do I have to add anything to my Gemfile besides <code>&#39;automodel&#39;</code>?</h5>
216
+
217
+ <p>Only if you want to use connection adapters that are not yet part of your
218
+ gemset. (e.g. Don&#39;t expect to be able to connect to a MySQL database
219
+ without having added <code>&#39;mysql2&#39;</code> to your Gemfile.</p>
220
+ </li><li>
221
+ <h5 id="label-But+what+about+my+application-27s+own+models-3F">But what about my application&#39;s own models?</h5>
222
+
223
+ <p>You can use Automodel <strong>and</strong> continue to use your
224
+ application&#39;s own models without changing a single line of code.</p>
225
+ </li><li>
226
+ <h5 id="label-Can+I+Automodel+more+than+one+database-3F">Can I Automodel more than one database?</h5>
227
+
228
+ <p>Yes! You can Automodel as many databases with as many different adapters
229
+ as you like. Automodel takes care of connecting to the various databases
230
+ and managing their connection pools for you.</p>
231
+ </li><li>
232
+ <h5 id="label-What+about+model+name+collisions-3F">What about model name collisions?</h5>
233
+
234
+ <p>If an <code>automodel</code> call will result in a class name collision,
235
+ an Automodel::NameCollisionError is raised <em>before</em> any classes are
236
+ clobbered.</p>
237
+ </li><li>
238
+ <h5 id="label-What+if+I+want+custom+methods+for+certain+models-3F">What if I want custom methods for certain models?</h5>
239
+
240
+ <p>You can either monkey-patch your methods onto the applicable
241
+ Automodel-generated classes once they&#39;ve been defined, or you can
242
+ monkey-patch the method onto the connection handler class returned by the
243
+ <code>automodel</code> call itself, which will make it available for all
244
+ models generated <em>by that call</em>.</p>
245
+ </li><li>
246
+ <h5 id="label-What+if+I-27m+using+ActiveRecord+but+not+Rails-3F">What if I&#39;m using ActiveRecord but not Rails?</h5>
247
+
248
+ <p>That&#39;s no problem at all! The <strong>automodel</strong> gem&#39;s
249
+ <em>only</em> dependency is ActiveRecord – not Rails. Adding
250
+ <code>&#39;automodel&#39;</code> to your Gemfile (along with any relevant
251
+ connection adapters, of course) is all you need to make use of the tool in
252
+ your vanilla-Ruby project. Just be mindful that – since
253
+ “config/database.yml” isn&#39;t available (as you&#39;re not using Rails) –
254
+ you&#39;ll always need to pass in a full connection spec to your
255
+ <code>automodel</code> calls (as in the very first example, under
256
+ <em>“Connecting To The External Database”</em> above).</p>
257
+ </li></ul>
258
+
259
+ <h2 id="label-Feature+Roadmap+-2F+Future+Development">Feature Roadmap / Future Development</h2>
260
+
261
+ <p>Additional features/options coming in the future:</p>
262
+ <ul><li>
263
+ <p><strong>Naming</strong>: Better generation of Railsy names for
264
+ <code>:date</code>/<code>:datetime</code> column types.</p>
265
+ </li><li>
266
+ <p><strong>Reads</strong>: Support for <code>#find</code> on tables with
267
+ composite primary keys.</p>
268
+ </li><li>
269
+ <p><strong>Writes</strong>: Better handling of missing
270
+ <code>created_at</code>/<code>updated_at</code> columns on record
271
+ creation/updates.</p>
272
+ </li><li>
273
+ <p><strong>Traversal</strong>: Support for <code>has_many</code> relations
274
+ (only <code>belongs_to</code> is currently supported).</p>
275
+ </li><li>
276
+ <p><strong>Traversal</strong>: Support for self-referential foreign keys.</p>
277
+ </li><li>
278
+ <p><strong>Traversal</strong>: Support for multiple relations to the same
279
+ target model.</p>
280
+ </li></ul>
281
+
282
+ <h2 id="label-Contribution+-2F+Development">Contribution / Development</h2>
283
+
284
+ <p>Bug reports and pull requests are welcome on GitHub at <a
285
+ href="https://github.com/nestor-custodio/automodel">github.com/nestor-custodio/automodel</a>.</p>
286
+
287
+ <p>After checking out the repo, run <code>bin/setup</code> to install
288
+ dependencies. Then, run <code>rake spec</code> to run the tests. You can
289
+ also run <code>bin/console</code> for an interactive prompt that will allow
290
+ you to experiment.</p>
291
+
292
+ <p>Linting is courtesy of <a
293
+ href="https://github.com/bbatsov/rubocop">Rubocop</a> and documentation is
294
+ built using <a href="https://yardoc.org/">Yard</a>. Neither is included in
295
+ the Gemspec; you&#39;ll need to install these locally (<code>gem install
296
+ rubocop yard</code>) to take advantage.</p>
297
+
298
+ <h2 id="label-License">License</h2>
299
+
300
+ <p>The gem is available as open source under the terms of the <a
301
+ href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
302
+ </div></div>
303
+
304
+ <div id="footer">
305
+ Generated on Fri Jun 15 16:46:49 2018 by
306
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
307
+ 0.9.14 (ruby-2.5.1).
308
+ </div>
309
+
310
+ </div>
311
+ </body>
312
+ </html>
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
5
+ <meta charset="utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <title>File List</title>
19
+ <base id="base_target" target="_parent" />
20
+ </head>
21
+ <body>
22
+ <div id="content">
23
+ <div class="fixed_header">
24
+ <h1 id="full_list_header">File List</h1>
25
+ <div id="full_list_nav">
26
+
27
+ <span><a target="_self" href="class_list.html">
28
+ Classes
29
+ </a></span>
30
+
31
+ <span><a target="_self" href="method_list.html">
32
+ Methods
33
+ </a></span>
34
+
35
+ <span><a target="_self" href="file_list.html">
36
+ Files
37
+ </a></span>
38
+
39
+ </div>
40
+
41
+ <div id="search">Search: <input type="text" /></div>
42
+ </div>
43
+
44
+ <ul id="full_list" class="file">
45
+
46
+
47
+ <li id="object_README" class="odd">
48
+ <div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
49
+ </li>
50
+
51
+
52
+
53
+ </ul>
54
+ </div>
55
+ </body>
56
+ </html>
data/docs/frames.html ADDED
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Documentation by YARD 0.9.14</title>
6
+ </head>
7
+ <script type="text/javascript" charset="utf-8">
8
+ var match = unescape(window.location.hash).match(/^#!(.+)/);
9
+ var name = match ? match[1] : 'index.html';
10
+ name = name.replace(/^(\w+):\/\//, '').replace(/^\/\//, '');
11
+ window.top.location = name;
12
+ </script>
13
+ <noscript>
14
+ <h1>Oops!</h1>
15
+ <h2>YARD requires JavaScript!</h2>
16
+ </noscript>
17
+ </html>
data/docs/index.html ADDED
@@ -0,0 +1,312 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.9.14
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ pathId = "README";
19
+ relpath = '';
20
+ </script>
21
+
22
+
23
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
24
+
25
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
26
+
27
+
28
+ </head>
29
+ <body>
30
+ <div class="nav_wrap">
31
+ <iframe id="nav" src="class_list.html?1"></iframe>
32
+ <div id="resizer"></div>
33
+ </div>
34
+
35
+ <div id="main" tabindex="-1">
36
+ <div id="header">
37
+ <div id="menu">
38
+
39
+ <a href="_index.html">Index</a> &raquo;
40
+ <span class="title">File: README</span>
41
+
42
+ </div>
43
+
44
+ <div id="search">
45
+
46
+ <a class="full_list_link" id="class_list_link"
47
+ href="class_list.html">
48
+
49
+ <svg width="24" height="24">
50
+ <rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
51
+ <rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
52
+ <rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
53
+ </svg>
54
+ </a>
55
+
56
+ </div>
57
+ <div class="clear"></div>
58
+ </div>
59
+
60
+ <div id="content"><div id='filecontents'>
61
+ <h1 id="label-Automodel+rdoc-image-3Ahttps-3A-2F-2Fbadge.fury.io-2Frb-2Fautomodel.svg">Automodel <a href="https://badge.fury.io/rb/automodel"><img src="https://badge.fury.io/rb/automodel.svg"></a></h1>
62
+
63
+ <p>Connecting your Rails application to a database created outside of the
64
+ Rails environment usually means either spending hours writing up class
65
+ files for every table, or giving up on using the ActiveRecord query DSL and
66
+ resigning yourself to building SQL strings and making
67
+ <code>execute</code>/<code>exec_query</code> calls.</p>
68
+
69
+ <p>Are those SQL strings you&#39;re building even injection-safe? Hmm… 😟</p>
70
+
71
+ <p><em>With a single command</em>, <strong>Automodel</strong> lets you connect
72
+ to any database and access all of its tables via the ActiveRecord DSL
73
+ you&#39;ve grown to love!</p>
74
+
75
+ <p>It does this by analyzing the table structures and: - automatically
76
+ defining all of the corresponding model classes - declaring column aliases
77
+ so you can use Railsy names an idioms - constructing model relations based
78
+ on foreign key definitions</p>
79
+
80
+ <h2 id="label-Installation">Installation</h2>
81
+
82
+ <p>Add this line to your application&#39;s Gemfile:</p>
83
+
84
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>automodel</span><span class='tstring_end'>&#39;</span></span>
85
+ </code></pre>
86
+
87
+ <p>And then execute:</p>
88
+
89
+ <pre class="code ruby"><code class="ruby">$ bundle
90
+ </code></pre>
91
+
92
+ <p>Or install it yourself as:</p>
93
+
94
+ <pre class="code ruby"><code class="ruby">$ gem install automodel
95
+ </code></pre>
96
+
97
+ <h2 id="label-Using+Automodel">Using Automodel</h2>
98
+
99
+ <p>The following examples all assume a Postgres database with the following
100
+ tables: “`sql – Create Table: Authors CREATE TABLE public.“Authors” (
101
+ “Author ID” serial NOT NULL , “Name” varchar NOT NULL DEFAULT &#39;&#39;,
102
+ “Birthday” date NULL , “Address” varchar NOT NULL DEFAULT &#39;&#39;,</p>
103
+
104
+ <p>CONSTRAINT authors__pk PRIMARY KEY (“Author ID”) ) WITH ( OIDS=FALSE );</p>
105
+
106
+ <p>– Create Table: Publishers CREATE TABLE public.“Publishers” ( “Publisher
107
+ ID” serial NOT NULL , “Name” varchar NOT NULL DEFAULT &#39;&#39;,
108
+ “Address” varchar NOT NULL DEFAULT &#39;&#39;, “Website” varchar NOT NULL
109
+ DEFAULT &#39;&#39;,</p>
110
+
111
+ <p>CONSTRAINT publishers__pk PRIMARY KEY (“Publisher ID”) ) WITH ( OIDS=FALSE
112
+ );</p>
113
+
114
+ <p>– Create Table: Books CREATE TABLE public.“Books” ( “Book ID” serial NOT
115
+ NULL , “Title” varchar NOT NULL DEFAULT &#39;&#39; , “Edition” int NOT
116
+ NULL DEFAULT 1 , “ISBN Number” varchar NOT NULL DEFAULT &#39;&#39; ,
117
+ “Published On” date NOT NULL , “Is Out Of Print” bool NOT NULL DEFAULT
118
+ FALSE, “Author ID” bigint NOT NULL , “Publisher ID” bigint NOT NULL ,</p>
119
+
120
+ <p>CONSTRAINT books__pk PRIMARY KEY (“Book ID”),</p>
121
+
122
+ <p>CONSTRAINT books_authors_fk FOREIGN KEY (“Author ID”) REFERENCES
123
+ public.“Authors”(“Author ID”),</p>
124
+
125
+ <p>CONSTRAINT books_publishers_fk FOREIGN KEY (“Publisher ID”) REFERENCES
126
+ public.“Publishers”(“Publisher ID”) ) WITH ( OIDS=FALSE ); “`</p>
127
+ <hr>
128
+
129
+ <h4 id="label-Connecting+To+The+External+Database">Connecting To The External Database</h4>
130
+
131
+ <p>You can provide the connection spec inline …</p>
132
+
133
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='label'>adapter:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>postgresql</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
134
+ <span class='label'>encoding:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>unicode</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
135
+ <span class='label'>host:</span> <span class='id identifier rubyid_hostname'>hostname</span> <span class='comma'>,</span>
136
+ <span class='label'>port:</span> <span class='id identifier rubyid_port_number'>port_number</span> <span class='comma'>,</span>
137
+ <span class='label'>username:</span> <span class='id identifier rubyid_username'>username</span> <span class='comma'>,</span>
138
+ <span class='label'>password:</span> <span class='id identifier rubyid_password'>password</span> <span class='comma'>,</span>
139
+ <span class='label'>database:</span> <span class='id identifier rubyid_database_name'>database_name</span>
140
+ </code></pre>
141
+
142
+ <p>… or you can use a connection spec defined in “config/database.yml” …</p>
143
+
144
+ <pre class="code ruby"><code class="ruby">## In &quot;database.yml&quot; ...
145
+
146
+ ## ... (your application&#39;s own db connection stuff) ...
147
+
148
+
149
+ external_db:
150
+ adapter: postgresql
151
+ pool: &lt;%= ENV.fetch(&#39;RAILS_MAX_THREADS&#39;) { 5 } %&gt;
152
+ timeouts: 5000
153
+ encoding: unicode
154
+ host: name_or_ip
155
+ port: port_number
156
+ username: username
157
+ password: password
158
+ database: sample_db
159
+ </code></pre>
160
+
161
+ <pre class="code ruby"><code class="ruby"><span class='comment'>## In &quot;config/puma.rb&quot; or &quot;config/unicorn.rb&quot; ...
162
+ </span>
163
+ <span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='symbol'>:external_db</span>
164
+ </code></pre>
165
+ <hr>
166
+
167
+ <h4 id="label-Using+The+Automodel-27ed+Objects">Using The Automodel&#39;ed Objects</h4>
168
+
169
+ <p>Connecting via either method above will allow you to issue all of the
170
+ following expressions, just as if these were your own models:</p>
171
+
172
+ <pre class="code ruby"><code class="ruby"><span class='comment'>## ISBNs for all non-first-edition books.
173
+ </span><span class='id identifier rubyid_isbn_list'>isbn_list</span> <span class='op'>=</span> <span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='period'>.</span><span class='id identifier rubyid_not'>not</span><span class='lparen'>(</span><span class='label'>edition:</span> <span class='int'>1</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_pluck'>pluck</span><span class='lparen'>(</span><span class='symbol'>:isbn_number</span><span class='rparen'>)</span>
174
+
175
+ <span class='comment'>## Take any book and look up some values.
176
+ </span><span class='id identifier rubyid_book'>book</span> <span class='op'>=</span> <span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_take'>take</span>
177
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_title'>title</span>
178
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_out_of_print?'>out_of_print?</span>
179
+ <span class='id identifier rubyid_book'>book</span><span class='period'>.</span><span class='id identifier rubyid_publisher'>publisher</span><span class='period'>.</span><span class='id identifier rubyid_name'>name</span>
180
+
181
+
182
+ <span class='comment'>## Note that some ActiveRecord constructs surface real table names,
183
+ </span><span class='comment'>## which can look awkward in code when working with tables with non-Railsy names:
184
+ </span><span class='comment'>## (the uppercase &quot;P&quot; in &quot;Publishers&quot; below makes it look like a class reference)
185
+ </span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_joins'>joins</span><span class='lparen'>(</span><span class='symbol'>:Publishers</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_where'>where</span><span class='lparen'>(</span><span class='label'>Publishers:</span> <span class='lbrace'>{</span> <span class='label'>name:</span> <span class='id identifier rubyid_test_value'>test_value</span> <span class='rbrace'>}</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_all'>all</span>
186
+ </code></pre>
187
+ <hr>
188
+
189
+ <h4 id="label-Automodel+With+Namespacing">Automodel With Namespacing</h4>
190
+
191
+ <p>If you&#39;re worried about model name collisions (or just want to keep the
192
+ global namespace tidy), Automodel can define all of the new model classes
193
+ under a module.</p>
194
+
195
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_automodel'><span class='object_link'><a href="top-level-namespace.html#automodel-instance_method" title="#automodel (method)">automodel</a></span></span> <span class='label'>adapter:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>postgresql</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
196
+ <span class='label'>encoding:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>unicode</span><span class='tstring_end'>&#39;</span></span> <span class='comma'>,</span>
197
+ <span class='label'>host:</span> <span class='id identifier rubyid_hostname'>hostname</span> <span class='comma'>,</span>
198
+ <span class='label'>port:</span> <span class='id identifier rubyid_port_number'>port_number</span> <span class='comma'>,</span>
199
+ <span class='label'>username:</span> <span class='id identifier rubyid_username'>username</span> <span class='comma'>,</span>
200
+ <span class='label'>password:</span> <span class='id identifier rubyid_password'>password</span> <span class='comma'>,</span>
201
+ <span class='label'>database:</span> <span class='id identifier rubyid_database_name'>database_name</span><span class='comma'>,</span>
202
+ <span class='label'>namespace:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>ExternalDB</span><span class='tstring_end'>&#39;</span></span>
203
+
204
+ <span class='comment'>## Now you can do everything you&#39;d expect, but the models are namespaced under ExternalDB.
205
+ </span><span class='const'>ExternalDB</span><span class='op'>::</span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_find'>find</span><span class='lparen'>(</span><span class='int'>5</span><span class='rparen'>)</span> <span class='comment'>## =&gt; Book #5
206
+ </span><span class='const'>ExternalDB</span><span class='op'>::</span><span class='const'>Book</span><span class='period'>.</span><span class='id identifier rubyid_take'>take</span><span class='period'>.</span><span class='id identifier rubyid_author'>author</span><span class='period'>.</span><span class='id identifier rubyid_class'>class</span> <span class='comment'>## =&gt; ExternalDB::Author
207
+ </span></code></pre>
208
+ <hr>
209
+
210
+ <p><a href="http://nestor-custodio.github.io/automodel/Automodel.html">Consult
211
+ the repo docs for the full Automodel documentation.</a></p>
212
+
213
+ <h2 id="label-FAQs">FAQs</h2>
214
+ <ul><li>
215
+ <h5 id="label-Do+I+have+to+add+anything+to+my+Gemfile+besides+-27automodel-27-3F">Do I have to add anything to my Gemfile besides <code>&#39;automodel&#39;</code>?</h5>
216
+
217
+ <p>Only if you want to use connection adapters that are not yet part of your
218
+ gemset. (e.g. Don&#39;t expect to be able to connect to a MySQL database
219
+ without having added <code>&#39;mysql2&#39;</code> to your Gemfile.</p>
220
+ </li><li>
221
+ <h5 id="label-But+what+about+my+application-27s+own+models-3F">But what about my application&#39;s own models?</h5>
222
+
223
+ <p>You can use Automodel <strong>and</strong> continue to use your
224
+ application&#39;s own models without changing a single line of code.</p>
225
+ </li><li>
226
+ <h5 id="label-Can+I+Automodel+more+than+one+database-3F">Can I Automodel more than one database?</h5>
227
+
228
+ <p>Yes! You can Automodel as many databases with as many different adapters
229
+ as you like. Automodel takes care of connecting to the various databases
230
+ and managing their connection pools for you.</p>
231
+ </li><li>
232
+ <h5 id="label-What+about+model+name+collisions-3F">What about model name collisions?</h5>
233
+
234
+ <p>If an <code>automodel</code> call will result in a class name collision,
235
+ an Automodel::NameCollisionError is raised <em>before</em> any classes are
236
+ clobbered.</p>
237
+ </li><li>
238
+ <h5 id="label-What+if+I+want+custom+methods+for+certain+models-3F">What if I want custom methods for certain models?</h5>
239
+
240
+ <p>You can either monkey-patch your methods onto the applicable
241
+ Automodel-generated classes once they&#39;ve been defined, or you can
242
+ monkey-patch the method onto the connection handler class returned by the
243
+ <code>automodel</code> call itself, which will make it available for all
244
+ models generated <em>by that call</em>.</p>
245
+ </li><li>
246
+ <h5 id="label-What+if+I-27m+using+ActiveRecord+but+not+Rails-3F">What if I&#39;m using ActiveRecord but not Rails?</h5>
247
+
248
+ <p>That&#39;s no problem at all! The <strong>automodel</strong> gem&#39;s
249
+ <em>only</em> dependency is ActiveRecord – not Rails. Adding
250
+ <code>&#39;automodel&#39;</code> to your Gemfile (along with any relevant
251
+ connection adapters, of course) is all you need to make use of the tool in
252
+ your vanilla-Ruby project. Just be mindful that – since
253
+ “config/database.yml” isn&#39;t available (as you&#39;re not using Rails) –
254
+ you&#39;ll always need to pass in a full connection spec to your
255
+ <code>automodel</code> calls (as in the very first example, under
256
+ <em>“Connecting To The External Database”</em> above).</p>
257
+ </li></ul>
258
+
259
+ <h2 id="label-Feature+Roadmap+-2F+Future+Development">Feature Roadmap / Future Development</h2>
260
+
261
+ <p>Additional features/options coming in the future:</p>
262
+ <ul><li>
263
+ <p><strong>Naming</strong>: Better generation of Railsy names for
264
+ <code>:date</code>/<code>:datetime</code> column types.</p>
265
+ </li><li>
266
+ <p><strong>Reads</strong>: Support for <code>#find</code> on tables with
267
+ composite primary keys.</p>
268
+ </li><li>
269
+ <p><strong>Writes</strong>: Better handling of missing
270
+ <code>created_at</code>/<code>updated_at</code> columns on record
271
+ creation/updates.</p>
272
+ </li><li>
273
+ <p><strong>Traversal</strong>: Support for <code>has_many</code> relations
274
+ (only <code>belongs_to</code> is currently supported).</p>
275
+ </li><li>
276
+ <p><strong>Traversal</strong>: Support for self-referential foreign keys.</p>
277
+ </li><li>
278
+ <p><strong>Traversal</strong>: Support for multiple relations to the same
279
+ target model.</p>
280
+ </li></ul>
281
+
282
+ <h2 id="label-Contribution+-2F+Development">Contribution / Development</h2>
283
+
284
+ <p>Bug reports and pull requests are welcome on GitHub at <a
285
+ href="https://github.com/nestor-custodio/automodel">github.com/nestor-custodio/automodel</a>.</p>
286
+
287
+ <p>After checking out the repo, run <code>bin/setup</code> to install
288
+ dependencies. Then, run <code>rake spec</code> to run the tests. You can
289
+ also run <code>bin/console</code> for an interactive prompt that will allow
290
+ you to experiment.</p>
291
+
292
+ <p>Linting is courtesy of <a
293
+ href="https://github.com/bbatsov/rubocop">Rubocop</a> and documentation is
294
+ built using <a href="https://yardoc.org/">Yard</a>. Neither is included in
295
+ the Gemspec; you&#39;ll need to install these locally (<code>gem install
296
+ rubocop yard</code>) to take advantage.</p>
297
+
298
+ <h2 id="label-License">License</h2>
299
+
300
+ <p>The gem is available as open source under the terms of the <a
301
+ href="https://opensource.org/licenses/MIT">MIT License</a>.</p>
302
+ </div></div>
303
+
304
+ <div id="footer">
305
+ Generated on Fri Jun 15 16:46:47 2018 by
306
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
307
+ 0.9.14 (ruby-2.5.1).
308
+ </div>
309
+
310
+ </div>
311
+ </body>
312
+ </html>