KirbyBase 2.6 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/README +65 -67
  2. data/bin/kbserver.rb +18 -18
  3. data/changes.txt +144 -137
  4. data/examples/aaa_try_this_first/kbtest.rb +237 -237
  5. data/examples/add_column_test/add_column_test.rb +27 -27
  6. data/examples/calculated_field_test/calculated_field_test.rb +51 -51
  7. data/examples/change_column_type_test/change_column_type_test.rb +25 -25
  8. data/examples/column_required_test/column_required_test.rb +44 -44
  9. data/examples/crosstab_test/crosstab_test.rb +100 -100
  10. data/examples/csv_import_test/csv_import_test.rb +31 -31
  11. data/examples/csv_import_test/plane.csv +11 -11
  12. data/examples/default_value_test/default_value_test.rb +54 -54
  13. data/examples/drop_column_test/drop_column_test.rb +24 -24
  14. data/examples/indexes_test/add_index_test.rb +46 -46
  15. data/examples/indexes_test/drop_index_test.rb +65 -65
  16. data/examples/indexes_test/index_test.rb +94 -94
  17. data/examples/kbserver_as_win32_service/kbserver_daemon.rb +47 -47
  18. data/examples/kbserver_as_win32_service/kbserverctl.rb +75 -75
  19. data/examples/link_many_test/link_many_test.rb +70 -70
  20. data/examples/lookup_field_test/lookup_field_test.rb +55 -55
  21. data/examples/lookup_field_test/lookup_field_test_2.rb +62 -62
  22. data/examples/lookup_field_test/the_hal_fulton_feature_test.rb +69 -69
  23. data/examples/many_to_many_test/many_to_many_test.rb +65 -65
  24. data/examples/memo_test/memo_test.rb +74 -74
  25. data/examples/record_class_test/record_class_test.rb +77 -77
  26. data/examples/record_class_test/record_class_test2.rb +31 -31
  27. data/examples/rename_column_test/rename_column_test.rb +45 -45
  28. data/examples/rename_table_test/rename_table_test.rb +38 -38
  29. data/examples/yaml_field_test/yaml_field_test.rb +47 -47
  30. data/kirbybaserubymanual.html +2324 -2324
  31. data/lib/kirbybase.rb +3907 -3880
  32. data/test/tc_local_table.rb +108 -108
  33. metadata +56 -54
@@ -1,38 +1,38 @@
1
- # This script is an example of how to rename a table.
2
- #
3
- require 'kirbybase'
4
-
5
- db = KirbyBase.new
6
-
7
- # If tables exist, delete them.
8
- db.drop_table(:address_book) if db.table_exists?(:address_book)
9
- db.drop_table(:contact_list) if db.table_exists?(:contact_list)
10
-
11
- address_book_tbl = db.create_table(:address_book,
12
- :firstname, :String, :lastname, :String, :street_address, :String,
13
- :city, :String, :phone, :String, :category, :String
14
- )
15
-
16
- # Insert some contact info records.
17
- address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
18
- '111-111-1111', 'Super Hero')
19
- address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
20
- '222-222-2222', 'Cartoon Character')
21
- address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
22
- 'Washington', '333-333-3333', 'President')
23
- address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
24
- 'Any City', '444-444-4444', 'Super Hero')
25
-
26
- address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
27
- puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
28
- }
29
- puts;puts
30
-
31
- contact_list_tbl = db.rename_table(:address_book, :contact_list)
32
-
33
- contact_list_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
34
- puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
35
- }
36
- puts;puts
37
-
38
- p db.tables
1
+ # This script is an example of how to rename a table.
2
+ #
3
+ require 'kirbybase'
4
+
5
+ db = KirbyBase.new
6
+
7
+ # If tables exist, delete them.
8
+ db.drop_table(:address_book) if db.table_exists?(:address_book)
9
+ db.drop_table(:contact_list) if db.table_exists?(:contact_list)
10
+
11
+ address_book_tbl = db.create_table(:address_book,
12
+ :firstname, :String, :lastname, :String, :street_address, :String,
13
+ :city, :String, :phone, :String, :category, :String
14
+ )
15
+
16
+ # Insert some contact info records.
17
+ address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
18
+ '111-111-1111', 'Super Hero')
19
+ address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
20
+ '222-222-2222', 'Cartoon Character')
21
+ address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
22
+ 'Washington', '333-333-3333', 'President')
23
+ address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
24
+ 'Any City', '444-444-4444', 'Super Hero')
25
+
26
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
27
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
28
+ }
29
+ puts;puts
30
+
31
+ contact_list_tbl = db.rename_table(:address_book, :contact_list)
32
+
33
+ contact_list_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
34
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
35
+ }
36
+ puts;puts
37
+
38
+ p db.tables
@@ -1,47 +1,47 @@
1
- #Test of YAML field type.
2
-
3
- require 'kirbybase'
4
-
5
- # To run local, single-user, uncomment next line.
6
- db = KirbyBase.new
7
-
8
- # To run as a client in a multi-user environment, uncomment next line.
9
- # Also, make sure kbserver.rb is running.
10
- #db = KirbyBase.new do |d|
11
- # d.connect_type = :client
12
- # d.host = 'localhost'
13
- # d.port = 44444
14
- #end
15
-
16
- # If table exists, delete it.
17
- db.drop_table(:pet) if db.table_exists?(:pet)
18
-
19
- # Create a table.
20
- pet_tbl = db.create_table(:pet, :name, :String, :pet_type, :String,
21
- :born, :Date, :characteristics, :YAML)
22
-
23
- pet_tbl.insert('Kirby', 'dog', Date.new(2002, 06, 01),
24
- ['cute', 'stinky', 4, 55.6])
25
- pet_tbl.insert('Mojo', 'cat', Date.new(2000, 04, 01),
26
- ['cute', 'soft', '6', 12.25])
27
- pet_tbl.insert('Goldy', 'fish', Date.new(2004, 10, 10),
28
- [])
29
-
30
- pet_tbl.select.each { |r|
31
- puts '%s %s' % [r.name, r.characteristics[1]]
32
- }
33
-
34
- puts
35
-
36
- pet_tbl.select { |r| r.characteristics.include?('stinky') }.each { |r|
37
- puts '%s smells like a dog!' % r.name
38
- }
39
-
40
- pet_tbl.update { |r| r.name == 'Goldy' }.set(
41
- :characteristics => ['small', 'slimy', 2, 0.02])
42
-
43
- puts
44
- pet_tbl.select.each { |r|
45
- puts '%s %s' % [r.name, r.characteristics.join(' ')]
46
- }
47
-
1
+ #Test of YAML field type.
2
+
3
+ require 'kirbybase'
4
+
5
+ # To run local, single-user, uncomment next line.
6
+ db = KirbyBase.new
7
+
8
+ # To run as a client in a multi-user environment, uncomment next line.
9
+ # Also, make sure kbserver.rb is running.
10
+ #db = KirbyBase.new do |d|
11
+ # d.connect_type = :client
12
+ # d.host = 'localhost'
13
+ # d.port = 44444
14
+ #end
15
+
16
+ # If table exists, delete it.
17
+ db.drop_table(:pet) if db.table_exists?(:pet)
18
+
19
+ # Create a table.
20
+ pet_tbl = db.create_table(:pet, :name, :String, :pet_type, :String,
21
+ :born, :Date, :characteristics, :YAML)
22
+
23
+ pet_tbl.insert('Kirby', 'dog', Date.new(2002, 06, 01),
24
+ ['cute', 'stinky', 4, 55.6])
25
+ pet_tbl.insert('Mojo', 'cat', Date.new(2000, 04, 01),
26
+ ['cute', 'soft', '6', 12.25])
27
+ pet_tbl.insert('Goldy', 'fish', Date.new(2004, 10, 10),
28
+ [])
29
+
30
+ pet_tbl.select.each { |r|
31
+ puts '%s %s' % [r.name, r.characteristics[1]]
32
+ }
33
+
34
+ puts
35
+
36
+ pet_tbl.select { |r| r.characteristics.include?('stinky') }.each { |r|
37
+ puts '%s smells like a dog!' % r.name
38
+ }
39
+
40
+ pet_tbl.update { |r| r.name == 'Goldy' }.set(
41
+ :characteristics => ['small', 'slimy', 2, 0.02])
42
+
43
+ puts
44
+ pet_tbl.select.each { |r|
45
+ puts '%s %s' % [r.name, r.characteristics.join(' ')]
46
+ }
47
+
@@ -1,2324 +1,2324 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
- "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
- <head>
5
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
- <meta name="generator" content="AsciiDoc 7.0.2" />
7
- <style type="text/css">
8
- /* Debug borders */
9
- p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
10
- /*
11
- border: 1px solid red;
12
- */
13
- }
14
-
15
- body {
16
- margin: 1em 5% 1em 5%;
17
- }
18
-
19
- a { color: blue; }
20
- a:visited { color: fuchsia; }
21
-
22
- em {
23
- font-style: italic;
24
- }
25
-
26
- strong {
27
- font-weight: bold;
28
- }
29
-
30
- tt {
31
- color: navy;
32
- }
33
-
34
- h1, h2, h3, h4, h5, h6 {
35
- color: #527bbd;
36
- font-family: sans-serif;
37
- margin-top: 1.2em;
38
- margin-bottom: 0.5em;
39
- line-height: 1.3;
40
- }
41
-
42
- h1 {
43
- border-bottom: 2px solid silver;
44
- }
45
- h2 {
46
- border-bottom: 2px solid silver;
47
- padding-top: 0.5em;
48
- }
49
-
50
- div.sectionbody {
51
- font-family: serif;
52
- margin-left: 0;
53
- }
54
-
55
- hr {
56
- border: 1px solid silver;
57
- }
58
-
59
- p {
60
- margin-top: 0.5em;
61
- margin-bottom: 0.5em;
62
- }
63
-
64
- pre {
65
- padding: 0;
66
- margin: 0;
67
- }
68
-
69
- span#author {
70
- color: #527bbd;
71
- font-family: sans-serif;
72
- font-weight: bold;
73
- font-size: 1.2em;
74
- }
75
- span#email {
76
- }
77
- span#revision {
78
- font-family: sans-serif;
79
- }
80
-
81
- div#footer {
82
- font-family: sans-serif;
83
- font-size: small;
84
- border-top: 2px solid silver;
85
- padding-top: 0.5em;
86
- margin-top: 4.0em;
87
- }
88
- div#footer-text {
89
- float: left;
90
- padding-bottom: 0.5em;
91
- }
92
- div#footer-badges {
93
- float: right;
94
- padding-bottom: 0.5em;
95
- }
96
-
97
- div#preamble,
98
- div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
99
- div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
100
- div.admonitionblock {
101
- margin-right: 10%;
102
- margin-top: 1.5em;
103
- margin-bottom: 1.5em;
104
- }
105
- div.admonitionblock {
106
- margin-top: 2.5em;
107
- margin-bottom: 2.5em;
108
- }
109
-
110
- div.content { /* Block element content. */
111
- padding: 0;
112
- }
113
-
114
- /* Block element titles. */
115
- div.title, caption.title {
116
- font-family: sans-serif;
117
- font-weight: bold;
118
- text-align: left;
119
- margin-top: 1.0em;
120
- margin-bottom: 0.5em;
121
- }
122
- div.title + * {
123
- margin-top: 0;
124
- }
125
-
126
- td div.title:first-child {
127
- margin-top: 0.0em;
128
- }
129
- div.content div.title:first-child {
130
- margin-top: 0.0em;
131
- }
132
- div.content + div.title {
133
- margin-top: 0.0em;
134
- }
135
-
136
- div.sidebarblock > div.content {
137
- background: #ffffee;
138
- border: 1px solid silver;
139
- padding: 0.5em;
140
- }
141
-
142
- div.listingblock > div.content {
143
- border: 1px solid silver;
144
- background: #f4f4f4;
145
- padding: 0.5em;
146
- }
147
-
148
- div.quoteblock > div.content {
149
- padding-left: 2.0em;
150
- }
151
- div.quoteblock .attribution {
152
- text-align: right;
153
- }
154
-
155
- div.admonitionblock .icon {
156
- vertical-align: top;
157
- font-size: 1.1em;
158
- font-weight: bold;
159
- text-decoration: underline;
160
- color: #527bbd;
161
- padding-right: 0.5em;
162
- }
163
- div.admonitionblock td.content {
164
- padding-left: 0.5em;
165
- border-left: 2px solid silver;
166
- }
167
-
168
- div.exampleblock > div.content {
169
- border-left: 2px solid silver;
170
- padding: 0.5em;
171
- }
172
-
173
- div.verseblock div.content {
174
- white-space: pre;
175
- }
176
-
177
- div.imageblock div.content { padding-left: 0; }
178
- div.imageblock img { border: 1px solid silver; }
179
- span.image img { border-style: none; }
180
-
181
- dl {
182
- margin-top: 0.8em;
183
- margin-bottom: 0.8em;
184
- }
185
- dt {
186
- margin-top: 0.5em;
187
- margin-bottom: 0;
188
- font-style: italic;
189
- }
190
- dd > *:first-child {
191
- margin-top: 0;
192
- }
193
-
194
- ul, ol {
195
- list-style-position: outside;
196
- }
197
- ol.olist2 {
198
- list-style-type: lower-alpha;
199
- }
200
-
201
- div.tableblock > table {
202
- border-color: #527bbd;
203
- border-width: 3px;
204
- }
205
- thead {
206
- font-family: sans-serif;
207
- font-weight: bold;
208
- }
209
- tfoot {
210
- font-weight: bold;
211
- }
212
-
213
- div.hlist {
214
- margin-top: 0.8em;
215
- margin-bottom: 0.8em;
216
- }
217
- td.hlist1 {
218
- vertical-align: top;
219
- font-style: italic;
220
- padding-right: 0.8em;
221
- }
222
- td.hlist2 {
223
- vertical-align: top;
224
- }
225
-
226
- @media print {
227
- div#footer-badges { display: none; }
228
- }
229
- /* Workarounds for IE6's broken and incomplete CSS2. */
230
-
231
- div.sidebar-content {
232
- background: #ffffee;
233
- border: 1px solid silver;
234
- padding: 0.5em;
235
- }
236
- div.sidebar-title, div.image-title {
237
- font-family: sans-serif;
238
- font-weight: bold;
239
- margin-top: 0.0em;
240
- margin-bottom: 0.5em;
241
- }
242
-
243
- div.listingblock div.content {
244
- border: 1px solid silver;
245
- background: #f4f4f4;
246
- padding: 0.5em;
247
- }
248
-
249
- div.quoteblock-content {
250
- padding-left: 2.0em;
251
- }
252
-
253
- div.exampleblock-content {
254
- border-left: 2px solid silver;
255
- padding-left: 0.5em;
256
- }
257
- </style>
258
- <title>KirbyBase Manual (Ruby Version)</title>
259
- </head>
260
- <body>
261
- <div id="header">
262
- <h1>KirbyBase Manual (Ruby Version)</h1>
263
- <span id="author">Jamey Cribbs</span><br />
264
- <span id="email"><tt>&lt;<a href="mailto:jcribbs@netpromi.com">jcribbs@netpromi.com</a>&gt;</tt></span><br />
265
- v2.6 June 2006
266
- </div>
267
- <div id="preamble">
268
- <div class="sectionbody">
269
- <div class="imageblock">
270
- <div class="content">
271
- <img src="images/kirby1.jpg" alt="images/kirby1.jpg"/>
272
- </div>
273
- <div class="image-title">Figure: Kirby, pictured here in attack mode.</div>
274
- </div>
275
- </div>
276
- </div>
277
- <h2>Table of Contents</h2>
278
- <div class="sectionbody">
279
- <div class="sidebarblock">
280
- <div class="sidebar-content">
281
- <ol>
282
- <li>
283
- <p>
284
- <a href="#introduction">Introduction</a>
285
- </p>
286
- </li>
287
- <li>
288
- <p>
289
- <a href="#connecting-to-a-database">Connecting to a database</a>
290
- </p>
291
- </li>
292
- <li>
293
- <p>
294
- <a href="#creating-a-new-table">Creating a new table</a>
295
- </p>
296
- <ol class="olist2">
297
- <li>
298
- <p>
299
- <a href="#field-types">Database field types</a>
300
- </p>
301
- </li>
302
- <li>
303
- <p>
304
- <a href="#recno">The recno field</a>
305
- </p>
306
- </li>
307
- <li>
308
- <p>
309
- <a href="#encrypt">Turning on encryption</a>
310
- </p>
311
- </li>
312
- <li>
313
- <p>
314
- <a href="#record-class">Specifying a custom record class</a>
315
- </p>
316
- </li>
317
- <li>
318
- <p>
319
- <a href="#defaults">Specifying default values</a>
320
- </p>
321
- </li>
322
- <li>
323
- <p>
324
- <a href="#requireds">Specifying required fields</a>
325
- </p>
326
- </li>
327
- <li>
328
- <p>
329
- <a href="#creating-indexes">Indexes</a>
330
- </p>
331
- </li>
332
- <li>
333
- <p>
334
- <a href="#a-note-about-indexes">A note about indexes</a>
335
- </p>
336
- </li>
337
- <li>
338
- <p>
339
- <a href="#creating-lookup-fields">Lookup Fields</a>
340
- </p>
341
- </li>
342
- <li>
343
- <p>
344
- <a href="#creating-link-many-fields">Link_many Fields</a>
345
- </p>
346
- </li>
347
- <li>
348
- <p>
349
- <a href="#creating-calculated-fields">Calculated Fields</a>
350
- </p>
351
- </li>
352
- </ol>
353
- </li>
354
- <li>
355
- <p>
356
- <a href="#obtaining-a-reference-to-an-existing-table">Obtaining a reference to an existing table</a>
357
- </p>
358
- </li>
359
- <li>
360
- <p>
361
- <a href="#insert-method">The insert method</a>
362
- </p>
363
- </li>
364
- <li>
365
- <p>
366
- <a href="#how-to-select-records">How to select records</a>
367
- </p>
368
- <ol class="olist2">
369
- <li>
370
- <p>
371
- <a href="#select-method">The select method</a>
372
- </p>
373
- </li>
374
- <li>
375
- <p>
376
- <a href="#selecting-by-index">Selecting by index</a>
377
- </p>
378
- </li>
379
- <li>
380
- <p>
381
- <a href="#selecting-by-recno-index">Selecting by :recno index</a>
382
- </p>
383
- </li>
384
- <li>
385
- <p>
386
- <a href="#selects-involving-lookups-or-link-manys">Selects involving Lookups or Link_manys</a>
387
- </p>
388
- </li>
389
- <li>
390
- <p>
391
- <a href="#a-note-about-nil-values">A note about nil values</a>
392
- </p>
393
- </li>
394
- </ol>
395
- </li>
396
- <li>
397
- <p>
398
- <a href="#kbresultset">KBResultSet</a>
399
- </p>
400
- <ol class="olist2">
401
- <li>
402
- <p>
403
- <a href="#sorting-a-result-set">Sorting a result set</a>
404
- </p>
405
- </li>
406
- <li>
407
- <p>
408
- <a href="#to-report">Producing a report from a result set</a>
409
- </p>
410
- </li>
411
- <li>
412
- <p>
413
- <a href="#crosstabs">CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</a>
414
- </p>
415
- </li>
416
- </ol>
417
- </li>
418
- <li>
419
- <p>
420
- <a href="#how-to-update-records">How to update records</a>
421
- </p>
422
- <ol class="olist2">
423
- <li>
424
- <p>
425
- <a href="#update-method">The update method</a>
426
- </p>
427
- </li>
428
- <li>
429
- <p>
430
- <a href="#set-method">The set method</a>
431
- </p>
432
- </li>
433
- <li>
434
- <p>
435
- <a href="#update-all-method">The update_all method</a>
436
- </p>
437
- </li>
438
- </ol>
439
- </li>
440
- <li>
441
- <p>
442
- <a href="#how-to-delete-records">How to delete records</a>
443
- </p>
444
- <ol class="olist2">
445
- <li>
446
- <p>
447
- <a href="#delete-method">The delete method</a>
448
- </p>
449
- </li>
450
- <li>
451
- <p>
452
- <a href="#clear-method">The clear method</a>
453
- </p>
454
- </li>
455
- </ol>
456
- </li>
457
- <li>
458
- <p>
459
- <a href="#pack-method">The pack method</a>
460
- </p>
461
- </li>
462
- <li>
463
- <p>
464
- <a href="#memo-and-blob-fields">Memo and Blob Fields</a>
465
- </p>
466
- </li>
467
- <li>
468
- <p>
469
- <a href="#misc-kirbybase-methods">Miscellaneous KirbyBase methods</a>
470
- </p>
471
- <ol class="olist2">
472
- <li>
473
- <p>
474
- <a href="#drop-table">KirbyBase#drop_table</a>
475
- </p>
476
- </li>
477
- <li>
478
- <p>
479
- <a href="#tables">KirbyBase#tables</a>
480
- </p>
481
- </li>
482
- <li>
483
- <p>
484
- <a href="#table-exists">KirbyBase#table_exists?</a>
485
- </p>
486
- </li>
487
- <li>
488
- <p>
489
- <a href="#rename-table">KirbyBase#rename_table</a>
490
- </p>
491
- </li>
492
- </ol>
493
- </li>
494
- <li>
495
- <p>
496
- <a href="#misc-kbtable-methods">Miscellaneous KBTable methods</a>
497
- </p>
498
- <ol class="olist2">
499
- <li>
500
- <p>
501
- <a href="#update-by-recno">KBTable#[]=</a>
502
- </p>
503
- </li>
504
- <li>
505
- <p>
506
- <a href="#get-by-recno">KBTable#[]</a>
507
- </p>
508
- </li>
509
- <li>
510
- <p>
511
- <a href="#field-names">KBTable#field_names</a>
512
- </p>
513
- </li>
514
- <li>
515
- <p>
516
- <a href="#field-types">KBTable#field_types</a>
517
- </p>
518
- </li>
519
- <li>
520
- <p>
521
- <a href="#total-recs">KBTable#total_recs</a>
522
- </p>
523
- </li>
524
- <li>
525
- <p>
526
- <a href="#import-csv">KBTable#import_csv</a>
527
- </p>
528
- </li>
529
- <li>
530
- <p>
531
- <a href="#add-column">KBTable#add_column</a>
532
- </p>
533
- </li>
534
- <li>
535
- <p>
536
- <a href="#drop-column">KBTable#drop_column</a>
537
- </p>
538
- </li>
539
- <li>
540
- <p>
541
- <a href="#rename-column">KBTable#rename_column</a>
542
- </p>
543
- </li>
544
- <li>
545
- <p>
546
- <a href="#change-column-type">KBTable#change_column_type</a>
547
- </p>
548
- </li>
549
- <li>
550
- <p>
551
- <a href="#change-column-default-value">KBTable#change_column_defaul_value</a>
552
- </p>
553
- </li>
554
- <li>
555
- <p>
556
- <a href="#change-column-required">KBTable#change_column_required</a>
557
- </p>
558
- </li>
559
- <li>
560
- <p>
561
- <a href="#add-index">KBTable#add_index</a>
562
- </p>
563
- </li>
564
- <li>
565
- <p>
566
- <a href="#drop-index">KBTable#drop_index</a>
567
- </p>
568
- </li>
569
- </ol>
570
- </li>
571
- <li>
572
- <p>
573
- <a href="#special-characters-in-data">Special characters in data</a>
574
- </p>
575
- </li>
576
- <li>
577
- <p>
578
- <a href="#table-structure">Table Structure</a>
579
- </p>
580
- </li>
581
- <li>
582
- <p>
583
- <a href="#server-notes">Server Notes</a>
584
- </p>
585
- </li>
586
- <li>
587
- <p>
588
- <a href="#tips-on-improving-performance">Tips on improving performance</a>
589
- </p>
590
- </li>
591
- <li>
592
- <p>
593
- <a href="#single-user-diagram">Single-user memory space diagram</a>
594
- </p>
595
- </li>
596
- <li>
597
- <p>
598
- <a href="#client-server-diagram">Client/Server memory space diagram</a>
599
- </p>
600
- </li>
601
- <li>
602
- <p>
603
- <a href="#license">License</a>
604
- </p>
605
- </li>
606
- <li>
607
- <p>
608
- <a href="#credits">Credits</a>
609
- </p>
610
- </li>
611
- </ol>
612
- </div></div>
613
- </div>
614
- <h2><a id="introduction"></a>Introduction</h2>
615
- <div class="sectionbody">
616
- <p>KirbyBase is a simple, pure-Ruby, flat-file database management system.
617
- Some of its features include:</p>
618
- <ul>
619
- <li>
620
- <p>
621
- Since KirbyBase is written in Ruby, it runs anywhere that Ruby runs. It
622
- is easy to distribute, since the entire DBMS is in one (approx. 100k) code
623
- file.
624
- </p>
625
- </li>
626
- <li>
627
- <p>
628
- All data is kept in plain-text, delimited files that can be edited by
629
- hand. This gives you the ability to make changes by just opening the file
630
- up in a text editor, or you can use another programming language to read the
631
- file in and do things with it.
632
- </p>
633
- </li>
634
- <li>
635
- <p>
636
- It can be used as an embedded database or in a client/server, multi-user
637
- mode. To switch from one mode to the other, you only have to change one
638
- line in your program. Included in the distribution is a sample database
639
- server script using DRb.
640
- </p>
641
- </li>
642
- <li>
643
- <p>
644
- Tables are kept on disk during use and accessed from disk when selecting,
645
- updating, inserting, and deleting records. Changes to a table are written
646
- immediately to disk. KirbyBase is not an "in-memory" database. Once you
647
- update the database in your program, you can be assured that the change has
648
- been saved to disk. The chance of lost data due to power interruptions, or
649
- disk crashes is much reduced. Also, since the entire database does not have
650
- to reside in memory at once, KirbyBase should run adequately on a
651
- memory-constrained system.
652
- </p>
653
- </li>
654
- <li>
655
- <p>
656
- You can specify the type of data that each field will hold. The available
657
- data types are: String, Integer, Float, Boolean, Time, Date, DateTime, Memo,
658
- Blob, and YAML.
659
- </p>
660
- </li>
661
- <li>
662
- <p>
663
- The query syntax is very "rubyish". Instead of having to use another
664
- language like SQL, you can express your query using Ruby code blocks.
665
- </p>
666
- </li>
667
- <li>
668
- <p>
669
- All inserted records have an auto-incrementing primary key that is
670
- guaranteed to uniquely identify the record throughout its lifetime.
671
- </p>
672
- </li>
673
- <li>
674
- <p>
675
- You can specify that the result set be sorted on multiple fields, each
676
- one either ascending or descending.
677
- </p>
678
- </li>
679
- <li>
680
- <p>
681
- You can specify that certain fields be indexed. Using an index in a select
682
- query can greatly improve performance on large tables (I've seen 10x speed
683
- improvements). Index maintenance is completely handled by KirbyBase.
684
- </p>
685
- </li>
686
- <li>
687
- <p>
688
- You can specify that a field has a "lookup table". Whenever that field is
689
- accessed, the corresponding record from the lookup table is automatically
690
- available.
691
- </p>
692
- </li>
693
- <li>
694
- <p>
695
- You can specify one-to-many links between tables, somewhat analogous to a
696
- "join" in SQL.
697
- </p>
698
- </li>
699
- <li>
700
- <p>
701
- You can create calculated fields that are computed at runtime.
702
- </p>
703
- </li>
704
- <li>
705
- <p>
706
- It is fairly fast, comparing favorably to SQLite.
707
- </p>
708
- </li>
709
- </ul>
710
- <p>In meeting your DBMS needs, KirbyBase fits in somewhere between plain
711
- text files and small SQL database management systems like SQLite and
712
- MySQL.</p>
713
- <div class="sidebarblock">
714
- <div class="sidebar-content">
715
- <div class="sidebar-title">Drop me a line!</div>
716
- <p>If you find a use for KirbyBase, please send me an email telling how you
717
- use it, whether it is ok for me to mention your application on the
718
- "KirbyBase Applications" webpage, and possibly a link to your application's
719
- webpage (if you have one).</p>
720
- </div></div>
721
- </div>
722
- <h2><a id="connecting-to-a-database"></a>Connecting to a database</h2>
723
- <div class="sectionbody">
724
- <p>To use Kirbybase, you first need to require the module:</p>
725
- <div class="listingblock">
726
- <div class="content">
727
- <pre><tt>require 'kirbybase'</tt></pre>
728
- </div></div>
729
- <p>Then create an instance:</p>
730
- <div class="listingblock">
731
- <div class="content">
732
- <pre><tt>db = KirbyBase.new</tt></pre>
733
- </div></div>
734
- <p>By default, the instance is a local connection using the same memory space
735
- as your application. To specify a client/server connection, it would look
736
- like this:</p>
737
- <div class="listingblock">
738
- <div class="content">
739
- <pre><tt>db = KirbyBase.new(:client, 'localhost', 44444)</tt></pre>
740
- </div></div>
741
- <p>Of course, you would substitute your server's ip address and port number.</p>
742
- <p>To specify a different location (other than the current directory) for the
743
- database files, you need to pass the location as an argument, like so:</p>
744
- <div class="listingblock">
745
- <div class="content">
746
- <pre><tt>db = KirbyBase.new(:local, nil, nil, './data')</tt></pre>
747
- </div></div>
748
- <p>KirbyBase treats every file in the specified directory that has the proper
749
- extension as a database table. The default extension is ".tbl". To specify
750
- a different extension, pass this as an argument, like so:</p>
751
- <div class="listingblock">
752
- <div class="content">
753
- <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.dat')</tt></pre>
754
- </div></div>
755
- <p>To specify a different location other than the current directory for any
756
- memo/blob files, you need to pass the location as an argument, like so:</p>
757
- <div class="listingblock">
758
- <div class="content">
759
- <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.tbl', './memos')</tt></pre>
760
- </div></div>
761
- <p>If you don't want KirbyBase to spend time initially creating all of the
762
- indexes for the tables in the database, you can pass true as the
763
- delay_index_creation argument:</p>
764
- <div class="listingblock">
765
- <div class="content">
766
- <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.tbl', './', true)</tt></pre>
767
- </div></div>
768
- <p>KirbyBase will skip initial index creation and will create a table's
769
- indexes when the table is first referenced.</p>
770
- <p>You can also specify the arguments via a code block. So, if you don't want
771
- to have to specify a bunch of arguments just to get to the one you want,
772
- put it in a code block attached to the method call. You could re-code the
773
- previous example like so:</p>
774
- <div class="listingblock">
775
- <div class="content">
776
- <pre><tt>db = KirbyBase.new { |d| d.delay_index_creation = true }</tt></pre>
777
- </div></div>
778
- </div>
779
- <h2><a id="creating-a-new-table"></a>Creating a new table</h2>
780
- <div class="sectionbody">
781
- <p>To create a new table, you specify the table name, and a name and type for
782
- each column. For example, to create a table containing information on World
783
- War II planes:</p>
784
- <div class="listingblock">
785
- <div class="content">
786
- <pre><tt>plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
787
- :role, :String, :speed, :Integer, :range, :Integer, :began_service, :Date,
788
- :still_flying, :Boolean)</tt></pre>
789
- </div></div>
790
- <div class="sidebarblock">
791
- <a id="field-types"></a>
792
- <div class="sidebar-content">
793
- <div class="sidebar-title">KirbyBase Field Types</div>
794
- <div class="admonitionblock">
795
- <table><tr>
796
- <td class="icon">
797
- <img src="./images/tip.png" alt="Tip" />
798
- </td>
799
- <td class="content">:String, :Integer, :Float, :Boolean(true/false), :Time, :Date,
800
- :DateTime, :Memo, :Blob, and :YAML.</td>
801
- </tr></table>
802
- </div>
803
- </div></div>
804
- <div class="sidebarblock">
805
- <a id="recno"></a>
806
- <div class="sidebar-content">
807
- <div class="sidebar-title">The recno field</div>
808
- <div class="admonitionblock">
809
- <table><tr>
810
- <td class="icon">
811
- <img src="./images/important.png" alt="Important" />
812
- </td>
813
- <td class="content">KirbyBase will automatically create a primary key field, called
814
- recno, with a type of :Integer, for each table. This field will be
815
- auto-incremented each time a record is inserted. You can use this field in
816
- select, update, and delete queries, but you can't modify this field.</td>
817
- </tr></table>
818
- </div>
819
- </div></div>
820
- <h3><a id="encrypt"></a>Turning on encryption</h3>
821
- <p>You can also specify whether the table should be encrypted. This will save
822
- the table to disk encrypted (more like obfuscated) using a Vignere Cipher.
823
- This is similar to rot13, but it uses a key to determine character
824
- substitution. Still, this encryption will only stymie the most casual
825
- of hackers. Do not rely on it to keep sensitive data safe! You specify
826
- encryption by using a code block attached to #create_table:</p>
827
- <div class="listingblock">
828
- <div class="content">
829
- <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
830
- t.encrypt = true
831
- end</tt></pre>
832
- </div></div>
833
- <h3><a id="record-class"></a>Specifying a custom record class</h3>
834
- <p>You can also specify that you want records of the table to be returned to
835
- you as instances of a class. To do this, simply define a class before you
836
- call #create_table. This class needs to have an accessor for each fieldname
837
- in the table.</p>
838
- <p>If this class has a class method, called #kb_create, KirbyBase, when
839
- creating each record of the result set, will call that method and pass it
840
- the field values of the result record. #kb_create will need to handle
841
- creating an instance of the record class itself.</p>
842
- <p>Here is an example of #kb_create in action:</p>
843
- <div class="listingblock">
844
- <div class="content">
845
- <pre><tt>class Foobar
846
- attr_accessor(:recno, :name, :country, :role, :speed, :range,
847
- :began_service, :still_flying, :alpha, :beta)
848
-
849
- def Foobar.kb_create(recno, name, country, role, speed, range,
850
- began_service, still_flying)
851
- name ||= 'No Name!'
852
- speed ||= 0
853
- began_service ||= Date.today
854
-
855
- Foobar.new do |x|
856
- x.recno = recno
857
- x.name = name
858
- x.country = country
859
- x.role = role
860
- x.speed = speed
861
- x.range = range
862
- x.began_service = began_service
863
- x.still_flying = still_flying
864
- end
865
- end
866
-
867
- def initialize(&amp;block)
868
- instance_eval(&amp;block)
869
- end
870
- end</tt></pre>
871
- </div></div>
872
- <p>Pass this class to #create_table in an attached code block, like so:</p>
873
- <div class="listingblock">
874
- <div class="content">
875
- <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
876
- t.record_class = Foobar
877
- end</tt></pre>
878
- </div></div>
879
- <p>Now, when you call #select, the result set will be made up of instances of
880
- Foobar, instead of the default, which is instances of Struct. This also
881
- works the other way. You can now specify instances of Foobar as input to
882
- the #insert, #update and #set methods. More on those methods below.</p>
883
- <p>If the custom record class does not respond to #kb_create, KirbyBase will
884
- call the class's #new method instead, passing it all of the field values.</p>
885
- <div class="sidebarblock">
886
- <div class="sidebar-content">
887
- <div class="admonitionblock">
888
- <table><tr>
889
- <td class="icon">
890
- <img src="./images/important.png" alt="Important" />
891
- </td>
892
- <td class="content">The #create_table method will return a reference to a KBTable
893
- instance. This is the only way, besides calling KirbyBase#get_table, that
894
- you can obtain a handle to a KBTable instance. You can not call KBTable#new
895
- directly.</td>
896
- </tr></table>
897
- </div>
898
- </div></div>
899
- <h3>Specifying Advanced Field Type Information</h3>
900
- <p>There are four types of advanced field type information that you can
901
- specify:
902
- Defaults, Requireds, Indexes and Extras (i.e. Lookup, Link_many,
903
- Calculated).</p>
904
- <h4><a id="defaults"></a>Default Field Values</h4>
905
- <p>Normally, when you insert a record, if you don't specify a value for a field
906
- or specify nil as the value, KirbyBase stores this as an empty string
907
- (i.e. "") in the table's physical file, and returns it as a nil value when
908
- you do a #select.</p>
909
- <p>However, you can tell KirbyBase that you want a column to have a default
910
- value. Only KBTable#insert is affected by default values. Default values
911
- do not apply to updating a record. So, for inserts, there are two cases
912
- where a default value, if one is specified, will be applied: (1) if nil
913
- is specified for a field's value, and (2) if no value is specified for a
914
- field.</p>
915
- <p>For example, to specify that the category column has a default value, you
916
- would code:</p>
917
- <div class="listingblock">
918
- <div class="content">
919
- <pre><tt>db.create_table(:addressbook, :firstname, :String,
920
- :lastname, :String, :phone_no, :String,
921
- :category, {:DataType=&gt;:String, :Default=&gt;'Business'})</tt></pre>
922
- </div></div>
923
- <p>Notice that, since we are specifying advanced field type information, we
924
- cannot just simply say :String for the second half of the field definition.
925
- Instead, we have to pass a hash, with a :DataType item set to :String.
926
- Next, because we are specifying a default value, we have to include a hash
927
- item called :Default with its value set to whatever we want the default to
928
- be. The default value must be of a type that is valid for the column.</p>
929
- <h4><a id="requireds"></a>Required Fields</h4>
930
- <p>Normally, when you insert or update a record, if you don't specify a value
931
- for a field or specify nil as the value, KirbyBase stores this as an empty
932
- string (i.e. "") in the table's physical file, and returns it as a nil
933
- value when you do a #select.</p>
934
- <p>However, you can tell KirbyBase that you want a column to be required
935
- (i.e. you must supply a value and it can't be nil). When a record is
936
- inserted or updated, an exception will be raised for any required field
937
- that has not been given a value or been given a nil value.</p>
938
- <p>For example, to specify that the category column is required, you would
939
- code:</p>
940
- <div class="listingblock">
941
- <div class="content">
942
- <pre><tt>db.create_table(:addressbook, :firstname, :String,
943
- :lastname, :String, :phone_no, :String,
944
- :category, {:DataType=&gt;:String, :Required=&gt;true})</tt></pre>
945
- </div></div>
946
- <p>Notice that, since we are specifying advanced field type information, we
947
- cannot just simply say :String for the second half of the field definition.
948
- Instead, we have to pass a hash, with a :DataType item set to :String.
949
- Next, because we are specifying that a column is required, we have to
950
- include a hash item called :Required with its value set to true.</p>
951
- <h4><a id="creating-indexes"></a>Indexes</h4>
952
- <p>Indexes are in-memory arrays that have an entry that corresponds to each
953
- table record, but just holds the field values specified when the index was
954
- created, plus the :recno of the actual table record. Because index arrays
955
- are smaller than the actual table and because they are in-memory instead of
956
- on-disk, using an index in a select query is usually much faster than
957
- selecting against the table itself, especially when the table is quite
958
- large.</p>
959
- <p>To specify that an index is to be created, you need to tell KirbyBase which
960
- fields are to be included in a particular index. You can have up to 5
961
- indexes per table. Indexes can either contain single or multiple fields.
962
- For example, to create an index on firstname and lastname for a table called
963
- :addressbook, you would code:</p>
964
- <div class="listingblock">
965
- <div class="content">
966
- <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
967
- :lastname, {:DataType=&gt;:String, :Index=&gt;1},
968
- :phone_no, :String)</tt></pre>
969
- </div></div>
970
- <p>Notice that, since we are specifying advanced field type information, we
971
- cannot just simply say :String for the second half of the field definition.
972
- Instead, we have to pass a hash, with a :DataType item set to :String.
973
- Next, because we are creating an index, we have to include a hash item
974
- called :Index with its value set from 1 to 5. For compound indexes, like
975
- the one in the above example, we need to make sure that all fields in the
976
- index have the same number. To have another index for a table, just make
977
- sure you increment the index number. So, for example, if we wanted to have
978
- another index for the :addressbook table on the field phone number, we would
979
- code:</p>
980
- <div class="listingblock">
981
- <div class="content">
982
- <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
983
- :lastname, {:DataType=&gt;:String, :Index=&gt;1},
984
- :phone_no, {:DataType=&gt;:String, :Index=&gt;2})</tt></pre>
985
- </div></div>
986
- <p>Notice how we just increment the index number to 2 for the :phone_no index.
987
- Since there are no other fields with the same index number, this will create
988
- an index with just the :phone_no field in it. You will see how to use
989
- indexes in your select queries later.</p>
990
- <div class="sidebarblock">
991
- <a id="a-note-about-indexes"></a>
992
- <div class="sidebar-content">
993
- <div class="sidebar-title">A note about indexes</div>
994
- <p>When KirbyBase initializes, it creates an instance for each table in
995
- the database. It also creates each index array for each indexed field in
996
- each table. So, if there are several large tables that have indexed fields,
997
- this database initialization process could take several seconds. I decided
998
- to have it operate this way, because I thought that it made more sense to
999
- have a user application wait once upon initialization, rather than have it
1000
- wait the first time a table is referenced. A user is more used to waiting
1001
- for an application to properly initialize, so this initial delay, I thought,
1002
- would feel more natural to the user, rather than a wait time in the middle
1003
- of the application.</p>
1004
- <p>If you find that this initial delay while indexes are created is
1005
- un-acceptable, you can pass delay_index_creation=true to KirbyBase.new.
1006
- This will bypass the initial index creation for all tables. Indexes for an
1007
- individual table will be created when the table is first referenced.</p>
1008
- <p>This is also an excellent reason to use the client/server capabilities of
1009
- KirbyBase. In client/server mode, the database initialization processing is
1010
- all done on the server, so, once this is done, any users starting their
1011
- client application and connecting to the server will experience no delay due
1012
- to index array creation.</p>
1013
- </div></div>
1014
- <h4><a id="creating-lookup-fields"></a>Lookup Fields</h4>
1015
- <p>Lookup fields are fields that hold a reference to a record in another table.
1016
- For example, say you have a table called :department that has fields called
1017
- :dept_id, :dept_name, and :manager. Now, let's say that you don't want the
1018
- :manager field to just hold the manager's name; you want it to point to the
1019
- manager's record in the :employee table, which has fields like
1020
- :employee_id, :firstname, :lastname, :ss_no, etc. What you want to do is
1021
- to tell KirbyBase that the :dept.manager field should actually point to the
1022
- manager's record in the :employee table (the "lookup" table). Here's how
1023
- you would do that:</p>
1024
- <div class="listingblock">
1025
- <div class="content">
1026
- <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
1027
- :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee, :employee_id]})</tt></pre>
1028
- </div></div>
1029
- <p>Ok, what we have done here is to tell KirbyBase a little bit "extra" about
1030
- the :manager field. We are specifying that whenever we ask for the value of
1031
- :manager, we want KirbyBase to do a #select against the :employee table that
1032
- compares the value of the :department.manager field to the value of the
1033
- :employee.employee_id field. If an index is available for the
1034
- :employee.employee_id field, KirbyBase will automatically use it.</p>
1035
- <p>There is a shortcut to specifying a lookup field. If the :employee_id field
1036
- has been designated a "key" field for the :employee table, we can even
1037
- shorten our code and KirbyBase will figure it all out. For example, if the
1038
- :employee table was created with this code:</p>
1039
- <div class="listingblock">
1040
- <div class="content">
1041
- <pre><tt>db.create_table(:employee, :employee_id, {:DataType=&gt;:String, :Key=&gt;true},
1042
- :firstname, :String, :lastname, :String)</tt></pre>
1043
- </div></div>
1044
- <p>Then the field definition for :manager could be re-written as:</p>
1045
- <div class="listingblock">
1046
- <div class="content">
1047
- <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
1048
- :manager, :employee)</tt></pre>
1049
- </div></div>
1050
- <p>KirbyBase will figure out that you want to compare :department.manager to
1051
- :employee.employee_id.</p>
1052
- <div class="sidebarblock">
1053
- <div class="sidebar-content">
1054
- <div class="admonitionblock">
1055
- <table><tr>
1056
- <td class="icon">
1057
- <img src="./images/important.png" alt="Important" />
1058
- </td>
1059
- <td class="content">In order to use the shortcut when specifying a lookup field, the
1060
- lookup table it is pointing to <strong>must</strong> already exist. This is so that
1061
- KirbyBase can do the defaulting magic.</td>
1062
- </tr></table>
1063
- </div>
1064
- </div></div>
1065
- <h4><a id="creating-link-many-fields"></a>Link_many Fields</h4>
1066
- <p>When you specify that a field has a Link_many, you are telling KirbyBase
1067
- that you want to create a one-to-many link between this field and a subset
1068
- of records from another table.</p>
1069
- <p>For example, say you are creating an order entry system for your business.
1070
- You have a master table called :orders that holds one record for each
1071
- customer order that is placed. It has fields like: :order_id, :cust_id,
1072
- :order_date, etc.</p>
1073
- <p>Now, you also need a table that is going to have a record for each detail
1074
- item type ordered. Let's call it :order_items and some of its fields would
1075
- be: :item_no, :qty, :order_id.</p>
1076
- <p>Notice that the detail table has a field called :order_id. This will hold
1077
- the order_id linking it back to the :orders.order_id table. If a customer
1078
- order's only one type of item, then there will only be one record in the
1079
- :order_items table that has that order_id. But, if the customer places an
1080
- order for many different types of items, there will be many records in the
1081
- :order_items table that have the same order_id. That's why we say that
1082
- there is a "one to many" link between the master (or parent) table, :orders,
1083
- and the detail (or child) table, :order_items.</p>
1084
- <p>When we select an :order record, we want the ability to also select all the
1085
- detail records from the :order_items table that belong to that order. We do
1086
- this by telling KirbyBase about the one-to-many link between the two
1087
- tables. Here's how:</p>
1088
- <div class="listingblock">
1089
- <div class="content">
1090
- <pre><tt>db.create_table(:orders, :order_id, :Integer, :cust_id, :Integer,
1091
- :order_date, :Date, :items, {:DataType=&gt;:ResultSet, :Link_many=&gt;[:order_id,
1092
- :order_items, :order_id]})
1093
-
1094
- db.create_table(:order_items, :item_no, :Integer, :qty, :Integer,
1095
- :order_id, :Integer)</tt></pre>
1096
- </div></div>
1097
- <p>Now, look at the :Link_many item in the field type definition hash in the
1098
- above example. We are specifying that a field, called :items, be created
1099
- with a field type of :ResultSet. We tell KirbyBase that, when we ask for
1100
- the value of :items, it should do a #select on :order_items and return a
1101
- KBResultSet that contains :order_items whose :order_id field (the last item
1102
- in the array above), equals the value of the :orders.order_id field (the
1103
- first item of the array above).</p>
1104
- <p>If you opened up the :orders table file in a text editor, you would notice
1105
- that, for each record, the :items field is blank. No data is ever stored in
1106
- this field, since its value is always computed at runtime.</p>
1107
- <h4><a id="creating-calculated-fields"></a>Calculated Fields</h4>
1108
- <p>When you specify that a field is a Calculated field, you are telling
1109
- KirbyBase to compute the value of the field at runtime, based on the code
1110
- string that you pass it at table creation time.</p>
1111
- <p>For example. let's say you have a table that is going to track your
1112
- purchases. It will have fields like :purchase_date, :description, :qty, and
1113
- :price.</p>
1114
- <p>Let's say that you want to have a "virtual" field, called :total_cost, that
1115
- is the result of quantity multiplied by price. You want this field
1116
- calculated at runtime, so that if you change a record's quantity or price,
1117
- the :total_cost field will automatically reflect the changes.
1118
- Here's how you would define this table:</p>
1119
- <div class="listingblock">
1120
- <div class="content">
1121
- <pre><tt>db.create_table(:purchases, :purchase_date, :Date, :description, :String,
1122
- :qty, :Integer, :price, :Float, :total_cost, {:DataType=&gt;:Float,
1123
- :Calculated=&gt;'qty*price'})</tt></pre>
1124
- </div></div>
1125
- <p>See how we tell KirbyBase how to calculate the field? By multiplying the
1126
- :qty field by the :price field.</p>
1127
- <p>If you opened up the :purchases file in a text editor, you would notice
1128
- that, for each record, the :total_cost field is blank. No data is ever
1129
- stored in this field, since its value is always computed at runtime.</p>
1130
- </div>
1131
- <h2><a id="obtaining-a-reference-to-an-existing-table"></a>Obtaining a reference to an existing table</h2>
1132
- <div class="sectionbody">
1133
- <p>If a table already exists and you need to get a reference to it so that you
1134
- can insert, select, etc., you would call the #get_table method from your
1135
- KirbyBase instance. This is how to obtain a handle to an existing table.
1136
- You cannot call KBTable#new directly.</p>
1137
- <div class="listingblock">
1138
- <div class="content">
1139
- <pre><tt>plane_tbl_another_reference = db.get_table(:plane)</tt></pre>
1140
- </div></div>
1141
- <p>Then, you can use it just like you would use a reference you got when
1142
- you created a new table.</p>
1143
- </div>
1144
- <h2><a id="insert-method"></a>The insert method</h2>
1145
- <div class="sectionbody">
1146
- <p>To insert records into a table, you use the insert method. You can use an
1147
- array, a hash, a struct, a code block, or an instance of the table's custom
1148
- record class to specify the insert values.</p>
1149
- <h3>Insert a record using an array for the input values:</h3>
1150
- <div class="listingblock">
1151
- <div class="content">
1152
- <pre><tt>plane_tbl.insert('FW-190', 'Germany', 'Fighter', 399, 499,
1153
- Date.new(1942,12,1), false)</tt></pre>
1154
- </div></div>
1155
- <p>The length of the data array must equal the number of columns in the table,
1156
- <strong>not</strong> including the :recno column. Also, the data types must match. In the
1157
- above example, specifying "399", instead of 399, would have resulted in an
1158
- error.</p>
1159
- <h3>Insert a record using a hash for the input values:</h3>
1160
- <div class="listingblock">
1161
- <div class="content">
1162
- <pre><tt>plane_tbl.insert(:name='P-51', :country='USA', :role='Fighter', :speed=403,
1163
- :range=1201, :began_service=Date.new(1943,6,24), :still_flying=true)</tt></pre>
1164
- </div></div>
1165
- <h3>Insert a record using a Struct for the input values:</h3>
1166
- <div class="listingblock">
1167
- <div class="content">
1168
- <pre><tt>InputRec = Struct.new(:name, :country, :role, :speed, :range,
1169
- :began_service, :still_flying)
1170
- rec = InputRec.new('P-47', 'USA', 'Fighter', 365, 888, Date.new(1943,3,12),
1171
- false)
1172
-
1173
- plane_tbl.insert(rec)</tt></pre>
1174
- </div></div>
1175
- <h3>Insert a record using a code block for the input values:</h3>
1176
- <div class="listingblock">
1177
- <div class="content">
1178
- <pre><tt>plane_tbl.insert do |r|
1179
- r.name = 'B-17'
1180
- r.country = 'USA'
1181
- r.role = 'Bomber'
1182
- r.speed = 315
1183
- r.range = 1400
1184
- r.began_service = Date.new(1937, 5, 1)
1185
- r.still_flying = true
1186
- end</tt></pre>
1187
- </div></div>
1188
- <h3>Insert a record using an instance of the table's custom record class:</h3>
1189
- <div class="listingblock">
1190
- <div class="content">
1191
- <pre><tt>foo = Foobar.new do |x|
1192
- x.name = 'Spitfire'
1193
- x.country = 'Great Britain'
1194
- x.role = 'Fighter'
1195
- x.speed = 333
1196
- x.range = 454
1197
- x.began_service = Date.new(1936, 1, 1)
1198
- x.still_flying = true
1199
- x.alpha = "This variable won't be stored in KirbyBase."
1200
- x.beta = 'Neither will this one.'
1201
- end
1202
-
1203
- plane_tbl.insert(foo)</tt></pre>
1204
- </div></div>
1205
- <div class="sidebarblock">
1206
- <div class="sidebar-content">
1207
- <div class="admonitionblock">
1208
- <table><tr>
1209
- <td class="icon">
1210
- <img src="./images/note.png" alt="Note" />
1211
- </td>
1212
- <td class="content">The #insert method will return the record number of the newly created
1213
- record. This is an auto-incremented integer generated by KirbyBase. This
1214
- number will <strong>never</strong> change for the record and can be used as a unique
1215
- identifier for the record.</td>
1216
- </tr></table>
1217
- </div>
1218
- </div></div>
1219
- </div>
1220
- <h2><a id="how-to-select-records"></a>How to select records</h2>
1221
- <div class="sectionbody">
1222
- <p>The syntax you use to select records to perform operations on is the same
1223
- for a select, update, or delete statement, so I wanted to cover, in
1224
- general, how to create a query expression first, before getting to the
1225
- specifics of select, update, and delete.</p>
1226
- <p>In KirbyBase, query conditions are specified simply by using Ruby code
1227
- blocks. Therefore, any code block that can be converted into a Proc object
1228
- is valid. This allows for great flexibility, as you will see in the many
1229
- examples below.</p>
1230
- <div class="sidebarblock">
1231
- <div class="sidebar-content">
1232
- <div class="admonitionblock">
1233
- <table><tr>
1234
- <td class="icon">
1235
- <img src="./images/tip.png" alt="Tip" />
1236
- </td>
1237
- <td class="content">You can find many examples of how to specify queries in the "examples"
1238
- directory of the KirbyBase distribution.</td>
1239
- </tr></table>
1240
- </div>
1241
- </div></div>
1242
- <p>Now that we have a general understanding of how to select records to operate
1243
- on, lets get more specific by looking at the select, update, and delete
1244
- methods.</p>
1245
- <h3><a id="select-method"></a>The select method</h3>
1246
- <p>The select method allows you to ask for all records in a table that match
1247
- certain selection criteria. Additionally, you can also specify which fields
1248
- you want included in the result set. The select method returns an instance
1249
- of KBResultSet, which is an array of records that satisfied the select
1250
- criteria. KBResultSet is covered in more detail later in the manual.</p>
1251
- <p>Here is the simplest example of a select statement:</p>
1252
- <div class="listingblock">
1253
- <div class="content">
1254
- <pre><tt>result_set = plane_tbl.select</tt></pre>
1255
- </div></div>
1256
- <p>Since, no code block was specified, KirbyBase will include all records in
1257
- the result set. Additionally, because a list of fields to include in the
1258
- result set was not specified, KirbyBase will include all fields for each
1259
- record in the result set.</p>
1260
- <p>To specify that you only want a subset of fields in the result set, you list
1261
- their field names as arguments to the select method. For example:</p>
1262
- <div class="listingblock">
1263
- <div class="content">
1264
- <pre><tt>result_set = plane_tbl.select(:name, :speed)</tt></pre>
1265
- </div></div>
1266
- <p>To specify selection criteria, attach a code block to the select method
1267
- call. For example, if you only wanted to select Japanese planes:</p>
1268
- <div class="listingblock">
1269
- <div class="content">
1270
- <pre><tt>result_set = plane_tbl.select(:name, :speed) { |r| r.country == 'Japan' }</tt></pre>
1271
- </div></div>
1272
- <p>You can combine multiple expressions in the code block. For example, to
1273
- select only US planes that have a speed greater than 350mph:</p>
1274
- <div class="listingblock">
1275
- <div class="content">
1276
- <pre><tt>result_set = plane_tbl.select { |r| r.country == 'USA' and r.speed &gt; 350 }</tt></pre>
1277
- </div></div>
1278
- <p>You can use regular expressions in the code block. Let's select all Axis
1279
- fighters:</p>
1280
- <div class="listingblock">
1281
- <div class="content">
1282
- <pre><tt>result_set = plane_tbl.select do |r|
1283
- r.country =~ /Germany|Japan/ and r.role == 'Fighter'
1284
- end</tt></pre>
1285
- </div></div>
1286
- <h3><a id="selecting-by-index"></a>Selecting by index</h3>
1287
- <p>Performing a select query using an index is almost identical to performing a
1288
- regular select query. You just have to specify the particular select
1289
- method, based on the index you wish to use.</p>
1290
- <p>For example, say you have created an index on the :speed field of the
1291
- :plane table. You want to search for all planes with a speed greater than
1292
- 400 mph. Ruby automatically creates select methods for each one of the
1293
- indexes of a table. So, you would code your select query like this:</p>
1294
- <div class="listingblock">
1295
- <div class="content">
1296
- <pre><tt>plane_tbl.select_by_speed_index { |r| r.speed &gt; 400 }</tt></pre>
1297
- </div></div>
1298
- <p>Notice that you simply insert the name of the field as part of the method
1299
- name. Its as simple as that.</p>
1300
- <p>For compound indexes, you just need to specify the
1301
- indexed field names in the select method in the same order as they are in
1302
- the table. So, let's say you have indexed the :plane table on :country and
1303
- :role, in one index. To select on this compound index, you would code:</p>
1304
- <div class="listingblock">
1305
- <div class="content">
1306
- <pre><tt>plane_tbl.select_by_country_role_index do |r|
1307
- r.country == 'Germany' and r.role == 'Fighter' }
1308
- end</tt></pre>
1309
- </div></div>
1310
- <p>Notice how you just list both fields as part of the name of the select
1311
- method, separated by underscores.</p>
1312
- <div class="sidebarblock">
1313
- <div class="sidebar-content">
1314
- <div class="admonitionblock">
1315
- <table><tr>
1316
- <td class="icon">
1317
- <img src="./images/warning.png" alt="Warning" />
1318
- </td>
1319
- <td class="content">If you specify a select method that does not exist, you will get an
1320
- error. Likewise, if you specify a query by an index, yet include a field
1321
- name in the query that is not part of the index, you will get an error.</td>
1322
- </tr></table>
1323
- </div>
1324
- </div></div>
1325
- <h3><a id="selecting-by-recno-index"></a>Selecting by :recno index</h3>
1326
- <p>For each table, a :recno index is automatically created, whether or not
1327
- other indexes are explicitly created by you. You can alway use this index
1328
- to select records based solely on :recno. For example:</p>
1329
- <div class="listingblock">
1330
- <div class="content">
1331
- <pre><tt>plane_tbl.select_by_recno_index { |r| [3, 45, 152].include?(r.recno) }</tt></pre>
1332
- </div></div>
1333
- <h3><a id="selects-involving-lookups-or-link-manys"></a>Selects Involving Lookups or Link_manys</h3>
1334
- <p>Selects that involve Lookup fields or Link_many fields have a special case
1335
- because both field types return complex objects rather than simple data
1336
- types. For example, consider the lookup field example that I described
1337
- earlier. For reference, here are the two table defintions again:</p>
1338
- <div class="listingblock">
1339
- <div class="content">
1340
- <pre><tt>department_tbl = db.create_table(:department, :dept_id, :String,
1341
- :dept_name, :String, :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee,
1342
- :employee_id]})
1343
-
1344
- employee_tbl = db.create_table(:employee, :employee_id, {:DataType=&gt;:String,
1345
- :Key=&gt;true}, :firstname, :String, :lastname, :String)</tt></pre>
1346
- </div></div>
1347
- <p>To find the department managed by John Doe, the select query would look like
1348
- this:</p>
1349
- <div class="listingblock">
1350
- <div class="content">
1351
- <pre><tt>department_tbl.select do |r|
1352
- r.manager.firstname == 'John' and r.manager.lastname == 'Doe'
1353
- end</tt></pre>
1354
- </div></div>
1355
- <p>Notice how the manager attribute is itself a Struct with its own members.</p>
1356
- <p>To print out all departments including the manager's full name:</p>
1357
- <div class="listingblock">
1358
- <div class="content">
1359
- <pre><tt>department_tbl.select.each do |r|
1360
- puts 'Department: %s Manager: %s %s' % [r.dept_name,
1361
- r.manager.firstname, r.manager.lastname]
1362
- end</tt></pre>
1363
- </div></div>
1364
- <p>Selects involving Link_many fields are slightly different because they
1365
- involve ResultSets instead of just single objects. Here's the table
1366
- definitions from the earlier Link_many discussion:</p>
1367
- <div class="listingblock">
1368
- <div class="content">
1369
- <pre><tt>orders_tbl = db.create_table(:orders, :order_id, :Integer,
1370
- :cust_id, :Integer, :order_date, :Date, :items, {:DataType=&gt;:ResultSet,
1371
- :Link_many=&gt;[:order_id, :order_items, :order_id]})
1372
-
1373
- order_items_tbl = db.create_table(:order_items, :item_no, :Integer,
1374
- :qty, :Integer, :order_id, :Integer)</tt></pre>
1375
- </div></div>
1376
- <p>To print an order and all of its associated detail items:</p>
1377
- <div class="listingblock">
1378
- <div class="content">
1379
- <pre><tt>result = order_tbl.select { |r| r.order_id == 501 }.first
1380
- puts '%d %d %s' % [result.order_id, result.cust_id, result.order_date]
1381
-
1382
- result.items.each { |item| puts '%d %d' % [item.item_no, item.qty] }</tt></pre>
1383
- </div></div>
1384
- <p>Notice how the items attribute in the ResultSet is itself a ResultSet
1385
- containing all of the :order_items records that belong to the selected
1386
- order.</p>
1387
- <h3><a id="a-note-about-nil-values"></a>A Note About nil Values</h3>
1388
- <p>Beginning in version 2.6 of KirbyBase, nil values are no longer stored as
1389
- the singleton instance of NilClass in the database. Now, they are stored
1390
- as references to the singleton instance, kb_nil, of KBNilClass. KBNilClass
1391
- is as similar to NilClass as possible, but since NilClass cannot
1392
- be sub-classed, there are a few minor differences.</p>
1393
- <p>However, this should all be transparent to you because KirbyBase converts
1394
- kb_nil values to Ruby nil values before returning the results of a query.
1395
- The only time you will need to be worried about kb_nil is when you need to
1396
- explicitly test for a nil value in a query. For example:</p>
1397
- <div class="listingblock">
1398
- <div class="content">
1399
- <pre><tt>plane_tbl.select {|r| r.speed == kb_nil}</tt></pre>
1400
- </div></div>
1401
- <p>which is the same as:</p>
1402
- <div class="listingblock">
1403
- <div class="content">
1404
- <pre><tt>plane_tbl.select {|r| r.speed.kb_nil?}</tt></pre>
1405
- </div></div>
1406
- <p>Notice how it is very similar to how you would test for nil?</p>
1407
- <p>The only other difference you will now notice, is if you open up a table in
1408
- a text editor. Now, nil values are stored as "kb_nil", instead of being
1409
- stored as an empty string (i.e. ""). This has the added advantage that
1410
- KirbyBase can now distinguish between empty strings and nil values. In the
1411
- past, if you saved an empty string as a field value, the next time you
1412
- selected that record, KirbyBase would return that field's value as nil.</p>
1413
- <p>The main reason for making this change was to eliminate the need to
1414
- override NilClass#method_missing, which was cause for concern for some
1415
- users.</p>
1416
- </div>
1417
- <h2><a id="kbresultset"></a>KBResultSet</h2>
1418
- <div class="sectionbody">
1419
- <p>As stated above, the select method returns an instance of KBResultSet, which
1420
- is an array of Struct objects (or instances of the class specified in
1421
- record_class), each one representing a record that satisfied the selection
1422
- criteria.</p>
1423
- <p>Since each item in KBResultSet is a Struct object, you can easily reference
1424
- its members using field names. So, to print the name and speed of each
1425
- German plane in the table you would code:</p>
1426
- <div class="listingblock">
1427
- <div class="content">
1428
- <pre><tt>plane_tbl.select(:name, :speed) { |r| r.country == 'German' }.each do |r|
1429
- puts '%s %s' % [r.name, r.speed]
1430
- end</tt></pre>
1431
- </div></div>
1432
- <h3><a id="sorting-a-result-set"></a>Sorting a result set</h3>
1433
- <p>You can specify sort criteria by calling KBResultSet#sort. You must supply
1434
- the sort method with a list of field names that you want to sort by. For
1435
- example, to select all planes, include just name, country, and speed in the
1436
- result set, and sort the result set by country (ascending) then name
1437
- (ascending), you would code:</p>
1438
- <div class="listingblock">
1439
- <div class="content">
1440
- <pre><tt>result = plane_tbl.select(:name, :country, :speed).sort(:country, :name)</tt></pre>
1441
- </div></div>
1442
- <p>To indicate that you want a particular field sorted in descending order
1443
- rather than ascending order, you need to put a minus sign in front of it.
1444
- For example, to select all planes, include just name, country, and speed in
1445
- the result set, and sort the result set by country (ascending) then speed
1446
- (descending), you would code:</p>
1447
- <div class="listingblock">
1448
- <div class="content">
1449
- <pre><tt>result_set = plane_tbl.select(:name, :country, :speed).sort(:country,
1450
- -:speed)</tt></pre>
1451
- </div></div>
1452
- <p>You can also explicitly specify that a field be sorted in ascending order by
1453
- putting a plus sign in front of it. This is not necessary, since ascending
1454
- is the default, but its there if you prefer to use it.</p>
1455
- <h3><a id="to-report"></a>Producing a report from a result set</h3>
1456
- <p>Additionally, you can also transform the KBResultSet into a nicely formatted
1457
- report, suitable for printing, by calling KBResultSet#to_report. To print
1458
- a formatted report of all plane names, countries, and speeds, sorted by
1459
- name, you would code the following:</p>
1460
- <div class="listingblock">
1461
- <div class="content">
1462
- <pre><tt>puts plane_tbl.select(:name, :country, :speed).sort(:name).to_report</tt></pre>
1463
- </div></div>
1464
- <h3><a id="crosstabs"></a>CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</h3>
1465
- <p>Every KBResultSet has an additional feature that can prove quite useful.
1466
- When a result set is created, KirbyBase creates an array for each column
1467
- name that has all of the values of that column in it. Perhaps an example
1468
- would make this more clear. Let's say you have a table that looks like
1469
- this:</p>
1470
- <div class="tableblock">
1471
- <table rules="all"
1472
- frame="border"
1473
- cellspacing="0" cellpadding="4">
1474
- <col width="102" />
1475
- <col width="114" />
1476
- <col width="137" />
1477
- <thead>
1478
- <tr>
1479
- <th align="left">
1480
- name
1481
- </th>
1482
- <th align="left">
1483
- speed
1484
- </th>
1485
- <th align="left">
1486
- range
1487
- </th>
1488
- </tr>
1489
- </thead>
1490
- <tbody valign="top">
1491
- <tr>
1492
- <td align="left">
1493
- P-51
1494
- </td>
1495
- <td align="left">
1496
- 402
1497
- </td>
1498
- <td align="left">
1499
- 1201
1500
- </td>
1501
- </tr>
1502
- <tr>
1503
- <td align="left">
1504
- ME-109
1505
- </td>
1506
- <td align="left">
1507
- 354
1508
- </td>
1509
- <td align="left">
1510
- 544
1511
- </td>
1512
- </tr>
1513
- <tr>
1514
- <td align="left">
1515
- Spitfire
1516
- </td>
1517
- <td align="left">
1518
- 343
1519
- </td>
1520
- <td align="left">
1521
- 501
1522
- </td>
1523
- </tr>
1524
- </tbody>
1525
- </table>
1526
- </div>
1527
- <p>If you do a select on the table, not only will the result set contain a
1528
- row for each record that satisfied the select condition, but it will also
1529
- contain an array for each column, which will hold all the column values.
1530
- Here's an example, using the above mentioned table:</p>
1531
- <div class="listingblock">
1532
- <div class="content">
1533
- <pre><tt>result = plane_tbl.select
1534
-
1535
- puts result[0].name =&gt; P-51
1536
- puts result[0].speed =&gt; 402
1537
-
1538
- p result.speed =&gt; [402,354,343]</tt></pre>
1539
- </div></div>
1540
- <p>Notice how you can reference this "column array" by calling the column name
1541
- as a method. KirbyBase returns an array that holds all the values, in this
1542
- case, of the speed column. This can be very useful in some cases. For a
1543
- good example of this, look in the examples\crosstab_test directory of the
1544
- distribution.</p>
1545
- </div>
1546
- <h2><a id="how-to-update-records"></a>How to update records</h2>
1547
- <div class="sectionbody">
1548
- <p>You can update the data in a table either by using the KBTable#update method
1549
- by itself, or using it in conjunction with the KBResultSet#set method.
1550
- Both methods produce the same result. The main difference is that, while
1551
- using the #update method by itself, you can use a Hash, Array, or Struct as
1552
- your update criteria, using the #set method in conjunction with the #update
1553
- method adds the ability to use a code block as your update criteria. You
1554
- will see specific examples of this in "The update method" description below.</p>
1555
- <h3><a id="update-method"></a>The update method</h3>
1556
- <p>To update a table, you use the update method. You <strong>must</strong> specify a code
1557
- block that indicates which records are to be updated. Additionally, you must
1558
- specify the fields to be updated and the new values for those fields.</p>
1559
- <p>You can update records using a Hash, Struct, an Array, or an instance of a
1560
- class you defined. For example, to change the P-51's speed to 405mph and
1561
- its range to 1210 miles, you could code:</p>
1562
- <div class="listingblock">
1563
- <div class="content">
1564
- <pre><tt>plane_tbl.update(:speed=&gt;405, :range=&gt;1210) { |r| r.name == 'P-51' }</tt></pre>
1565
- </div></div>
1566
- <p>or:</p>
1567
- <div class="listingblock">
1568
- <div class="content">
1569
- <pre><tt>UpdateRec = Struct.new(:name, :country, :role, :speed, :range,
1570
- :began_service, :still_flying)
1571
-
1572
- rec = UpdateRec.new
1573
- rec.speed = 405
1574
- rec.range = 1210
1575
- plane_tbl.update(rec) { |r| r.name == 'P-51' }</tt></pre>
1576
- </div></div>
1577
- <h3><a id="set-method"></a>The set method</h3>
1578
- <p>You can also update records using a code block, via KBResultSet#set:</p>
1579
- <div class="listingblock">
1580
- <div class="content">
1581
- <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set do |r|
1582
- r.speed = 405
1583
- r.range = 1210
1584
- end</tt></pre>
1585
- </div></div>
1586
- <p>You can also update records using a Hash, Struct, or an Array, via
1587
- KBResultSet#set:</p>
1588
- <div class="listingblock">
1589
- <div class="content">
1590
- <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set(:speed=&gt;405, :range=&gt;1210)</tt></pre>
1591
- </div></div>
1592
- <div class="sidebarblock">
1593
- <div class="sidebar-content">
1594
- <div class="admonitionblock">
1595
- <table><tr>
1596
- <td class="icon">
1597
- <img src="./images/important.png" alt="Important" />
1598
- </td>
1599
- <td class="content">When you don't supply a code block to the #select method,
1600
- KirbyBase automatically selects all of the records in the table. I felt
1601
- that having the #update method work the same way was too dangerous. It
1602
- would be too easy for someone to accidentally update all of the records in
1603
- a table if they forgot to supply a code block to #update. That is why the
1604
- #update method <strong>requires</strong> a code block. To update all of the records in a
1605
- table, use the #update_all method.</td>
1606
- </tr></table>
1607
- </div>
1608
- </div></div>
1609
- <div class="sidebarblock">
1610
- <div class="sidebar-content">
1611
- <div class="admonitionblock">
1612
- <table><tr>
1613
- <td class="icon">
1614
- <img src="./images/note.png" alt="Note" />
1615
- </td>
1616
- <td class="content">The #update method will return an Integer specifying the number of
1617
- records that were updated.</td>
1618
- </tr></table>
1619
- </div>
1620
- </div></div>
1621
- <h3><a id="update-all-method"></a>The update_all method</h3>
1622
- <p>To update all records in a table, you can use KBTable#update_all. This
1623
- works just like the update method, except that you don't specify a code
1624
- block containing selection criteria.</p>
1625
- <p>For example, to add 50 mph to every record's speed field, you would code:</p>
1626
- <div class="listingblock">
1627
- <div class="content">
1628
- <pre><tt>plane_tbl.update_all { |r| r.speed = r.speed + 50 }</tt></pre>
1629
- </div></div>
1630
- <div class="sidebarblock">
1631
- <div class="sidebar-content">
1632
- <div class="admonitionblock">
1633
- <table><tr>
1634
- <td class="icon">
1635
- <img src="./images/note.png" alt="Note" />
1636
- </td>
1637
- <td class="content">The #update_all method will return an Integer specifying the number
1638
- of records that were updated.</td>
1639
- </tr></table>
1640
- </div>
1641
- </div></div>
1642
- </div>
1643
- <h2><a id="how-to-delete-records"></a>How to delete records</h2>
1644
- <div class="sectionbody">
1645
- <p>Deleting records from a table is similar to performing a #select or an
1646
- #update.</p>
1647
- <h3><a id="delete-method"></a>The delete method</h3>
1648
- <p>To use the #delete method, you <strong>must</strong> supply a code block that identifies
1649
- which records should be deleted.</p>
1650
- <p>For example, to delete the FW-190's record from the table:</p>
1651
- <div class="listingblock">
1652
- <div class="content">
1653
- <pre><tt>plane_tbl.delete { |r| r.name == 'FW-190' }</tt></pre>
1654
- </div></div>
1655
- <div class="sidebarblock">
1656
- <div class="sidebar-content">
1657
- <div class="admonitionblock">
1658
- <table><tr>
1659
- <td class="icon">
1660
- <img src="./images/important.png" alt="Important" />
1661
- </td>
1662
- <td class="content">When you don't supply a code block to the #select method,
1663
- KirbyBase automatically selects all of the records in the table. I felt
1664
- that having the #delete method work the same way was too dangerous. It
1665
- would be too easy for someone to accidentally delete all of the records in
1666
- a table if they forgot to supply a code block to #delete. That is why the
1667
- #delete method <strong>requires</strong> a code block. To delete all of the records in a
1668
- table, use the #clear method.</td>
1669
- </tr></table>
1670
- </div>
1671
- </div></div>
1672
- <div class="sidebarblock">
1673
- <div class="sidebar-content">
1674
- <div class="admonitionblock">
1675
- <table><tr>
1676
- <td class="icon">
1677
- <img src="./images/note.png" alt="Note" />
1678
- </td>
1679
- <td class="content">The #delete method will return an Integer specifying the total number
1680
- of records that were deleted.</td>
1681
- </tr></table>
1682
- </div>
1683
- </div></div>
1684
- <h3><a id="clear-method"></a>The clear (alias delete_all) method</h3>
1685
- <p>To completely empty a table, use the clear method. For example:</p>
1686
- <div class="listingblock">
1687
- <div class="content">
1688
- <pre><tt>plane_tbl.clear</tt></pre>
1689
- </div></div>
1690
- <div class="sidebarblock">
1691
- <div class="sidebar-content">
1692
- <div class="admonitionblock">
1693
- <table><tr>
1694
- <td class="icon">
1695
- <img src="./images/important.png" alt="Important" />
1696
- </td>
1697
- <td class="content">By default, KirbyBase will reset the recno counter to 0. So, any
1698
- new records inserted after a #clear will be given a :recno starting with 1.
1699
- To prevent #clear from resetting the recno counter, pass false to #clear.</td>
1700
- </tr></table>
1701
- </div>
1702
- </div></div>
1703
- </div>
1704
- <h2><a id="pack-method"></a>The pack method</h2>
1705
- <div class="sectionbody">
1706
- <p>When KirbyBase deletes a record, it really just fills the entire line in the
1707
- file with spaces. Deleting the entire line and moving each subsequent line
1708
- up one would take too much time. Also, when a record is updated, if the size
1709
- of the updated record is greater than the size of the old record, KirbyBase
1710
- spaces out that entire line in the file, and rewrites the updated record at
1711
- the end of the file. Again, this is done so that the entire file doesn't
1712
- have to be re-written just because one record got updated.</p>
1713
- <p>However, this means that after a lot of deletes and updates, a table can
1714
- have lots of blank lines in it. This slows down searches and makes the file
1715
- bigger than it has to be. You can use the pack method to remove these blank
1716
- lines:</p>
1717
- <div class="listingblock">
1718
- <div class="content">
1719
- <pre><tt>result = plane_tbl.pack</tt></pre>
1720
- </div></div>
1721
- <div class="admonitionblock">
1722
- <table><tr>
1723
- <td class="icon">
1724
- <img src="./images/important.png" alt="Important" />
1725
- </td>
1726
- <td class="content">You can only call this method when connect_type==:local.</td>
1727
- </tr></table>
1728
- </div>
1729
- <div class="sidebarblock">
1730
- <div class="sidebar-content">
1731
- <div class="admonitionblock">
1732
- <table><tr>
1733
- <td class="icon">
1734
- <img src="./images/note.png" alt="Note" />
1735
- </td>
1736
- <td class="content">The #pack method will return an Integer specifiying the number of
1737
- blank lines that were removed from the table.</td>
1738
- </tr></table>
1739
- </div>
1740
- </div></div>
1741
- </div>
1742
- <h2><a id="memo-and-blob-fields"></a>Memo and Blob Fields</h2>
1743
- <div class="sectionbody">
1744
- <p>Memo and Blob fields operate a little differently from standard field types.
1745
- You specify their creation just like regular field types. Notice how you
1746
- can specify a base path for where memo/blob files will be stored.</p>
1747
- <div class="listingblock">
1748
- <div class="content">
1749
- <pre><tt>db.create_table(:plane, :name, :String, :speed, :Integer, :descr,
1750
- :Memo) do |d|
1751
- d.memo_blob_path = './memos'
1752
- end</tt></pre>
1753
- </div></div>
1754
- <p>However, what you actually store in the Memo field upon an #insert is an
1755
- instance of KBMemo. KBMemo has two attributes: :filepath and :contents.
1756
- The first holds the path (including filename) to the text file that will
1757
- hold the contents of the memo. This path will be relative to whatever
1758
- path was specified as the memo_blob_path upon database initialization. Here
1759
- is an example of how to do this:</p>
1760
- <div class="listingblock">
1761
- <div class="content">
1762
- <pre><tt>memo_string = &lt;&lt;END_OF_STRING
1763
- The FW-190 was a World War II German fighter. It was used primarily as an
1764
- interceptor against Allied strategic bombers.
1765
- END_OF_STRING
1766
-
1767
- memo = KBMemo.new(db, 'FW-190.txt', memo_string)
1768
- plane_tbl.insert('FW-190', 'Germany', 399, 499, memo)</tt></pre>
1769
- </div></div>
1770
- <p>Updates work similarly in that you would need to supply a KBMemo instance
1771
- to the #update method for the :Memo field.</p>
1772
- <p>Other than this difference, you can use a memo field just like a regular
1773
- field. When you do a #select, KirbyBase goes out to the file that holds the
1774
- memo data, reads in all the lines, and returns a KBMemo instance. Here is
1775
- an example of how you can even query against a memo field:</p>
1776
- <div class="listingblock">
1777
- <div class="content">
1778
- <pre><tt>plane_tbl.select { |r| r.descr.contents =~ /built in Detroit, Michigan/ }</tt></pre>
1779
- </div></div>
1780
- <p>And KirbyBase would select all records whose memo field contained the phrase
1781
- "built in Detroit, Michigan".</p>
1782
- <p>Blob fields work similarly, except that instead of doing a #readlines,
1783
- KirbyBase opens the file in binary mode and reads in the whole file at once.</p>
1784
- </div>
1785
- <h2><a id="misc-kirbybase-methods"></a>Miscellaneous KirbyBase methods</h2>
1786
- <div class="sectionbody">
1787
- <div class="sidebarblock">
1788
- <a id="drop-table"></a>
1789
- <div class="sidebar-content">
1790
- <div class="sidebar-title">KirbyBase#drop_table</div>
1791
- <div class="listingblock">
1792
- <div class="content">
1793
- <pre><tt>db.drop_table(:plane)</tt></pre>
1794
- </div></div>
1795
- <p>Will delete a table from the database.</p>
1796
- <p>Returns true if table was dropped.</p>
1797
- </div></div>
1798
- <div class="sidebarblock">
1799
- <a id="tables"></a>
1800
- <div class="sidebar-content">
1801
- <div class="sidebar-title">KirbyBase#tables</div>
1802
- <div class="listingblock">
1803
- <div class="content">
1804
- <pre><tt>db.tables</tt></pre>
1805
- </div></div>
1806
- <p>Returns an array of all table names in the database.</p>
1807
- </div></div>
1808
- <div class="sidebarblock">
1809
- <a id="table-exists"></a>
1810
- <div class="sidebar-content">
1811
- <div class="sidebar-title">KirbyBase#table_exists?</div>
1812
- <div class="listingblock">
1813
- <div class="content">
1814
- <pre><tt>db.table_exists?(:plane)</tt></pre>
1815
- </div></div>
1816
- <p>Returns true if table exists, false otherwise.</p>
1817
- </div></div>
1818
- <div class="sidebarblock">
1819
- <a id="rename-table"></a>
1820
- <div class="sidebar-content">
1821
- <div class="sidebar-title">KirbyBase#rename_table</div>
1822
- <div class="listingblock">
1823
- <div class="content">
1824
- <pre><tt>db.rename_table(:plane, :warplanes)</tt></pre>
1825
- </div></div>
1826
- <p>Rename table to new name.</p>
1827
- <p>Returns a handle to the newly-renamed table.</p>
1828
- </div></div>
1829
- </div>
1830
- <h2><a id="misc-kbtable-methods"></a>Miscellaneous KBTable methods</h2>
1831
- <div class="sectionbody">
1832
- <div class="sidebarblock">
1833
- <a id="update-by-recno"></a>
1834
- <div class="sidebar-content">
1835
- <div class="sidebar-title">KBTable#[]=</div>
1836
- <div class="listingblock">
1837
- <div class="content">
1838
- <pre><tt>plane_tbl[5] = {:country = 'Tasmania'}</tt></pre>
1839
- </div></div>
1840
- <p>You can quickly update an individual record by treating the table as a Hash
1841
- and the keys as recno's. You can update it using a Hash, Array, or Struct.</p>
1842
- <p>Returns Integer specifying number of records updated (should always be 1).</p>
1843
- </div></div>
1844
- <div class="sidebarblock">
1845
- <a id="get-by-recno"></a>
1846
- <div class="sidebar-content">
1847
- <div class="sidebar-title">KBTable#[]</div>
1848
- <div class="listingblock">
1849
- <div class="content">
1850
- <pre><tt>plane_tbl[5]</tt></pre>
1851
- </div></div>
1852
- <p>You can quickly select an individual record, by passing its recno to a
1853
- table as if it were a hash.</p>
1854
- <p>Returns a single record either in the form of a Struct or an instance of
1855
- the table's custom record class, if specified.</p>
1856
- <div class="listingblock">
1857
- <div class="content">
1858
- <pre><tt>plane_tbl[5, 14, 33]</tt></pre>
1859
- </div></div>
1860
- <p>You can also use the [] method to get a group of records by passing it more
1861
- than one recno.</p>
1862
- <p>Returns a KBResultSet with the records having the recno's you passed in.</p>
1863
- </div></div>
1864
- <div class="sidebarblock">
1865
- <a id="field-names"></a>
1866
- <div class="sidebar-content">
1867
- <div class="sidebar-title">KBTable#field_names</div>
1868
- <div class="listingblock">
1869
- <div class="content">
1870
- <pre><tt>plane_tbl.field_names</tt></pre>
1871
- </div></div>
1872
- <p>Returns an array of the table's field names.</p>
1873
- </div></div>
1874
- <div class="sidebarblock">
1875
- <a id="field-types"></a>
1876
- <div class="sidebar-content">
1877
- <div class="sidebar-title">KBTable#field_types</div>
1878
- <div class="listingblock">
1879
- <div class="content">
1880
- <pre><tt>plane_tbl.field_types</tt></pre>
1881
- </div></div>
1882
- <p>Returns an array of the table's field types (i.e. :String, :Integer, :Float)</p>
1883
- </div></div>
1884
- <div class="sidebarblock">
1885
- <a id="total-recs"></a>
1886
- <div class="sidebar-content">
1887
- <div class="sidebar-title">KBTable#total_recs</div>
1888
- <div class="listingblock">
1889
- <div class="content">
1890
- <pre><tt>plane_tbl.total_recs</tt></pre>
1891
- </div></div>
1892
- <p>Returns an Integer specifying the total number of records in the table.</p>
1893
- </div></div>
1894
- <div class="sidebarblock">
1895
- <a id="import-csv"></a>
1896
- <div class="sidebar-content">
1897
- <div class="sidebar-title">KBTable#import_csv</div>
1898
- <div class="listingblock">
1899
- <div class="content">
1900
- <pre><tt>plane_tbl.import_csv(csv_filename)</tt></pre>
1901
- </div></div>
1902
- <p>This method allows you to import a csv file into the current table.
1903
- KirbyBase will attempt to convert the values in the csv file into their
1904
- corresponding KirbyBase field types, based upon the field types you
1905
- designated when you created the table.</p>
1906
- <p>If you have FasterCSV installed KirbyBase will use it instead of CSV from
1907
- the standard library.</p>
1908
- <p>Returns an Integer specifying the total number of records imported.</p>
1909
- </div></div>
1910
- <div class="sidebarblock">
1911
- <a id="add-column"></a>
1912
- <div class="sidebar-content">
1913
- <div class="sidebar-title">KBTable#add_column</div>
1914
- <div class="listingblock">
1915
- <div class="content">
1916
- <pre><tt>plane_tbl.add_column(:weight, :Integer, :range)</tt></pre>
1917
- </div></div>
1918
- <p>This method allows you to add a column to an existing table. You must
1919
- specify a column name, and a column type. You can optionally specify a
1920
- column that you want the new column added after. If this is not specified,
1921
- KirbyBase will add the column to the end of the table.</p>
1922
- <div class="admonitionblock">
1923
- <table><tr>
1924
- <td class="icon">
1925
- <img src="./images/important.png" alt="Important" />
1926
- </td>
1927
- <td class="content">Because #add_column changes the structure of a table, you can
1928
- only call this method when connect_type==:local.</td>
1929
- </tr></table>
1930
- </div>
1931
- </div></div>
1932
- <div class="sidebarblock">
1933
- <a id="drop-column"></a>
1934
- <div class="sidebar-content">
1935
- <div class="sidebar-title">KBTable#drop_column</div>
1936
- <div class="listingblock">
1937
- <div class="content">
1938
- <pre><tt>plane_tbl.drop_column(:speed)</tt></pre>
1939
- </div></div>
1940
- <p>This method allows you to remove a column from an existing table. You must
1941
- specify the column name to be removed.</p>
1942
- <div class="admonitionblock">
1943
- <table><tr>
1944
- <td class="icon">
1945
- <img src="./images/important.png" alt="Important" />
1946
- </td>
1947
- <td class="content">You cannot drop the :recno column.</td>
1948
- </tr></table>
1949
- </div>
1950
- <div class="admonitionblock">
1951
- <table><tr>
1952
- <td class="icon">
1953
- <img src="./images/important.png" alt="Important" />
1954
- </td>
1955
- <td class="content">Because #drop_column changes the structure of a table, you can
1956
- only call this method when connect_type==:local.</td>
1957
- </tr></table>
1958
- </div>
1959
- </div></div>
1960
- <div class="sidebarblock">
1961
- <a id="rename-column"></a>
1962
- <div class="sidebar-content">
1963
- <div class="sidebar-title">KBTable#rename_column</div>
1964
- <div class="listingblock">
1965
- <div class="content">
1966
- <pre><tt>plane_tbl.rename_column(:speed, :maximum_speed)</tt></pre>
1967
- </div></div>
1968
- <p>This method allows you to rename a column in an existing table. You must
1969
- specify the column to be renamed and a new column name.</p>
1970
- <div class="admonitionblock">
1971
- <table><tr>
1972
- <td class="icon">
1973
- <img src="./images/important.png" alt="Important" />
1974
- </td>
1975
- <td class="content">You cannot rename the :recno column.</td>
1976
- </tr></table>
1977
- </div>
1978
- <div class="admonitionblock">
1979
- <table><tr>
1980
- <td class="icon">
1981
- <img src="./images/important.png" alt="Important" />
1982
- </td>
1983
- <td class="content">Because #rename_column changes the structure of a table, you can
1984
- only call this method when connect_type==:local.</td>
1985
- </tr></table>
1986
- </div>
1987
- </div></div>
1988
- <div class="sidebarblock">
1989
- <a id="change-column-type"></a>
1990
- <div class="sidebar-content">
1991
- <div class="sidebar-title">KBTable#change_column_type</div>
1992
- <div class="listingblock">
1993
- <div class="content">
1994
- <pre><tt>plane_tbl.change_column_type(:weight, :Float)</tt></pre>
1995
- </div></div>
1996
- <p>This method allows you to change a column's type in an existing table. You
1997
- must specify the column name and a new column type.</p>
1998
- <div class="admonitionblock">
1999
- <table><tr>
2000
- <td class="icon">
2001
- <img src="./images/important.png" alt="Important" />
2002
- </td>
2003
- <td class="content">You cannot change the type of the :recno column.</td>
2004
- </tr></table>
2005
- </div>
2006
- <div class="admonitionblock">
2007
- <table><tr>
2008
- <td class="icon">
2009
- <img src="./images/important.png" alt="Important" />
2010
- </td>
2011
- <td class="content">Because #change_column_type changes the structure of a table, you
2012
- can only call this method when connect_type==:local.</td>
2013
- </tr></table>
2014
- </div>
2015
- </div></div>
2016
- <div class="sidebarblock">
2017
- <a id="change-column-default-value"></a>
2018
- <div class="sidebar-content">
2019
- <div class="sidebar-title">KBTable#change_column_default_value</div>
2020
- <div class="listingblock">
2021
- <div class="content">
2022
- <pre><tt>plane_tbl.change_column_default_value(:country, 'United States')</tt></pre>
2023
- </div></div>
2024
- <p>This method allows you to change a column's default value in an existing
2025
- table. You must specify the column name and a default value. If the
2026
- default value is equal to nil, this, in effect will make the column not have
2027
- a default value any more.</p>
2028
- <div class="admonitionblock">
2029
- <table><tr>
2030
- <td class="icon">
2031
- <img src="./images/important.png" alt="Important" />
2032
- </td>
2033
- <td class="content">Since the :recno column cannot have a default value, you cannot
2034
- change the default value of the :recno column.</td>
2035
- </tr></table>
2036
- </div>
2037
- <div class="admonitionblock">
2038
- <table><tr>
2039
- <td class="icon">
2040
- <img src="./images/important.png" alt="Important" />
2041
- </td>
2042
- <td class="content">Because #change_column_default_value changes the structure of a
2043
- table, you can only call this method when connect_type==:local.</td>
2044
- </tr></table>
2045
- </div>
2046
- </div></div>
2047
- <div class="sidebarblock">
2048
- <a id="change-column-required"></a>
2049
- <div class="sidebar-content">
2050
- <div class="sidebar-title">KBTable#change_column_required</div>
2051
- <div class="listingblock">
2052
- <div class="content">
2053
- <pre><tt>plane_tbl.change_column_required(:country, true)</tt></pre>
2054
- </div></div>
2055
- <p>This method allows you to change whether a value for a column is required or
2056
- not. You must specify the column name and either true or false for the
2057
- required argument.</p>
2058
- <div class="admonitionblock">
2059
- <table><tr>
2060
- <td class="icon">
2061
- <img src="./images/important.png" alt="Important" />
2062
- </td>
2063
- <td class="content">You cannot specify whether the :recno column is required or not.</td>
2064
- </tr></table>
2065
- </div>
2066
- <div class="admonitionblock">
2067
- <table><tr>
2068
- <td class="icon">
2069
- <img src="./images/important.png" alt="Important" />
2070
- </td>
2071
- <td class="content">Because #change_column_required changes the structure of a table,
2072
- you can only call this method when connect_type==:local.</td>
2073
- </tr></table>
2074
- </div>
2075
- </div></div>
2076
- <div class="sidebarblock">
2077
- <a id="add-index"></a>
2078
- <div class="sidebar-content">
2079
- <div class="sidebar-title">KBTable#add_index</div>
2080
- <div class="listingblock">
2081
- <div class="content">
2082
- <pre><tt>plane_tbl.add_index(:name, :country)</tt></pre>
2083
- </div></div>
2084
- <p>This method allows you to add an index to an existing table. This index can
2085
- consist of one or more columns. You must specify one or more column names
2086
- that you want to make up the index.</p>
2087
- <div class="admonitionblock">
2088
- <table><tr>
2089
- <td class="icon">
2090
- <img src="./images/important.png" alt="Important" />
2091
- </td>
2092
- <td class="content">Because #add_index changes the structure of a table, you can
2093
- only call this method when connect_type==:local.</td>
2094
- </tr></table>
2095
- </div>
2096
- </div></div>
2097
- <div class="sidebarblock">
2098
- <a id="drop-index"></a>
2099
- <div class="sidebar-content">
2100
- <div class="sidebar-title">KBTable#drop_index</div>
2101
- <div class="listingblock">
2102
- <div class="content">
2103
- <pre><tt>plane_tbl.drop_index(:name, :country)</tt></pre>
2104
- </div></div>
2105
- <p>This method allows you to drop an index from an existing table. You must
2106
- specify one or more column names that make up the index that you want to
2107
- drop.</p>
2108
- <div class="admonitionblock">
2109
- <table><tr>
2110
- <td class="icon">
2111
- <img src="./images/important.png" alt="Important" />
2112
- </td>
2113
- <td class="content">Because #drop_index changes the structure of a table, you can
2114
- only call this method when connect_type==:local.</td>
2115
- </tr></table>
2116
- </div>
2117
- </div></div>
2118
- </div>
2119
- <h2><a id="special-characters-in-data"></a>Special characters in data</h2>
2120
- <div class="sectionbody">
2121
- <p>Since KirbyBase tables are just plain-text, newline-delimited files with
2122
- each field delimited by a <em>|</em>, certain ASCII characters could cause problems
2123
- when used as input. For example, entering a newline character (\n on Unix,
2124
- \r\n on Windows) as part of a record's data would cause problems later when
2125
- KirbyBase attempted to read this record. Likewise, using the <em>|</em> character
2126
- in your data would also cause problems as KirbyBase uses this character as a
2127
- field delimiter. Finally, it turns out that Python has problems handling
2128
- octal code \032 under Windows (possibly because it equates to Ctrl-Z), so
2129
- to keep compatibility between the Ruby and Python versions of KirbyBase,
2130
- this issue needs to be handled.</p>
2131
- <p>To handle the above special characters as data input, KirbyBase checks all
2132
- :String and :YAML input data and replaces the special characters with
2133
- encodings that are safe. The following table shows how replacements are
2134
- done:</p>
2135
- <div class="tableblock">
2136
- <table rules="all"
2137
- frame="border"
2138
- cellspacing="0" cellpadding="4">
2139
- <col width="182" />
2140
- <col width="240" />
2141
- <thead>
2142
- <tr>
2143
- <th align="left">
2144
- Input Character
2145
- </th>
2146
- <th align="left">
2147
- KirbyBase Replacement
2148
- </th>
2149
- </tr>
2150
- </thead>
2151
- <tbody valign="top">
2152
- <tr>
2153
- <td align="left">
2154
- \n
2155
- </td>
2156
- <td align="left">
2157
- &amp;amp;linefeed;
2158
- </td>
2159
- </tr>
2160
- <tr>
2161
- <td align="left">
2162
- \r
2163
- </td>
2164
- <td align="left">
2165
- &amp;amp;carriage_return;
2166
- </td>
2167
- </tr>
2168
- <tr>
2169
- <td align="left">
2170
- \032
2171
- </td>
2172
- <td align="left">
2173
- &amp;amp;substitute;
2174
- </td>
2175
- </tr>
2176
- <tr>
2177
- <td align="left">
2178
- |
2179
- </td>
2180
- <td align="left">
2181
- &amp;amp;pipe;
2182
- </td>
2183
- </tr>
2184
- <tr>
2185
- <td align="left">
2186
- &amp;
2187
- </td>
2188
- <td align="left">
2189
- &amp;amp;
2190
- </td>
2191
- </tr>
2192
- </tbody>
2193
- </table>
2194
- </div>
2195
- <p>KirbyBase will translate to and from the special characters as data is
2196
- written to and read from a table. It should all be transparent to the user.
2197
- The only time you would encounter the replacement words is if you were to
2198
- open up the physical table file in a text editor or read it in as input
2199
- outside of KirbyBase.</p>
2200
- </div>
2201
- <h2><a id="table-structure"></a>Table Structure</h2>
2202
- <div class="sectionbody">
2203
- <p>Every table in KirbyBase is represented by a physical, newline-delimited
2204
- text-file. Here is an example:</p>
2205
- <div class="listingblock">
2206
- <div class="content">
2207
- <pre><tt>000006|000000|Struct|recno:Integer|name:String|country:String|speed:Integer
2208
- 1|P-51|USA|403
2209
- 2|P-51|USA|365
2210
- 3|Sptitfire|England|345
2211
- 4|Oscar|Japan|361
2212
- 5|ME-109|Germany|366
2213
- 6|Zero|Japan|377</tt></pre>
2214
- </div></div>
2215
- <p>The first line is the header rec. Each field is delimited by a "|". The
2216
- first field in the header is the record counter. It is incremented by
2217
- KirbyBase to create new record numbers when records are inserted.</p>
2218
- <p>The second field in the header is the deleted-records counter. Every time a
2219
- line in the file is blanked-out (see <a href="#pack-method">The pack method</a>), this
2220
- number is incremented. You can use this field in a maintenance script so
2221
- that the table is packed whenever the deleted-records counter reaches, say,
2222
- 5,000 records.</p>
2223
- <p>The third field in the header is the record_class field. If you specified a
2224
- class when you created the table, its name will show up here and records
2225
- returned from a #select will be instances of this class. The default is
2226
- "Struct".</p>
2227
- <p>The fourth field in the header is the :recno field. This field is
2228
- automatically added to the table when it is created. The field name and
2229
- field type are separated by a ":".</p>
2230
- <p>The rest of the fields are whatever you specified when you created the
2231
- table.</p>
2232
- <p>If there is a Z in the first position of the header rec and the rest of the
2233
- file is a bunch of random characters, this means that the table is
2234
- encrypted.</p>
2235
- <p>Each record after the header record is simply a line of text. Newline
2236
- characters delimit records.</p>
2237
- </div>
2238
- <h2><a id="server-notes"></a>Server Notes</h2>
2239
- <div class="sectionbody">
2240
- <p>There is a server script included in the distribution called kbserver.rb.
2241
- This script uses DRb to turn KirbyBase into a client/server, multi-user
2242
- DBMS. This DBMS server handles table locking for you so you don't have to
2243
- worry about it.</p>
2244
- </div>
2245
- <h2><a id="tips-on-improving-performance"></a>Tips on improving performance</h2>
2246
- <div class="sectionbody">
2247
- <h3>Beware of Date/DateTime</h3>
2248
- <p>Converting a String (the format in which data is stored in a KirbyBase
2249
- table) to a Date/DateTime is slow. If you have a large table with a
2250
- Date/DateTime field, this can result in long query times.</p>
2251
- <p>To get around this, you can specify the field type as a :String, instead of
2252
- a :Date/:DateTime. Queries will still work correctly, because Date/DateTime
2253
- fields that are in String format sort the same way they would if they were
2254
- in native format. Here's an example. The following two expressions will
2255
- result in the same result set being returned:</p>
2256
- <div class="listingblock">
2257
- <div class="content">
2258
- <pre><tt>date_field &lt;= Date.new(2005, 05, 11)</tt></pre>
2259
- </div></div>
2260
- <p>and</p>
2261
- <div class="listingblock">
2262
- <div class="content">
2263
- <pre><tt>date_field_stored_as_string_field &lt;= "2005-05-11"</tt></pre>
2264
- </div></div>
2265
- <h3>Create indexes on large tables</h3>
2266
- <p>The larger a table becomes, the more sense it makes to create an index on
2267
- one or more of its fields. Even though you take a hit when KirbyBase first
2268
- initializes because it has to create the index arrays, you make up for it
2269
- after that in greatly improved query speeds. I have noticed speed-ups of
2270
- as much as 10x on large tables.</p>
2271
- <h3>Create indexes on foreign keys</h3>
2272
- <p>If you have a Link_many on a table field, you might want to think about
2273
- creating an index on the field in the child table that is being linked to.
2274
- When performing a one-to-many link, KirbyBase will automatically take
2275
- advantage of an index on the link field in the child table.</p>
2276
- <p>By the way, the same holds true for Lookups.</p>
2277
- <h3>When possible, always search by :recno</h3>
2278
- <p>This might be a no-brainer, but, if you have the chance to select by
2279
- :recno, use the built-in #select_by_recno_index method (or the #[] method).
2280
- This is even faster than selecting on a regularly indexed field, because the
2281
- :recno index that KirbyBase creates for each table is actually a Hash, not
2282
- an Array like all of the regular indexes. So selects are even faster.</p>
2283
- </div>
2284
- <h2><a id="single-user-diagram"></a>Single-user memory space diagram</h2>
2285
- <div class="sectionbody">
2286
- <div class="imageblock">
2287
- <div class="content">
2288
- <img src="images/single_user.png" alt="images/single_user.png"/>
2289
- </div>
2290
- <div class="image-title">Figure: Single-user (embedded) mode.</div>
2291
- </div>
2292
- </div>
2293
- <h2><a id="client-server-diagram"></a>Client/Server memory space diagram</h2>
2294
- <div class="sectionbody">
2295
- <div class="imageblock">
2296
- <div class="content">
2297
- <img src="images/client_server.png" alt="images/client_server.png"/>
2298
- </div>
2299
- <div class="image-title">Figure: Client/Server (separate memory spaces) mode.</div>
2300
- </div>
2301
- </div>
2302
- <h2><a id="license"></a>License</h2>
2303
- <div class="sectionbody">
2304
- <p>KirbyBase is distributed under the same license terms as Ruby.</p>
2305
- </div>
2306
- <h2><a id="credits"></a>Credits</h2>
2307
- <div class="sectionbody">
2308
- <div class="admonitionblock">
2309
- <table><tr>
2310
- <td class="icon">
2311
- <img src="./images/note.png" alt="Note" />
2312
- </td>
2313
- <td class="content">This manual was produced using the awesome text document formatter,
2314
- <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>.</td>
2315
- </tr></table>
2316
- </div>
2317
- </div>
2318
- <div id="footer">
2319
- <div id="footer-text">
2320
- Last updated 26-Jun-2006 14:36:38 EDT
2321
- </div>
2322
- </div>
2323
- </body>
2324
- </html>
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="generator" content="AsciiDoc 7.0.2" />
7
+ <style type="text/css">
8
+ /* Debug borders */
9
+ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
10
+ /*
11
+ border: 1px solid red;
12
+ */
13
+ }
14
+
15
+ body {
16
+ margin: 1em 5% 1em 5%;
17
+ }
18
+
19
+ a { color: blue; }
20
+ a:visited { color: fuchsia; }
21
+
22
+ em {
23
+ font-style: italic;
24
+ }
25
+
26
+ strong {
27
+ font-weight: bold;
28
+ }
29
+
30
+ tt {
31
+ color: navy;
32
+ }
33
+
34
+ h1, h2, h3, h4, h5, h6 {
35
+ color: #527bbd;
36
+ font-family: sans-serif;
37
+ margin-top: 1.2em;
38
+ margin-bottom: 0.5em;
39
+ line-height: 1.3;
40
+ }
41
+
42
+ h1 {
43
+ border-bottom: 2px solid silver;
44
+ }
45
+ h2 {
46
+ border-bottom: 2px solid silver;
47
+ padding-top: 0.5em;
48
+ }
49
+
50
+ div.sectionbody {
51
+ font-family: serif;
52
+ margin-left: 0;
53
+ }
54
+
55
+ hr {
56
+ border: 1px solid silver;
57
+ }
58
+
59
+ p {
60
+ margin-top: 0.5em;
61
+ margin-bottom: 0.5em;
62
+ }
63
+
64
+ pre {
65
+ padding: 0;
66
+ margin: 0;
67
+ }
68
+
69
+ span#author {
70
+ color: #527bbd;
71
+ font-family: sans-serif;
72
+ font-weight: bold;
73
+ font-size: 1.2em;
74
+ }
75
+ span#email {
76
+ }
77
+ span#revision {
78
+ font-family: sans-serif;
79
+ }
80
+
81
+ div#footer {
82
+ font-family: sans-serif;
83
+ font-size: small;
84
+ border-top: 2px solid silver;
85
+ padding-top: 0.5em;
86
+ margin-top: 4.0em;
87
+ }
88
+ div#footer-text {
89
+ float: left;
90
+ padding-bottom: 0.5em;
91
+ }
92
+ div#footer-badges {
93
+ float: right;
94
+ padding-bottom: 0.5em;
95
+ }
96
+
97
+ div#preamble,
98
+ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
99
+ div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
100
+ div.admonitionblock {
101
+ margin-right: 10%;
102
+ margin-top: 1.5em;
103
+ margin-bottom: 1.5em;
104
+ }
105
+ div.admonitionblock {
106
+ margin-top: 2.5em;
107
+ margin-bottom: 2.5em;
108
+ }
109
+
110
+ div.content { /* Block element content. */
111
+ padding: 0;
112
+ }
113
+
114
+ /* Block element titles. */
115
+ div.title, caption.title {
116
+ font-family: sans-serif;
117
+ font-weight: bold;
118
+ text-align: left;
119
+ margin-top: 1.0em;
120
+ margin-bottom: 0.5em;
121
+ }
122
+ div.title + * {
123
+ margin-top: 0;
124
+ }
125
+
126
+ td div.title:first-child {
127
+ margin-top: 0.0em;
128
+ }
129
+ div.content div.title:first-child {
130
+ margin-top: 0.0em;
131
+ }
132
+ div.content + div.title {
133
+ margin-top: 0.0em;
134
+ }
135
+
136
+ div.sidebarblock > div.content {
137
+ background: #ffffee;
138
+ border: 1px solid silver;
139
+ padding: 0.5em;
140
+ }
141
+
142
+ div.listingblock > div.content {
143
+ border: 1px solid silver;
144
+ background: #f4f4f4;
145
+ padding: 0.5em;
146
+ }
147
+
148
+ div.quoteblock > div.content {
149
+ padding-left: 2.0em;
150
+ }
151
+ div.quoteblock .attribution {
152
+ text-align: right;
153
+ }
154
+
155
+ div.admonitionblock .icon {
156
+ vertical-align: top;
157
+ font-size: 1.1em;
158
+ font-weight: bold;
159
+ text-decoration: underline;
160
+ color: #527bbd;
161
+ padding-right: 0.5em;
162
+ }
163
+ div.admonitionblock td.content {
164
+ padding-left: 0.5em;
165
+ border-left: 2px solid silver;
166
+ }
167
+
168
+ div.exampleblock > div.content {
169
+ border-left: 2px solid silver;
170
+ padding: 0.5em;
171
+ }
172
+
173
+ div.verseblock div.content {
174
+ white-space: pre;
175
+ }
176
+
177
+ div.imageblock div.content { padding-left: 0; }
178
+ div.imageblock img { border: 1px solid silver; }
179
+ span.image img { border-style: none; }
180
+
181
+ dl {
182
+ margin-top: 0.8em;
183
+ margin-bottom: 0.8em;
184
+ }
185
+ dt {
186
+ margin-top: 0.5em;
187
+ margin-bottom: 0;
188
+ font-style: italic;
189
+ }
190
+ dd > *:first-child {
191
+ margin-top: 0;
192
+ }
193
+
194
+ ul, ol {
195
+ list-style-position: outside;
196
+ }
197
+ ol.olist2 {
198
+ list-style-type: lower-alpha;
199
+ }
200
+
201
+ div.tableblock > table {
202
+ border-color: #527bbd;
203
+ border-width: 3px;
204
+ }
205
+ thead {
206
+ font-family: sans-serif;
207
+ font-weight: bold;
208
+ }
209
+ tfoot {
210
+ font-weight: bold;
211
+ }
212
+
213
+ div.hlist {
214
+ margin-top: 0.8em;
215
+ margin-bottom: 0.8em;
216
+ }
217
+ td.hlist1 {
218
+ vertical-align: top;
219
+ font-style: italic;
220
+ padding-right: 0.8em;
221
+ }
222
+ td.hlist2 {
223
+ vertical-align: top;
224
+ }
225
+
226
+ @media print {
227
+ div#footer-badges { display: none; }
228
+ }
229
+ /* Workarounds for IE6's broken and incomplete CSS2. */
230
+
231
+ div.sidebar-content {
232
+ background: #ffffee;
233
+ border: 1px solid silver;
234
+ padding: 0.5em;
235
+ }
236
+ div.sidebar-title, div.image-title {
237
+ font-family: sans-serif;
238
+ font-weight: bold;
239
+ margin-top: 0.0em;
240
+ margin-bottom: 0.5em;
241
+ }
242
+
243
+ div.listingblock div.content {
244
+ border: 1px solid silver;
245
+ background: #f4f4f4;
246
+ padding: 0.5em;
247
+ }
248
+
249
+ div.quoteblock-content {
250
+ padding-left: 2.0em;
251
+ }
252
+
253
+ div.exampleblock-content {
254
+ border-left: 2px solid silver;
255
+ padding-left: 0.5em;
256
+ }
257
+ </style>
258
+ <title>KirbyBase Manual (Ruby Version)</title>
259
+ </head>
260
+ <body>
261
+ <div id="header">
262
+ <h1>KirbyBase Manual (Ruby Version)</h1>
263
+ <span id="author">Jamey Cribbs</span><br />
264
+ <span id="email"><tt>&lt;<a href="mailto:jcribbs@netpromi.com">jcribbs@netpromi.com</a>&gt;</tt></span><br />
265
+ v2.6 June 2006
266
+ </div>
267
+ <div id="preamble">
268
+ <div class="sectionbody">
269
+ <div class="imageblock">
270
+ <div class="content">
271
+ <img src="images/kirby1.jpg" alt="images/kirby1.jpg"/>
272
+ </div>
273
+ <div class="image-title">Figure: Kirby, pictured here in attack mode.</div>
274
+ </div>
275
+ </div>
276
+ </div>
277
+ <h2>Table of Contents</h2>
278
+ <div class="sectionbody">
279
+ <div class="sidebarblock">
280
+ <div class="sidebar-content">
281
+ <ol>
282
+ <li>
283
+ <p>
284
+ <a href="#introduction">Introduction</a>
285
+ </p>
286
+ </li>
287
+ <li>
288
+ <p>
289
+ <a href="#connecting-to-a-database">Connecting to a database</a>
290
+ </p>
291
+ </li>
292
+ <li>
293
+ <p>
294
+ <a href="#creating-a-new-table">Creating a new table</a>
295
+ </p>
296
+ <ol class="olist2">
297
+ <li>
298
+ <p>
299
+ <a href="#field-types">Database field types</a>
300
+ </p>
301
+ </li>
302
+ <li>
303
+ <p>
304
+ <a href="#recno">The recno field</a>
305
+ </p>
306
+ </li>
307
+ <li>
308
+ <p>
309
+ <a href="#encrypt">Turning on encryption</a>
310
+ </p>
311
+ </li>
312
+ <li>
313
+ <p>
314
+ <a href="#record-class">Specifying a custom record class</a>
315
+ </p>
316
+ </li>
317
+ <li>
318
+ <p>
319
+ <a href="#defaults">Specifying default values</a>
320
+ </p>
321
+ </li>
322
+ <li>
323
+ <p>
324
+ <a href="#requireds">Specifying required fields</a>
325
+ </p>
326
+ </li>
327
+ <li>
328
+ <p>
329
+ <a href="#creating-indexes">Indexes</a>
330
+ </p>
331
+ </li>
332
+ <li>
333
+ <p>
334
+ <a href="#a-note-about-indexes">A note about indexes</a>
335
+ </p>
336
+ </li>
337
+ <li>
338
+ <p>
339
+ <a href="#creating-lookup-fields">Lookup Fields</a>
340
+ </p>
341
+ </li>
342
+ <li>
343
+ <p>
344
+ <a href="#creating-link-many-fields">Link_many Fields</a>
345
+ </p>
346
+ </li>
347
+ <li>
348
+ <p>
349
+ <a href="#creating-calculated-fields">Calculated Fields</a>
350
+ </p>
351
+ </li>
352
+ </ol>
353
+ </li>
354
+ <li>
355
+ <p>
356
+ <a href="#obtaining-a-reference-to-an-existing-table">Obtaining a reference to an existing table</a>
357
+ </p>
358
+ </li>
359
+ <li>
360
+ <p>
361
+ <a href="#insert-method">The insert method</a>
362
+ </p>
363
+ </li>
364
+ <li>
365
+ <p>
366
+ <a href="#how-to-select-records">How to select records</a>
367
+ </p>
368
+ <ol class="olist2">
369
+ <li>
370
+ <p>
371
+ <a href="#select-method">The select method</a>
372
+ </p>
373
+ </li>
374
+ <li>
375
+ <p>
376
+ <a href="#selecting-by-index">Selecting by index</a>
377
+ </p>
378
+ </li>
379
+ <li>
380
+ <p>
381
+ <a href="#selecting-by-recno-index">Selecting by :recno index</a>
382
+ </p>
383
+ </li>
384
+ <li>
385
+ <p>
386
+ <a href="#selects-involving-lookups-or-link-manys">Selects involving Lookups or Link_manys</a>
387
+ </p>
388
+ </li>
389
+ <li>
390
+ <p>
391
+ <a href="#a-note-about-nil-values">A note about nil values</a>
392
+ </p>
393
+ </li>
394
+ </ol>
395
+ </li>
396
+ <li>
397
+ <p>
398
+ <a href="#kbresultset">KBResultSet</a>
399
+ </p>
400
+ <ol class="olist2">
401
+ <li>
402
+ <p>
403
+ <a href="#sorting-a-result-set">Sorting a result set</a>
404
+ </p>
405
+ </li>
406
+ <li>
407
+ <p>
408
+ <a href="#to-report">Producing a report from a result set</a>
409
+ </p>
410
+ </li>
411
+ <li>
412
+ <p>
413
+ <a href="#crosstabs">CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</a>
414
+ </p>
415
+ </li>
416
+ </ol>
417
+ </li>
418
+ <li>
419
+ <p>
420
+ <a href="#how-to-update-records">How to update records</a>
421
+ </p>
422
+ <ol class="olist2">
423
+ <li>
424
+ <p>
425
+ <a href="#update-method">The update method</a>
426
+ </p>
427
+ </li>
428
+ <li>
429
+ <p>
430
+ <a href="#set-method">The set method</a>
431
+ </p>
432
+ </li>
433
+ <li>
434
+ <p>
435
+ <a href="#update-all-method">The update_all method</a>
436
+ </p>
437
+ </li>
438
+ </ol>
439
+ </li>
440
+ <li>
441
+ <p>
442
+ <a href="#how-to-delete-records">How to delete records</a>
443
+ </p>
444
+ <ol class="olist2">
445
+ <li>
446
+ <p>
447
+ <a href="#delete-method">The delete method</a>
448
+ </p>
449
+ </li>
450
+ <li>
451
+ <p>
452
+ <a href="#clear-method">The clear method</a>
453
+ </p>
454
+ </li>
455
+ </ol>
456
+ </li>
457
+ <li>
458
+ <p>
459
+ <a href="#pack-method">The pack method</a>
460
+ </p>
461
+ </li>
462
+ <li>
463
+ <p>
464
+ <a href="#memo-and-blob-fields">Memo and Blob Fields</a>
465
+ </p>
466
+ </li>
467
+ <li>
468
+ <p>
469
+ <a href="#misc-kirbybase-methods">Miscellaneous KirbyBase methods</a>
470
+ </p>
471
+ <ol class="olist2">
472
+ <li>
473
+ <p>
474
+ <a href="#drop-table">KirbyBase#drop_table</a>
475
+ </p>
476
+ </li>
477
+ <li>
478
+ <p>
479
+ <a href="#tables">KirbyBase#tables</a>
480
+ </p>
481
+ </li>
482
+ <li>
483
+ <p>
484
+ <a href="#table-exists">KirbyBase#table_exists?</a>
485
+ </p>
486
+ </li>
487
+ <li>
488
+ <p>
489
+ <a href="#rename-table">KirbyBase#rename_table</a>
490
+ </p>
491
+ </li>
492
+ </ol>
493
+ </li>
494
+ <li>
495
+ <p>
496
+ <a href="#misc-kbtable-methods">Miscellaneous KBTable methods</a>
497
+ </p>
498
+ <ol class="olist2">
499
+ <li>
500
+ <p>
501
+ <a href="#update-by-recno">KBTable#[]=</a>
502
+ </p>
503
+ </li>
504
+ <li>
505
+ <p>
506
+ <a href="#get-by-recno">KBTable#[]</a>
507
+ </p>
508
+ </li>
509
+ <li>
510
+ <p>
511
+ <a href="#field-names">KBTable#field_names</a>
512
+ </p>
513
+ </li>
514
+ <li>
515
+ <p>
516
+ <a href="#field-types">KBTable#field_types</a>
517
+ </p>
518
+ </li>
519
+ <li>
520
+ <p>
521
+ <a href="#total-recs">KBTable#total_recs</a>
522
+ </p>
523
+ </li>
524
+ <li>
525
+ <p>
526
+ <a href="#import-csv">KBTable#import_csv</a>
527
+ </p>
528
+ </li>
529
+ <li>
530
+ <p>
531
+ <a href="#add-column">KBTable#add_column</a>
532
+ </p>
533
+ </li>
534
+ <li>
535
+ <p>
536
+ <a href="#drop-column">KBTable#drop_column</a>
537
+ </p>
538
+ </li>
539
+ <li>
540
+ <p>
541
+ <a href="#rename-column">KBTable#rename_column</a>
542
+ </p>
543
+ </li>
544
+ <li>
545
+ <p>
546
+ <a href="#change-column-type">KBTable#change_column_type</a>
547
+ </p>
548
+ </li>
549
+ <li>
550
+ <p>
551
+ <a href="#change-column-default-value">KBTable#change_column_defaul_value</a>
552
+ </p>
553
+ </li>
554
+ <li>
555
+ <p>
556
+ <a href="#change-column-required">KBTable#change_column_required</a>
557
+ </p>
558
+ </li>
559
+ <li>
560
+ <p>
561
+ <a href="#add-index">KBTable#add_index</a>
562
+ </p>
563
+ </li>
564
+ <li>
565
+ <p>
566
+ <a href="#drop-index">KBTable#drop_index</a>
567
+ </p>
568
+ </li>
569
+ </ol>
570
+ </li>
571
+ <li>
572
+ <p>
573
+ <a href="#special-characters-in-data">Special characters in data</a>
574
+ </p>
575
+ </li>
576
+ <li>
577
+ <p>
578
+ <a href="#table-structure">Table Structure</a>
579
+ </p>
580
+ </li>
581
+ <li>
582
+ <p>
583
+ <a href="#server-notes">Server Notes</a>
584
+ </p>
585
+ </li>
586
+ <li>
587
+ <p>
588
+ <a href="#tips-on-improving-performance">Tips on improving performance</a>
589
+ </p>
590
+ </li>
591
+ <li>
592
+ <p>
593
+ <a href="#single-user-diagram">Single-user memory space diagram</a>
594
+ </p>
595
+ </li>
596
+ <li>
597
+ <p>
598
+ <a href="#client-server-diagram">Client/Server memory space diagram</a>
599
+ </p>
600
+ </li>
601
+ <li>
602
+ <p>
603
+ <a href="#license">License</a>
604
+ </p>
605
+ </li>
606
+ <li>
607
+ <p>
608
+ <a href="#credits">Credits</a>
609
+ </p>
610
+ </li>
611
+ </ol>
612
+ </div></div>
613
+ </div>
614
+ <h2><a id="introduction"></a>Introduction</h2>
615
+ <div class="sectionbody">
616
+ <p>KirbyBase is a simple, pure-Ruby, flat-file database management system.
617
+ Some of its features include:</p>
618
+ <ul>
619
+ <li>
620
+ <p>
621
+ Since KirbyBase is written in Ruby, it runs anywhere that Ruby runs. It
622
+ is easy to distribute, since the entire DBMS is in one (approx. 100k) code
623
+ file.
624
+ </p>
625
+ </li>
626
+ <li>
627
+ <p>
628
+ All data is kept in plain-text, delimited files that can be edited by
629
+ hand. This gives you the ability to make changes by just opening the file
630
+ up in a text editor, or you can use another programming language to read the
631
+ file in and do things with it.
632
+ </p>
633
+ </li>
634
+ <li>
635
+ <p>
636
+ It can be used as an embedded database or in a client/server, multi-user
637
+ mode. To switch from one mode to the other, you only have to change one
638
+ line in your program. Included in the distribution is a sample database
639
+ server script using DRb.
640
+ </p>
641
+ </li>
642
+ <li>
643
+ <p>
644
+ Tables are kept on disk during use and accessed from disk when selecting,
645
+ updating, inserting, and deleting records. Changes to a table are written
646
+ immediately to disk. KirbyBase is not an "in-memory" database. Once you
647
+ update the database in your program, you can be assured that the change has
648
+ been saved to disk. The chance of lost data due to power interruptions, or
649
+ disk crashes is much reduced. Also, since the entire database does not have
650
+ to reside in memory at once, KirbyBase should run adequately on a
651
+ memory-constrained system.
652
+ </p>
653
+ </li>
654
+ <li>
655
+ <p>
656
+ You can specify the type of data that each field will hold. The available
657
+ data types are: String, Integer, Float, Boolean, Time, Date, DateTime, Memo,
658
+ Blob, and YAML.
659
+ </p>
660
+ </li>
661
+ <li>
662
+ <p>
663
+ The query syntax is very "rubyish". Instead of having to use another
664
+ language like SQL, you can express your query using Ruby code blocks.
665
+ </p>
666
+ </li>
667
+ <li>
668
+ <p>
669
+ All inserted records have an auto-incrementing primary key that is
670
+ guaranteed to uniquely identify the record throughout its lifetime.
671
+ </p>
672
+ </li>
673
+ <li>
674
+ <p>
675
+ You can specify that the result set be sorted on multiple fields, each
676
+ one either ascending or descending.
677
+ </p>
678
+ </li>
679
+ <li>
680
+ <p>
681
+ You can specify that certain fields be indexed. Using an index in a select
682
+ query can greatly improve performance on large tables (I've seen 10x speed
683
+ improvements). Index maintenance is completely handled by KirbyBase.
684
+ </p>
685
+ </li>
686
+ <li>
687
+ <p>
688
+ You can specify that a field has a "lookup table". Whenever that field is
689
+ accessed, the corresponding record from the lookup table is automatically
690
+ available.
691
+ </p>
692
+ </li>
693
+ <li>
694
+ <p>
695
+ You can specify one-to-many links between tables, somewhat analogous to a
696
+ "join" in SQL.
697
+ </p>
698
+ </li>
699
+ <li>
700
+ <p>
701
+ You can create calculated fields that are computed at runtime.
702
+ </p>
703
+ </li>
704
+ <li>
705
+ <p>
706
+ It is fairly fast, comparing favorably to SQLite.
707
+ </p>
708
+ </li>
709
+ </ul>
710
+ <p>In meeting your DBMS needs, KirbyBase fits in somewhere between plain
711
+ text files and small SQL database management systems like SQLite and
712
+ MySQL.</p>
713
+ <div class="sidebarblock">
714
+ <div class="sidebar-content">
715
+ <div class="sidebar-title">Drop me a line!</div>
716
+ <p>If you find a use for KirbyBase, please send me an email telling how you
717
+ use it, whether it is ok for me to mention your application on the
718
+ "KirbyBase Applications" webpage, and possibly a link to your application's
719
+ webpage (if you have one).</p>
720
+ </div></div>
721
+ </div>
722
+ <h2><a id="connecting-to-a-database"></a>Connecting to a database</h2>
723
+ <div class="sectionbody">
724
+ <p>To use Kirbybase, you first need to require the module:</p>
725
+ <div class="listingblock">
726
+ <div class="content">
727
+ <pre><tt>require 'kirbybase'</tt></pre>
728
+ </div></div>
729
+ <p>Then create an instance:</p>
730
+ <div class="listingblock">
731
+ <div class="content">
732
+ <pre><tt>db = KirbyBase.new</tt></pre>
733
+ </div></div>
734
+ <p>By default, the instance is a local connection using the same memory space
735
+ as your application. To specify a client/server connection, it would look
736
+ like this:</p>
737
+ <div class="listingblock">
738
+ <div class="content">
739
+ <pre><tt>db = KirbyBase.new(:client, 'localhost', 44444)</tt></pre>
740
+ </div></div>
741
+ <p>Of course, you would substitute your server's ip address and port number.</p>
742
+ <p>To specify a different location (other than the current directory) for the
743
+ database files, you need to pass the location as an argument, like so:</p>
744
+ <div class="listingblock">
745
+ <div class="content">
746
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './data')</tt></pre>
747
+ </div></div>
748
+ <p>KirbyBase treats every file in the specified directory that has the proper
749
+ extension as a database table. The default extension is ".tbl". To specify
750
+ a different extension, pass this as an argument, like so:</p>
751
+ <div class="listingblock">
752
+ <div class="content">
753
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.dat')</tt></pre>
754
+ </div></div>
755
+ <p>To specify a different location other than the current directory for any
756
+ memo/blob files, you need to pass the location as an argument, like so:</p>
757
+ <div class="listingblock">
758
+ <div class="content">
759
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.tbl', './memos')</tt></pre>
760
+ </div></div>
761
+ <p>If you don't want KirbyBase to spend time initially creating all of the
762
+ indexes for the tables in the database, you can pass true as the
763
+ delay_index_creation argument:</p>
764
+ <div class="listingblock">
765
+ <div class="content">
766
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.tbl', './', true)</tt></pre>
767
+ </div></div>
768
+ <p>KirbyBase will skip initial index creation and will create a table's
769
+ indexes when the table is first referenced.</p>
770
+ <p>You can also specify the arguments via a code block. So, if you don't want
771
+ to have to specify a bunch of arguments just to get to the one you want,
772
+ put it in a code block attached to the method call. You could re-code the
773
+ previous example like so:</p>
774
+ <div class="listingblock">
775
+ <div class="content">
776
+ <pre><tt>db = KirbyBase.new { |d| d.delay_index_creation = true }</tt></pre>
777
+ </div></div>
778
+ </div>
779
+ <h2><a id="creating-a-new-table"></a>Creating a new table</h2>
780
+ <div class="sectionbody">
781
+ <p>To create a new table, you specify the table name, and a name and type for
782
+ each column. For example, to create a table containing information on World
783
+ War II planes:</p>
784
+ <div class="listingblock">
785
+ <div class="content">
786
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
787
+ :role, :String, :speed, :Integer, :range, :Integer, :began_service, :Date,
788
+ :still_flying, :Boolean)</tt></pre>
789
+ </div></div>
790
+ <div class="sidebarblock">
791
+ <a id="field-types"></a>
792
+ <div class="sidebar-content">
793
+ <div class="sidebar-title">KirbyBase Field Types</div>
794
+ <div class="admonitionblock">
795
+ <table><tr>
796
+ <td class="icon">
797
+ <img src="./images/tip.png" alt="Tip" />
798
+ </td>
799
+ <td class="content">:String, :Integer, :Float, :Boolean(true/false), :Time, :Date,
800
+ :DateTime, :Memo, :Blob, and :YAML.</td>
801
+ </tr></table>
802
+ </div>
803
+ </div></div>
804
+ <div class="sidebarblock">
805
+ <a id="recno"></a>
806
+ <div class="sidebar-content">
807
+ <div class="sidebar-title">The recno field</div>
808
+ <div class="admonitionblock">
809
+ <table><tr>
810
+ <td class="icon">
811
+ <img src="./images/important.png" alt="Important" />
812
+ </td>
813
+ <td class="content">KirbyBase will automatically create a primary key field, called
814
+ recno, with a type of :Integer, for each table. This field will be
815
+ auto-incremented each time a record is inserted. You can use this field in
816
+ select, update, and delete queries, but you can't modify this field.</td>
817
+ </tr></table>
818
+ </div>
819
+ </div></div>
820
+ <h3><a id="encrypt"></a>Turning on encryption</h3>
821
+ <p>You can also specify whether the table should be encrypted. This will save
822
+ the table to disk encrypted (more like obfuscated) using a Vignere Cipher.
823
+ This is similar to rot13, but it uses a key to determine character
824
+ substitution. Still, this encryption will only stymie the most casual
825
+ of hackers. Do not rely on it to keep sensitive data safe! You specify
826
+ encryption by using a code block attached to #create_table:</p>
827
+ <div class="listingblock">
828
+ <div class="content">
829
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
830
+ t.encrypt = true
831
+ end</tt></pre>
832
+ </div></div>
833
+ <h3><a id="record-class"></a>Specifying a custom record class</h3>
834
+ <p>You can also specify that you want records of the table to be returned to
835
+ you as instances of a class. To do this, simply define a class before you
836
+ call #create_table. This class needs to have an accessor for each fieldname
837
+ in the table.</p>
838
+ <p>If this class has a class method, called #kb_create, KirbyBase, when
839
+ creating each record of the result set, will call that method and pass it
840
+ the field values of the result record. #kb_create will need to handle
841
+ creating an instance of the record class itself.</p>
842
+ <p>Here is an example of #kb_create in action:</p>
843
+ <div class="listingblock">
844
+ <div class="content">
845
+ <pre><tt>class Foobar
846
+ attr_accessor(:recno, :name, :country, :role, :speed, :range,
847
+ :began_service, :still_flying, :alpha, :beta)
848
+
849
+ def Foobar.kb_create(recno, name, country, role, speed, range,
850
+ began_service, still_flying)
851
+ name ||= 'No Name!'
852
+ speed ||= 0
853
+ began_service ||= Date.today
854
+
855
+ Foobar.new do |x|
856
+ x.recno = recno
857
+ x.name = name
858
+ x.country = country
859
+ x.role = role
860
+ x.speed = speed
861
+ x.range = range
862
+ x.began_service = began_service
863
+ x.still_flying = still_flying
864
+ end
865
+ end
866
+
867
+ def initialize(&amp;block)
868
+ instance_eval(&amp;block)
869
+ end
870
+ end</tt></pre>
871
+ </div></div>
872
+ <p>Pass this class to #create_table in an attached code block, like so:</p>
873
+ <div class="listingblock">
874
+ <div class="content">
875
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
876
+ t.record_class = Foobar
877
+ end</tt></pre>
878
+ </div></div>
879
+ <p>Now, when you call #select, the result set will be made up of instances of
880
+ Foobar, instead of the default, which is instances of Struct. This also
881
+ works the other way. You can now specify instances of Foobar as input to
882
+ the #insert, #update and #set methods. More on those methods below.</p>
883
+ <p>If the custom record class does not respond to #kb_create, KirbyBase will
884
+ call the class's #new method instead, passing it all of the field values.</p>
885
+ <div class="sidebarblock">
886
+ <div class="sidebar-content">
887
+ <div class="admonitionblock">
888
+ <table><tr>
889
+ <td class="icon">
890
+ <img src="./images/important.png" alt="Important" />
891
+ </td>
892
+ <td class="content">The #create_table method will return a reference to a KBTable
893
+ instance. This is the only way, besides calling KirbyBase#get_table, that
894
+ you can obtain a handle to a KBTable instance. You can not call KBTable#new
895
+ directly.</td>
896
+ </tr></table>
897
+ </div>
898
+ </div></div>
899
+ <h3>Specifying Advanced Field Type Information</h3>
900
+ <p>There are four types of advanced field type information that you can
901
+ specify:
902
+ Defaults, Requireds, Indexes and Extras (i.e. Lookup, Link_many,
903
+ Calculated).</p>
904
+ <h4><a id="defaults"></a>Default Field Values</h4>
905
+ <p>Normally, when you insert a record, if you don't specify a value for a field
906
+ or specify nil as the value, KirbyBase stores this as an empty string
907
+ (i.e. "") in the table's physical file, and returns it as a nil value when
908
+ you do a #select.</p>
909
+ <p>However, you can tell KirbyBase that you want a column to have a default
910
+ value. Only KBTable#insert is affected by default values. Default values
911
+ do not apply to updating a record. So, for inserts, there are two cases
912
+ where a default value, if one is specified, will be applied: (1) if nil
913
+ is specified for a field's value, and (2) if no value is specified for a
914
+ field.</p>
915
+ <p>For example, to specify that the category column has a default value, you
916
+ would code:</p>
917
+ <div class="listingblock">
918
+ <div class="content">
919
+ <pre><tt>db.create_table(:addressbook, :firstname, :String,
920
+ :lastname, :String, :phone_no, :String,
921
+ :category, {:DataType=&gt;:String, :Default=&gt;'Business'})</tt></pre>
922
+ </div></div>
923
+ <p>Notice that, since we are specifying advanced field type information, we
924
+ cannot just simply say :String for the second half of the field definition.
925
+ Instead, we have to pass a hash, with a :DataType item set to :String.
926
+ Next, because we are specifying a default value, we have to include a hash
927
+ item called :Default with its value set to whatever we want the default to
928
+ be. The default value must be of a type that is valid for the column.</p>
929
+ <h4><a id="requireds"></a>Required Fields</h4>
930
+ <p>Normally, when you insert or update a record, if you don't specify a value
931
+ for a field or specify nil as the value, KirbyBase stores this as an empty
932
+ string (i.e. "") in the table's physical file, and returns it as a nil
933
+ value when you do a #select.</p>
934
+ <p>However, you can tell KirbyBase that you want a column to be required
935
+ (i.e. you must supply a value and it can't be nil). When a record is
936
+ inserted or updated, an exception will be raised for any required field
937
+ that has not been given a value or been given a nil value.</p>
938
+ <p>For example, to specify that the category column is required, you would
939
+ code:</p>
940
+ <div class="listingblock">
941
+ <div class="content">
942
+ <pre><tt>db.create_table(:addressbook, :firstname, :String,
943
+ :lastname, :String, :phone_no, :String,
944
+ :category, {:DataType=&gt;:String, :Required=&gt;true})</tt></pre>
945
+ </div></div>
946
+ <p>Notice that, since we are specifying advanced field type information, we
947
+ cannot just simply say :String for the second half of the field definition.
948
+ Instead, we have to pass a hash, with a :DataType item set to :String.
949
+ Next, because we are specifying that a column is required, we have to
950
+ include a hash item called :Required with its value set to true.</p>
951
+ <h4><a id="creating-indexes"></a>Indexes</h4>
952
+ <p>Indexes are in-memory arrays that have an entry that corresponds to each
953
+ table record, but just holds the field values specified when the index was
954
+ created, plus the :recno of the actual table record. Because index arrays
955
+ are smaller than the actual table and because they are in-memory instead of
956
+ on-disk, using an index in a select query is usually much faster than
957
+ selecting against the table itself, especially when the table is quite
958
+ large.</p>
959
+ <p>To specify that an index is to be created, you need to tell KirbyBase which
960
+ fields are to be included in a particular index. You can have up to 5
961
+ indexes per table. Indexes can either contain single or multiple fields.
962
+ For example, to create an index on firstname and lastname for a table called
963
+ :addressbook, you would code:</p>
964
+ <div class="listingblock">
965
+ <div class="content">
966
+ <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
967
+ :lastname, {:DataType=&gt;:String, :Index=&gt;1},
968
+ :phone_no, :String)</tt></pre>
969
+ </div></div>
970
+ <p>Notice that, since we are specifying advanced field type information, we
971
+ cannot just simply say :String for the second half of the field definition.
972
+ Instead, we have to pass a hash, with a :DataType item set to :String.
973
+ Next, because we are creating an index, we have to include a hash item
974
+ called :Index with its value set from 1 to 5. For compound indexes, like
975
+ the one in the above example, we need to make sure that all fields in the
976
+ index have the same number. To have another index for a table, just make
977
+ sure you increment the index number. So, for example, if we wanted to have
978
+ another index for the :addressbook table on the field phone number, we would
979
+ code:</p>
980
+ <div class="listingblock">
981
+ <div class="content">
982
+ <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
983
+ :lastname, {:DataType=&gt;:String, :Index=&gt;1},
984
+ :phone_no, {:DataType=&gt;:String, :Index=&gt;2})</tt></pre>
985
+ </div></div>
986
+ <p>Notice how we just increment the index number to 2 for the :phone_no index.
987
+ Since there are no other fields with the same index number, this will create
988
+ an index with just the :phone_no field in it. You will see how to use
989
+ indexes in your select queries later.</p>
990
+ <div class="sidebarblock">
991
+ <a id="a-note-about-indexes"></a>
992
+ <div class="sidebar-content">
993
+ <div class="sidebar-title">A note about indexes</div>
994
+ <p>When KirbyBase initializes, it creates an instance for each table in
995
+ the database. It also creates each index array for each indexed field in
996
+ each table. So, if there are several large tables that have indexed fields,
997
+ this database initialization process could take several seconds. I decided
998
+ to have it operate this way, because I thought that it made more sense to
999
+ have a user application wait once upon initialization, rather than have it
1000
+ wait the first time a table is referenced. A user is more used to waiting
1001
+ for an application to properly initialize, so this initial delay, I thought,
1002
+ would feel more natural to the user, rather than a wait time in the middle
1003
+ of the application.</p>
1004
+ <p>If you find that this initial delay while indexes are created is
1005
+ un-acceptable, you can pass delay_index_creation=true to KirbyBase.new.
1006
+ This will bypass the initial index creation for all tables. Indexes for an
1007
+ individual table will be created when the table is first referenced.</p>
1008
+ <p>This is also an excellent reason to use the client/server capabilities of
1009
+ KirbyBase. In client/server mode, the database initialization processing is
1010
+ all done on the server, so, once this is done, any users starting their
1011
+ client application and connecting to the server will experience no delay due
1012
+ to index array creation.</p>
1013
+ </div></div>
1014
+ <h4><a id="creating-lookup-fields"></a>Lookup Fields</h4>
1015
+ <p>Lookup fields are fields that hold a reference to a record in another table.
1016
+ For example, say you have a table called :department that has fields called
1017
+ :dept_id, :dept_name, and :manager. Now, let's say that you don't want the
1018
+ :manager field to just hold the manager's name; you want it to point to the
1019
+ manager's record in the :employee table, which has fields like
1020
+ :employee_id, :firstname, :lastname, :ss_no, etc. What you want to do is
1021
+ to tell KirbyBase that the :dept.manager field should actually point to the
1022
+ manager's record in the :employee table (the "lookup" table). Here's how
1023
+ you would do that:</p>
1024
+ <div class="listingblock">
1025
+ <div class="content">
1026
+ <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
1027
+ :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee, :employee_id]})</tt></pre>
1028
+ </div></div>
1029
+ <p>Ok, what we have done here is to tell KirbyBase a little bit "extra" about
1030
+ the :manager field. We are specifying that whenever we ask for the value of
1031
+ :manager, we want KirbyBase to do a #select against the :employee table that
1032
+ compares the value of the :department.manager field to the value of the
1033
+ :employee.employee_id field. If an index is available for the
1034
+ :employee.employee_id field, KirbyBase will automatically use it.</p>
1035
+ <p>There is a shortcut to specifying a lookup field. If the :employee_id field
1036
+ has been designated a "key" field for the :employee table, we can even
1037
+ shorten our code and KirbyBase will figure it all out. For example, if the
1038
+ :employee table was created with this code:</p>
1039
+ <div class="listingblock">
1040
+ <div class="content">
1041
+ <pre><tt>db.create_table(:employee, :employee_id, {:DataType=&gt;:String, :Key=&gt;true},
1042
+ :firstname, :String, :lastname, :String)</tt></pre>
1043
+ </div></div>
1044
+ <p>Then the field definition for :manager could be re-written as:</p>
1045
+ <div class="listingblock">
1046
+ <div class="content">
1047
+ <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
1048
+ :manager, :employee)</tt></pre>
1049
+ </div></div>
1050
+ <p>KirbyBase will figure out that you want to compare :department.manager to
1051
+ :employee.employee_id.</p>
1052
+ <div class="sidebarblock">
1053
+ <div class="sidebar-content">
1054
+ <div class="admonitionblock">
1055
+ <table><tr>
1056
+ <td class="icon">
1057
+ <img src="./images/important.png" alt="Important" />
1058
+ </td>
1059
+ <td class="content">In order to use the shortcut when specifying a lookup field, the
1060
+ lookup table it is pointing to <strong>must</strong> already exist. This is so that
1061
+ KirbyBase can do the defaulting magic.</td>
1062
+ </tr></table>
1063
+ </div>
1064
+ </div></div>
1065
+ <h4><a id="creating-link-many-fields"></a>Link_many Fields</h4>
1066
+ <p>When you specify that a field has a Link_many, you are telling KirbyBase
1067
+ that you want to create a one-to-many link between this field and a subset
1068
+ of records from another table.</p>
1069
+ <p>For example, say you are creating an order entry system for your business.
1070
+ You have a master table called :orders that holds one record for each
1071
+ customer order that is placed. It has fields like: :order_id, :cust_id,
1072
+ :order_date, etc.</p>
1073
+ <p>Now, you also need a table that is going to have a record for each detail
1074
+ item type ordered. Let's call it :order_items and some of its fields would
1075
+ be: :item_no, :qty, :order_id.</p>
1076
+ <p>Notice that the detail table has a field called :order_id. This will hold
1077
+ the order_id linking it back to the :orders.order_id table. If a customer
1078
+ order's only one type of item, then there will only be one record in the
1079
+ :order_items table that has that order_id. But, if the customer places an
1080
+ order for many different types of items, there will be many records in the
1081
+ :order_items table that have the same order_id. That's why we say that
1082
+ there is a "one to many" link between the master (or parent) table, :orders,
1083
+ and the detail (or child) table, :order_items.</p>
1084
+ <p>When we select an :order record, we want the ability to also select all the
1085
+ detail records from the :order_items table that belong to that order. We do
1086
+ this by telling KirbyBase about the one-to-many link between the two
1087
+ tables. Here's how:</p>
1088
+ <div class="listingblock">
1089
+ <div class="content">
1090
+ <pre><tt>db.create_table(:orders, :order_id, :Integer, :cust_id, :Integer,
1091
+ :order_date, :Date, :items, {:DataType=&gt;:ResultSet, :Link_many=&gt;[:order_id,
1092
+ :order_items, :order_id]})
1093
+
1094
+ db.create_table(:order_items, :item_no, :Integer, :qty, :Integer,
1095
+ :order_id, :Integer)</tt></pre>
1096
+ </div></div>
1097
+ <p>Now, look at the :Link_many item in the field type definition hash in the
1098
+ above example. We are specifying that a field, called :items, be created
1099
+ with a field type of :ResultSet. We tell KirbyBase that, when we ask for
1100
+ the value of :items, it should do a #select on :order_items and return a
1101
+ KBResultSet that contains :order_items whose :order_id field (the last item
1102
+ in the array above), equals the value of the :orders.order_id field (the
1103
+ first item of the array above).</p>
1104
+ <p>If you opened up the :orders table file in a text editor, you would notice
1105
+ that, for each record, the :items field is blank. No data is ever stored in
1106
+ this field, since its value is always computed at runtime.</p>
1107
+ <h4><a id="creating-calculated-fields"></a>Calculated Fields</h4>
1108
+ <p>When you specify that a field is a Calculated field, you are telling
1109
+ KirbyBase to compute the value of the field at runtime, based on the code
1110
+ string that you pass it at table creation time.</p>
1111
+ <p>For example. let's say you have a table that is going to track your
1112
+ purchases. It will have fields like :purchase_date, :description, :qty, and
1113
+ :price.</p>
1114
+ <p>Let's say that you want to have a "virtual" field, called :total_cost, that
1115
+ is the result of quantity multiplied by price. You want this field
1116
+ calculated at runtime, so that if you change a record's quantity or price,
1117
+ the :total_cost field will automatically reflect the changes.
1118
+ Here's how you would define this table:</p>
1119
+ <div class="listingblock">
1120
+ <div class="content">
1121
+ <pre><tt>db.create_table(:purchases, :purchase_date, :Date, :description, :String,
1122
+ :qty, :Integer, :price, :Float, :total_cost, {:DataType=&gt;:Float,
1123
+ :Calculated=&gt;'qty*price'})</tt></pre>
1124
+ </div></div>
1125
+ <p>See how we tell KirbyBase how to calculate the field? By multiplying the
1126
+ :qty field by the :price field.</p>
1127
+ <p>If you opened up the :purchases file in a text editor, you would notice
1128
+ that, for each record, the :total_cost field is blank. No data is ever
1129
+ stored in this field, since its value is always computed at runtime.</p>
1130
+ </div>
1131
+ <h2><a id="obtaining-a-reference-to-an-existing-table"></a>Obtaining a reference to an existing table</h2>
1132
+ <div class="sectionbody">
1133
+ <p>If a table already exists and you need to get a reference to it so that you
1134
+ can insert, select, etc., you would call the #get_table method from your
1135
+ KirbyBase instance. This is how to obtain a handle to an existing table.
1136
+ You cannot call KBTable#new directly.</p>
1137
+ <div class="listingblock">
1138
+ <div class="content">
1139
+ <pre><tt>plane_tbl_another_reference = db.get_table(:plane)</tt></pre>
1140
+ </div></div>
1141
+ <p>Then, you can use it just like you would use a reference you got when
1142
+ you created a new table.</p>
1143
+ </div>
1144
+ <h2><a id="insert-method"></a>The insert method</h2>
1145
+ <div class="sectionbody">
1146
+ <p>To insert records into a table, you use the insert method. You can use an
1147
+ array, a hash, a struct, a code block, or an instance of the table's custom
1148
+ record class to specify the insert values.</p>
1149
+ <h3>Insert a record using an array for the input values:</h3>
1150
+ <div class="listingblock">
1151
+ <div class="content">
1152
+ <pre><tt>plane_tbl.insert('FW-190', 'Germany', 'Fighter', 399, 499,
1153
+ Date.new(1942,12,1), false)</tt></pre>
1154
+ </div></div>
1155
+ <p>The length of the data array must equal the number of columns in the table,
1156
+ <strong>not</strong> including the :recno column. Also, the data types must match. In the
1157
+ above example, specifying "399", instead of 399, would have resulted in an
1158
+ error.</p>
1159
+ <h3>Insert a record using a hash for the input values:</h3>
1160
+ <div class="listingblock">
1161
+ <div class="content">
1162
+ <pre><tt>plane_tbl.insert(:name='P-51', :country='USA', :role='Fighter', :speed=403,
1163
+ :range=1201, :began_service=Date.new(1943,6,24), :still_flying=true)</tt></pre>
1164
+ </div></div>
1165
+ <h3>Insert a record using a Struct for the input values:</h3>
1166
+ <div class="listingblock">
1167
+ <div class="content">
1168
+ <pre><tt>InputRec = Struct.new(:name, :country, :role, :speed, :range,
1169
+ :began_service, :still_flying)
1170
+ rec = InputRec.new('P-47', 'USA', 'Fighter', 365, 888, Date.new(1943,3,12),
1171
+ false)
1172
+
1173
+ plane_tbl.insert(rec)</tt></pre>
1174
+ </div></div>
1175
+ <h3>Insert a record using a code block for the input values:</h3>
1176
+ <div class="listingblock">
1177
+ <div class="content">
1178
+ <pre><tt>plane_tbl.insert do |r|
1179
+ r.name = 'B-17'
1180
+ r.country = 'USA'
1181
+ r.role = 'Bomber'
1182
+ r.speed = 315
1183
+ r.range = 1400
1184
+ r.began_service = Date.new(1937, 5, 1)
1185
+ r.still_flying = true
1186
+ end</tt></pre>
1187
+ </div></div>
1188
+ <h3>Insert a record using an instance of the table's custom record class:</h3>
1189
+ <div class="listingblock">
1190
+ <div class="content">
1191
+ <pre><tt>foo = Foobar.new do |x|
1192
+ x.name = 'Spitfire'
1193
+ x.country = 'Great Britain'
1194
+ x.role = 'Fighter'
1195
+ x.speed = 333
1196
+ x.range = 454
1197
+ x.began_service = Date.new(1936, 1, 1)
1198
+ x.still_flying = true
1199
+ x.alpha = "This variable won't be stored in KirbyBase."
1200
+ x.beta = 'Neither will this one.'
1201
+ end
1202
+
1203
+ plane_tbl.insert(foo)</tt></pre>
1204
+ </div></div>
1205
+ <div class="sidebarblock">
1206
+ <div class="sidebar-content">
1207
+ <div class="admonitionblock">
1208
+ <table><tr>
1209
+ <td class="icon">
1210
+ <img src="./images/note.png" alt="Note" />
1211
+ </td>
1212
+ <td class="content">The #insert method will return the record number of the newly created
1213
+ record. This is an auto-incremented integer generated by KirbyBase. This
1214
+ number will <strong>never</strong> change for the record and can be used as a unique
1215
+ identifier for the record.</td>
1216
+ </tr></table>
1217
+ </div>
1218
+ </div></div>
1219
+ </div>
1220
+ <h2><a id="how-to-select-records"></a>How to select records</h2>
1221
+ <div class="sectionbody">
1222
+ <p>The syntax you use to select records to perform operations on is the same
1223
+ for a select, update, or delete statement, so I wanted to cover, in
1224
+ general, how to create a query expression first, before getting to the
1225
+ specifics of select, update, and delete.</p>
1226
+ <p>In KirbyBase, query conditions are specified simply by using Ruby code
1227
+ blocks. Therefore, any code block that can be converted into a Proc object
1228
+ is valid. This allows for great flexibility, as you will see in the many
1229
+ examples below.</p>
1230
+ <div class="sidebarblock">
1231
+ <div class="sidebar-content">
1232
+ <div class="admonitionblock">
1233
+ <table><tr>
1234
+ <td class="icon">
1235
+ <img src="./images/tip.png" alt="Tip" />
1236
+ </td>
1237
+ <td class="content">You can find many examples of how to specify queries in the "examples"
1238
+ directory of the KirbyBase distribution.</td>
1239
+ </tr></table>
1240
+ </div>
1241
+ </div></div>
1242
+ <p>Now that we have a general understanding of how to select records to operate
1243
+ on, lets get more specific by looking at the select, update, and delete
1244
+ methods.</p>
1245
+ <h3><a id="select-method"></a>The select method</h3>
1246
+ <p>The select method allows you to ask for all records in a table that match
1247
+ certain selection criteria. Additionally, you can also specify which fields
1248
+ you want included in the result set. The select method returns an instance
1249
+ of KBResultSet, which is an array of records that satisfied the select
1250
+ criteria. KBResultSet is covered in more detail later in the manual.</p>
1251
+ <p>Here is the simplest example of a select statement:</p>
1252
+ <div class="listingblock">
1253
+ <div class="content">
1254
+ <pre><tt>result_set = plane_tbl.select</tt></pre>
1255
+ </div></div>
1256
+ <p>Since, no code block was specified, KirbyBase will include all records in
1257
+ the result set. Additionally, because a list of fields to include in the
1258
+ result set was not specified, KirbyBase will include all fields for each
1259
+ record in the result set.</p>
1260
+ <p>To specify that you only want a subset of fields in the result set, you list
1261
+ their field names as arguments to the select method. For example:</p>
1262
+ <div class="listingblock">
1263
+ <div class="content">
1264
+ <pre><tt>result_set = plane_tbl.select(:name, :speed)</tt></pre>
1265
+ </div></div>
1266
+ <p>To specify selection criteria, attach a code block to the select method
1267
+ call. For example, if you only wanted to select Japanese planes:</p>
1268
+ <div class="listingblock">
1269
+ <div class="content">
1270
+ <pre><tt>result_set = plane_tbl.select(:name, :speed) { |r| r.country == 'Japan' }</tt></pre>
1271
+ </div></div>
1272
+ <p>You can combine multiple expressions in the code block. For example, to
1273
+ select only US planes that have a speed greater than 350mph:</p>
1274
+ <div class="listingblock">
1275
+ <div class="content">
1276
+ <pre><tt>result_set = plane_tbl.select { |r| r.country == 'USA' and r.speed &gt; 350 }</tt></pre>
1277
+ </div></div>
1278
+ <p>You can use regular expressions in the code block. Let's select all Axis
1279
+ fighters:</p>
1280
+ <div class="listingblock">
1281
+ <div class="content">
1282
+ <pre><tt>result_set = plane_tbl.select do |r|
1283
+ r.country =~ /Germany|Japan/ and r.role == 'Fighter'
1284
+ end</tt></pre>
1285
+ </div></div>
1286
+ <h3><a id="selecting-by-index"></a>Selecting by index</h3>
1287
+ <p>Performing a select query using an index is almost identical to performing a
1288
+ regular select query. You just have to specify the particular select
1289
+ method, based on the index you wish to use.</p>
1290
+ <p>For example, say you have created an index on the :speed field of the
1291
+ :plane table. You want to search for all planes with a speed greater than
1292
+ 400 mph. Ruby automatically creates select methods for each one of the
1293
+ indexes of a table. So, you would code your select query like this:</p>
1294
+ <div class="listingblock">
1295
+ <div class="content">
1296
+ <pre><tt>plane_tbl.select_by_speed_index { |r| r.speed &gt; 400 }</tt></pre>
1297
+ </div></div>
1298
+ <p>Notice that you simply insert the name of the field as part of the method
1299
+ name. Its as simple as that.</p>
1300
+ <p>For compound indexes, you just need to specify the
1301
+ indexed field names in the select method in the same order as they are in
1302
+ the table. So, let's say you have indexed the :plane table on :country and
1303
+ :role, in one index. To select on this compound index, you would code:</p>
1304
+ <div class="listingblock">
1305
+ <div class="content">
1306
+ <pre><tt>plane_tbl.select_by_country_role_index do |r|
1307
+ r.country == 'Germany' and r.role == 'Fighter' }
1308
+ end</tt></pre>
1309
+ </div></div>
1310
+ <p>Notice how you just list both fields as part of the name of the select
1311
+ method, separated by underscores.</p>
1312
+ <div class="sidebarblock">
1313
+ <div class="sidebar-content">
1314
+ <div class="admonitionblock">
1315
+ <table><tr>
1316
+ <td class="icon">
1317
+ <img src="./images/warning.png" alt="Warning" />
1318
+ </td>
1319
+ <td class="content">If you specify a select method that does not exist, you will get an
1320
+ error. Likewise, if you specify a query by an index, yet include a field
1321
+ name in the query that is not part of the index, you will get an error.</td>
1322
+ </tr></table>
1323
+ </div>
1324
+ </div></div>
1325
+ <h3><a id="selecting-by-recno-index"></a>Selecting by :recno index</h3>
1326
+ <p>For each table, a :recno index is automatically created, whether or not
1327
+ other indexes are explicitly created by you. You can alway use this index
1328
+ to select records based solely on :recno. For example:</p>
1329
+ <div class="listingblock">
1330
+ <div class="content">
1331
+ <pre><tt>plane_tbl.select_by_recno_index { |r| [3, 45, 152].include?(r.recno) }</tt></pre>
1332
+ </div></div>
1333
+ <h3><a id="selects-involving-lookups-or-link-manys"></a>Selects Involving Lookups or Link_manys</h3>
1334
+ <p>Selects that involve Lookup fields or Link_many fields have a special case
1335
+ because both field types return complex objects rather than simple data
1336
+ types. For example, consider the lookup field example that I described
1337
+ earlier. For reference, here are the two table defintions again:</p>
1338
+ <div class="listingblock">
1339
+ <div class="content">
1340
+ <pre><tt>department_tbl = db.create_table(:department, :dept_id, :String,
1341
+ :dept_name, :String, :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee,
1342
+ :employee_id]})
1343
+
1344
+ employee_tbl = db.create_table(:employee, :employee_id, {:DataType=&gt;:String,
1345
+ :Key=&gt;true}, :firstname, :String, :lastname, :String)</tt></pre>
1346
+ </div></div>
1347
+ <p>To find the department managed by John Doe, the select query would look like
1348
+ this:</p>
1349
+ <div class="listingblock">
1350
+ <div class="content">
1351
+ <pre><tt>department_tbl.select do |r|
1352
+ r.manager.firstname == 'John' and r.manager.lastname == 'Doe'
1353
+ end</tt></pre>
1354
+ </div></div>
1355
+ <p>Notice how the manager attribute is itself a Struct with its own members.</p>
1356
+ <p>To print out all departments including the manager's full name:</p>
1357
+ <div class="listingblock">
1358
+ <div class="content">
1359
+ <pre><tt>department_tbl.select.each do |r|
1360
+ puts 'Department: %s Manager: %s %s' % [r.dept_name,
1361
+ r.manager.firstname, r.manager.lastname]
1362
+ end</tt></pre>
1363
+ </div></div>
1364
+ <p>Selects involving Link_many fields are slightly different because they
1365
+ involve ResultSets instead of just single objects. Here's the table
1366
+ definitions from the earlier Link_many discussion:</p>
1367
+ <div class="listingblock">
1368
+ <div class="content">
1369
+ <pre><tt>orders_tbl = db.create_table(:orders, :order_id, :Integer,
1370
+ :cust_id, :Integer, :order_date, :Date, :items, {:DataType=&gt;:ResultSet,
1371
+ :Link_many=&gt;[:order_id, :order_items, :order_id]})
1372
+
1373
+ order_items_tbl = db.create_table(:order_items, :item_no, :Integer,
1374
+ :qty, :Integer, :order_id, :Integer)</tt></pre>
1375
+ </div></div>
1376
+ <p>To print an order and all of its associated detail items:</p>
1377
+ <div class="listingblock">
1378
+ <div class="content">
1379
+ <pre><tt>result = order_tbl.select { |r| r.order_id == 501 }.first
1380
+ puts '%d %d %s' % [result.order_id, result.cust_id, result.order_date]
1381
+
1382
+ result.items.each { |item| puts '%d %d' % [item.item_no, item.qty] }</tt></pre>
1383
+ </div></div>
1384
+ <p>Notice how the items attribute in the ResultSet is itself a ResultSet
1385
+ containing all of the :order_items records that belong to the selected
1386
+ order.</p>
1387
+ <h3><a id="a-note-about-nil-values"></a>A Note About nil Values</h3>
1388
+ <p>Beginning in version 2.6 of KirbyBase, nil values are no longer stored as
1389
+ the singleton instance of NilClass in the database. Now, they are stored
1390
+ as references to the singleton instance, kb_nil, of KBNilClass. KBNilClass
1391
+ is as similar to NilClass as possible, but since NilClass cannot
1392
+ be sub-classed, there are a few minor differences.</p>
1393
+ <p>However, this should all be transparent to you because KirbyBase converts
1394
+ kb_nil values to Ruby nil values before returning the results of a query.
1395
+ The only time you will need to be worried about kb_nil is when you need to
1396
+ explicitly test for a nil value in a query. For example:</p>
1397
+ <div class="listingblock">
1398
+ <div class="content">
1399
+ <pre><tt>plane_tbl.select {|r| r.speed == kb_nil}</tt></pre>
1400
+ </div></div>
1401
+ <p>which is the same as:</p>
1402
+ <div class="listingblock">
1403
+ <div class="content">
1404
+ <pre><tt>plane_tbl.select {|r| r.speed.kb_nil?}</tt></pre>
1405
+ </div></div>
1406
+ <p>Notice how it is very similar to how you would test for nil?</p>
1407
+ <p>The only other difference you will now notice, is if you open up a table in
1408
+ a text editor. Now, nil values are stored as "kb_nil", instead of being
1409
+ stored as an empty string (i.e. ""). This has the added advantage that
1410
+ KirbyBase can now distinguish between empty strings and nil values. In the
1411
+ past, if you saved an empty string as a field value, the next time you
1412
+ selected that record, KirbyBase would return that field's value as nil.</p>
1413
+ <p>The main reason for making this change was to eliminate the need to
1414
+ override NilClass#method_missing, which was cause for concern for some
1415
+ users.</p>
1416
+ </div>
1417
+ <h2><a id="kbresultset"></a>KBResultSet</h2>
1418
+ <div class="sectionbody">
1419
+ <p>As stated above, the select method returns an instance of KBResultSet, which
1420
+ is an array of Struct objects (or instances of the class specified in
1421
+ record_class), each one representing a record that satisfied the selection
1422
+ criteria.</p>
1423
+ <p>Since each item in KBResultSet is a Struct object, you can easily reference
1424
+ its members using field names. So, to print the name and speed of each
1425
+ German plane in the table you would code:</p>
1426
+ <div class="listingblock">
1427
+ <div class="content">
1428
+ <pre><tt>plane_tbl.select(:name, :speed) { |r| r.country == 'German' }.each do |r|
1429
+ puts '%s %s' % [r.name, r.speed]
1430
+ end</tt></pre>
1431
+ </div></div>
1432
+ <h3><a id="sorting-a-result-set"></a>Sorting a result set</h3>
1433
+ <p>You can specify sort criteria by calling KBResultSet#sort. You must supply
1434
+ the sort method with a list of field names that you want to sort by. For
1435
+ example, to select all planes, include just name, country, and speed in the
1436
+ result set, and sort the result set by country (ascending) then name
1437
+ (ascending), you would code:</p>
1438
+ <div class="listingblock">
1439
+ <div class="content">
1440
+ <pre><tt>result = plane_tbl.select(:name, :country, :speed).sort(:country, :name)</tt></pre>
1441
+ </div></div>
1442
+ <p>To indicate that you want a particular field sorted in descending order
1443
+ rather than ascending order, you need to put a minus sign in front of it.
1444
+ For example, to select all planes, include just name, country, and speed in
1445
+ the result set, and sort the result set by country (ascending) then speed
1446
+ (descending), you would code:</p>
1447
+ <div class="listingblock">
1448
+ <div class="content">
1449
+ <pre><tt>result_set = plane_tbl.select(:name, :country, :speed).sort(:country,
1450
+ -:speed)</tt></pre>
1451
+ </div></div>
1452
+ <p>You can also explicitly specify that a field be sorted in ascending order by
1453
+ putting a plus sign in front of it. This is not necessary, since ascending
1454
+ is the default, but its there if you prefer to use it.</p>
1455
+ <h3><a id="to-report"></a>Producing a report from a result set</h3>
1456
+ <p>Additionally, you can also transform the KBResultSet into a nicely formatted
1457
+ report, suitable for printing, by calling KBResultSet#to_report. To print
1458
+ a formatted report of all plane names, countries, and speeds, sorted by
1459
+ name, you would code the following:</p>
1460
+ <div class="listingblock">
1461
+ <div class="content">
1462
+ <pre><tt>puts plane_tbl.select(:name, :country, :speed).sort(:name).to_report</tt></pre>
1463
+ </div></div>
1464
+ <h3><a id="crosstabs"></a>CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</h3>
1465
+ <p>Every KBResultSet has an additional feature that can prove quite useful.
1466
+ When a result set is created, KirbyBase creates an array for each column
1467
+ name that has all of the values of that column in it. Perhaps an example
1468
+ would make this more clear. Let's say you have a table that looks like
1469
+ this:</p>
1470
+ <div class="tableblock">
1471
+ <table rules="all"
1472
+ frame="border"
1473
+ cellspacing="0" cellpadding="4">
1474
+ <col width="102" />
1475
+ <col width="114" />
1476
+ <col width="137" />
1477
+ <thead>
1478
+ <tr>
1479
+ <th align="left">
1480
+ name
1481
+ </th>
1482
+ <th align="left">
1483
+ speed
1484
+ </th>
1485
+ <th align="left">
1486
+ range
1487
+ </th>
1488
+ </tr>
1489
+ </thead>
1490
+ <tbody valign="top">
1491
+ <tr>
1492
+ <td align="left">
1493
+ P-51
1494
+ </td>
1495
+ <td align="left">
1496
+ 402
1497
+ </td>
1498
+ <td align="left">
1499
+ 1201
1500
+ </td>
1501
+ </tr>
1502
+ <tr>
1503
+ <td align="left">
1504
+ ME-109
1505
+ </td>
1506
+ <td align="left">
1507
+ 354
1508
+ </td>
1509
+ <td align="left">
1510
+ 544
1511
+ </td>
1512
+ </tr>
1513
+ <tr>
1514
+ <td align="left">
1515
+ Spitfire
1516
+ </td>
1517
+ <td align="left">
1518
+ 343
1519
+ </td>
1520
+ <td align="left">
1521
+ 501
1522
+ </td>
1523
+ </tr>
1524
+ </tbody>
1525
+ </table>
1526
+ </div>
1527
+ <p>If you do a select on the table, not only will the result set contain a
1528
+ row for each record that satisfied the select condition, but it will also
1529
+ contain an array for each column, which will hold all the column values.
1530
+ Here's an example, using the above mentioned table:</p>
1531
+ <div class="listingblock">
1532
+ <div class="content">
1533
+ <pre><tt>result = plane_tbl.select
1534
+
1535
+ puts result[0].name =&gt; P-51
1536
+ puts result[0].speed =&gt; 402
1537
+
1538
+ p result.speed =&gt; [402,354,343]</tt></pre>
1539
+ </div></div>
1540
+ <p>Notice how you can reference this "column array" by calling the column name
1541
+ as a method. KirbyBase returns an array that holds all the values, in this
1542
+ case, of the speed column. This can be very useful in some cases. For a
1543
+ good example of this, look in the examples\crosstab_test directory of the
1544
+ distribution.</p>
1545
+ </div>
1546
+ <h2><a id="how-to-update-records"></a>How to update records</h2>
1547
+ <div class="sectionbody">
1548
+ <p>You can update the data in a table either by using the KBTable#update method
1549
+ by itself, or using it in conjunction with the KBResultSet#set method.
1550
+ Both methods produce the same result. The main difference is that, while
1551
+ using the #update method by itself, you can use a Hash, Array, or Struct as
1552
+ your update criteria, using the #set method in conjunction with the #update
1553
+ method adds the ability to use a code block as your update criteria. You
1554
+ will see specific examples of this in "The update method" description below.</p>
1555
+ <h3><a id="update-method"></a>The update method</h3>
1556
+ <p>To update a table, you use the update method. You <strong>must</strong> specify a code
1557
+ block that indicates which records are to be updated. Additionally, you must
1558
+ specify the fields to be updated and the new values for those fields.</p>
1559
+ <p>You can update records using a Hash, Struct, an Array, or an instance of a
1560
+ class you defined. For example, to change the P-51's speed to 405mph and
1561
+ its range to 1210 miles, you could code:</p>
1562
+ <div class="listingblock">
1563
+ <div class="content">
1564
+ <pre><tt>plane_tbl.update(:speed=&gt;405, :range=&gt;1210) { |r| r.name == 'P-51' }</tt></pre>
1565
+ </div></div>
1566
+ <p>or:</p>
1567
+ <div class="listingblock">
1568
+ <div class="content">
1569
+ <pre><tt>UpdateRec = Struct.new(:name, :country, :role, :speed, :range,
1570
+ :began_service, :still_flying)
1571
+
1572
+ rec = UpdateRec.new
1573
+ rec.speed = 405
1574
+ rec.range = 1210
1575
+ plane_tbl.update(rec) { |r| r.name == 'P-51' }</tt></pre>
1576
+ </div></div>
1577
+ <h3><a id="set-method"></a>The set method</h3>
1578
+ <p>You can also update records using a code block, via KBResultSet#set:</p>
1579
+ <div class="listingblock">
1580
+ <div class="content">
1581
+ <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set do |r|
1582
+ r.speed = 405
1583
+ r.range = 1210
1584
+ end</tt></pre>
1585
+ </div></div>
1586
+ <p>You can also update records using a Hash, Struct, or an Array, via
1587
+ KBResultSet#set:</p>
1588
+ <div class="listingblock">
1589
+ <div class="content">
1590
+ <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set(:speed=&gt;405, :range=&gt;1210)</tt></pre>
1591
+ </div></div>
1592
+ <div class="sidebarblock">
1593
+ <div class="sidebar-content">
1594
+ <div class="admonitionblock">
1595
+ <table><tr>
1596
+ <td class="icon">
1597
+ <img src="./images/important.png" alt="Important" />
1598
+ </td>
1599
+ <td class="content">When you don't supply a code block to the #select method,
1600
+ KirbyBase automatically selects all of the records in the table. I felt
1601
+ that having the #update method work the same way was too dangerous. It
1602
+ would be too easy for someone to accidentally update all of the records in
1603
+ a table if they forgot to supply a code block to #update. That is why the
1604
+ #update method <strong>requires</strong> a code block. To update all of the records in a
1605
+ table, use the #update_all method.</td>
1606
+ </tr></table>
1607
+ </div>
1608
+ </div></div>
1609
+ <div class="sidebarblock">
1610
+ <div class="sidebar-content">
1611
+ <div class="admonitionblock">
1612
+ <table><tr>
1613
+ <td class="icon">
1614
+ <img src="./images/note.png" alt="Note" />
1615
+ </td>
1616
+ <td class="content">The #update method will return an Integer specifying the number of
1617
+ records that were updated.</td>
1618
+ </tr></table>
1619
+ </div>
1620
+ </div></div>
1621
+ <h3><a id="update-all-method"></a>The update_all method</h3>
1622
+ <p>To update all records in a table, you can use KBTable#update_all. This
1623
+ works just like the update method, except that you don't specify a code
1624
+ block containing selection criteria.</p>
1625
+ <p>For example, to add 50 mph to every record's speed field, you would code:</p>
1626
+ <div class="listingblock">
1627
+ <div class="content">
1628
+ <pre><tt>plane_tbl.update_all { |r| r.speed = r.speed + 50 }</tt></pre>
1629
+ </div></div>
1630
+ <div class="sidebarblock">
1631
+ <div class="sidebar-content">
1632
+ <div class="admonitionblock">
1633
+ <table><tr>
1634
+ <td class="icon">
1635
+ <img src="./images/note.png" alt="Note" />
1636
+ </td>
1637
+ <td class="content">The #update_all method will return an Integer specifying the number
1638
+ of records that were updated.</td>
1639
+ </tr></table>
1640
+ </div>
1641
+ </div></div>
1642
+ </div>
1643
+ <h2><a id="how-to-delete-records"></a>How to delete records</h2>
1644
+ <div class="sectionbody">
1645
+ <p>Deleting records from a table is similar to performing a #select or an
1646
+ #update.</p>
1647
+ <h3><a id="delete-method"></a>The delete method</h3>
1648
+ <p>To use the #delete method, you <strong>must</strong> supply a code block that identifies
1649
+ which records should be deleted.</p>
1650
+ <p>For example, to delete the FW-190's record from the table:</p>
1651
+ <div class="listingblock">
1652
+ <div class="content">
1653
+ <pre><tt>plane_tbl.delete { |r| r.name == 'FW-190' }</tt></pre>
1654
+ </div></div>
1655
+ <div class="sidebarblock">
1656
+ <div class="sidebar-content">
1657
+ <div class="admonitionblock">
1658
+ <table><tr>
1659
+ <td class="icon">
1660
+ <img src="./images/important.png" alt="Important" />
1661
+ </td>
1662
+ <td class="content">When you don't supply a code block to the #select method,
1663
+ KirbyBase automatically selects all of the records in the table. I felt
1664
+ that having the #delete method work the same way was too dangerous. It
1665
+ would be too easy for someone to accidentally delete all of the records in
1666
+ a table if they forgot to supply a code block to #delete. That is why the
1667
+ #delete method <strong>requires</strong> a code block. To delete all of the records in a
1668
+ table, use the #clear method.</td>
1669
+ </tr></table>
1670
+ </div>
1671
+ </div></div>
1672
+ <div class="sidebarblock">
1673
+ <div class="sidebar-content">
1674
+ <div class="admonitionblock">
1675
+ <table><tr>
1676
+ <td class="icon">
1677
+ <img src="./images/note.png" alt="Note" />
1678
+ </td>
1679
+ <td class="content">The #delete method will return an Integer specifying the total number
1680
+ of records that were deleted.</td>
1681
+ </tr></table>
1682
+ </div>
1683
+ </div></div>
1684
+ <h3><a id="clear-method"></a>The clear (alias delete_all) method</h3>
1685
+ <p>To completely empty a table, use the clear method. For example:</p>
1686
+ <div class="listingblock">
1687
+ <div class="content">
1688
+ <pre><tt>plane_tbl.clear</tt></pre>
1689
+ </div></div>
1690
+ <div class="sidebarblock">
1691
+ <div class="sidebar-content">
1692
+ <div class="admonitionblock">
1693
+ <table><tr>
1694
+ <td class="icon">
1695
+ <img src="./images/important.png" alt="Important" />
1696
+ </td>
1697
+ <td class="content">By default, KirbyBase will reset the recno counter to 0. So, any
1698
+ new records inserted after a #clear will be given a :recno starting with 1.
1699
+ To prevent #clear from resetting the recno counter, pass false to #clear.</td>
1700
+ </tr></table>
1701
+ </div>
1702
+ </div></div>
1703
+ </div>
1704
+ <h2><a id="pack-method"></a>The pack method</h2>
1705
+ <div class="sectionbody">
1706
+ <p>When KirbyBase deletes a record, it really just fills the entire line in the
1707
+ file with spaces. Deleting the entire line and moving each subsequent line
1708
+ up one would take too much time. Also, when a record is updated, if the size
1709
+ of the updated record is greater than the size of the old record, KirbyBase
1710
+ spaces out that entire line in the file, and rewrites the updated record at
1711
+ the end of the file. Again, this is done so that the entire file doesn't
1712
+ have to be re-written just because one record got updated.</p>
1713
+ <p>However, this means that after a lot of deletes and updates, a table can
1714
+ have lots of blank lines in it. This slows down searches and makes the file
1715
+ bigger than it has to be. You can use the pack method to remove these blank
1716
+ lines:</p>
1717
+ <div class="listingblock">
1718
+ <div class="content">
1719
+ <pre><tt>result = plane_tbl.pack</tt></pre>
1720
+ </div></div>
1721
+ <div class="admonitionblock">
1722
+ <table><tr>
1723
+ <td class="icon">
1724
+ <img src="./images/important.png" alt="Important" />
1725
+ </td>
1726
+ <td class="content">You can only call this method when connect_type==:local.</td>
1727
+ </tr></table>
1728
+ </div>
1729
+ <div class="sidebarblock">
1730
+ <div class="sidebar-content">
1731
+ <div class="admonitionblock">
1732
+ <table><tr>
1733
+ <td class="icon">
1734
+ <img src="./images/note.png" alt="Note" />
1735
+ </td>
1736
+ <td class="content">The #pack method will return an Integer specifiying the number of
1737
+ blank lines that were removed from the table.</td>
1738
+ </tr></table>
1739
+ </div>
1740
+ </div></div>
1741
+ </div>
1742
+ <h2><a id="memo-and-blob-fields"></a>Memo and Blob Fields</h2>
1743
+ <div class="sectionbody">
1744
+ <p>Memo and Blob fields operate a little differently from standard field types.
1745
+ You specify their creation just like regular field types. Notice how you
1746
+ can specify a base path for where memo/blob files will be stored.</p>
1747
+ <div class="listingblock">
1748
+ <div class="content">
1749
+ <pre><tt>db.create_table(:plane, :name, :String, :speed, :Integer, :descr,
1750
+ :Memo) do |d|
1751
+ d.memo_blob_path = './memos'
1752
+ end</tt></pre>
1753
+ </div></div>
1754
+ <p>However, what you actually store in the Memo field upon an #insert is an
1755
+ instance of KBMemo. KBMemo has two attributes: :filepath and :contents.
1756
+ The first holds the path (including filename) to the text file that will
1757
+ hold the contents of the memo. This path will be relative to whatever
1758
+ path was specified as the memo_blob_path upon database initialization. Here
1759
+ is an example of how to do this:</p>
1760
+ <div class="listingblock">
1761
+ <div class="content">
1762
+ <pre><tt>memo_string = &lt;&lt;END_OF_STRING
1763
+ The FW-190 was a World War II German fighter. It was used primarily as an
1764
+ interceptor against Allied strategic bombers.
1765
+ END_OF_STRING
1766
+
1767
+ memo = KBMemo.new(db, 'FW-190.txt', memo_string)
1768
+ plane_tbl.insert('FW-190', 'Germany', 399, 499, memo)</tt></pre>
1769
+ </div></div>
1770
+ <p>Updates work similarly in that you would need to supply a KBMemo instance
1771
+ to the #update method for the :Memo field.</p>
1772
+ <p>Other than this difference, you can use a memo field just like a regular
1773
+ field. When you do a #select, KirbyBase goes out to the file that holds the
1774
+ memo data, reads in all the lines, and returns a KBMemo instance. Here is
1775
+ an example of how you can even query against a memo field:</p>
1776
+ <div class="listingblock">
1777
+ <div class="content">
1778
+ <pre><tt>plane_tbl.select { |r| r.descr.contents =~ /built in Detroit, Michigan/ }</tt></pre>
1779
+ </div></div>
1780
+ <p>And KirbyBase would select all records whose memo field contained the phrase
1781
+ "built in Detroit, Michigan".</p>
1782
+ <p>Blob fields work similarly, except that instead of doing a #readlines,
1783
+ KirbyBase opens the file in binary mode and reads in the whole file at once.</p>
1784
+ </div>
1785
+ <h2><a id="misc-kirbybase-methods"></a>Miscellaneous KirbyBase methods</h2>
1786
+ <div class="sectionbody">
1787
+ <div class="sidebarblock">
1788
+ <a id="drop-table"></a>
1789
+ <div class="sidebar-content">
1790
+ <div class="sidebar-title">KirbyBase#drop_table</div>
1791
+ <div class="listingblock">
1792
+ <div class="content">
1793
+ <pre><tt>db.drop_table(:plane)</tt></pre>
1794
+ </div></div>
1795
+ <p>Will delete a table from the database.</p>
1796
+ <p>Returns true if table was dropped.</p>
1797
+ </div></div>
1798
+ <div class="sidebarblock">
1799
+ <a id="tables"></a>
1800
+ <div class="sidebar-content">
1801
+ <div class="sidebar-title">KirbyBase#tables</div>
1802
+ <div class="listingblock">
1803
+ <div class="content">
1804
+ <pre><tt>db.tables</tt></pre>
1805
+ </div></div>
1806
+ <p>Returns an array of all table names in the database.</p>
1807
+ </div></div>
1808
+ <div class="sidebarblock">
1809
+ <a id="table-exists"></a>
1810
+ <div class="sidebar-content">
1811
+ <div class="sidebar-title">KirbyBase#table_exists?</div>
1812
+ <div class="listingblock">
1813
+ <div class="content">
1814
+ <pre><tt>db.table_exists?(:plane)</tt></pre>
1815
+ </div></div>
1816
+ <p>Returns true if table exists, false otherwise.</p>
1817
+ </div></div>
1818
+ <div class="sidebarblock">
1819
+ <a id="rename-table"></a>
1820
+ <div class="sidebar-content">
1821
+ <div class="sidebar-title">KirbyBase#rename_table</div>
1822
+ <div class="listingblock">
1823
+ <div class="content">
1824
+ <pre><tt>db.rename_table(:plane, :warplanes)</tt></pre>
1825
+ </div></div>
1826
+ <p>Rename table to new name.</p>
1827
+ <p>Returns a handle to the newly-renamed table.</p>
1828
+ </div></div>
1829
+ </div>
1830
+ <h2><a id="misc-kbtable-methods"></a>Miscellaneous KBTable methods</h2>
1831
+ <div class="sectionbody">
1832
+ <div class="sidebarblock">
1833
+ <a id="update-by-recno"></a>
1834
+ <div class="sidebar-content">
1835
+ <div class="sidebar-title">KBTable#[]=</div>
1836
+ <div class="listingblock">
1837
+ <div class="content">
1838
+ <pre><tt>plane_tbl[5] = {:country = 'Tasmania'}</tt></pre>
1839
+ </div></div>
1840
+ <p>You can quickly update an individual record by treating the table as a Hash
1841
+ and the keys as recno's. You can update it using a Hash, Array, or Struct.</p>
1842
+ <p>Returns Integer specifying number of records updated (should always be 1).</p>
1843
+ </div></div>
1844
+ <div class="sidebarblock">
1845
+ <a id="get-by-recno"></a>
1846
+ <div class="sidebar-content">
1847
+ <div class="sidebar-title">KBTable#[]</div>
1848
+ <div class="listingblock">
1849
+ <div class="content">
1850
+ <pre><tt>plane_tbl[5]</tt></pre>
1851
+ </div></div>
1852
+ <p>You can quickly select an individual record, by passing its recno to a
1853
+ table as if it were a hash.</p>
1854
+ <p>Returns a single record either in the form of a Struct or an instance of
1855
+ the table's custom record class, if specified.</p>
1856
+ <div class="listingblock">
1857
+ <div class="content">
1858
+ <pre><tt>plane_tbl[5, 14, 33]</tt></pre>
1859
+ </div></div>
1860
+ <p>You can also use the [] method to get a group of records by passing it more
1861
+ than one recno.</p>
1862
+ <p>Returns a KBResultSet with the records having the recno's you passed in.</p>
1863
+ </div></div>
1864
+ <div class="sidebarblock">
1865
+ <a id="field-names"></a>
1866
+ <div class="sidebar-content">
1867
+ <div class="sidebar-title">KBTable#field_names</div>
1868
+ <div class="listingblock">
1869
+ <div class="content">
1870
+ <pre><tt>plane_tbl.field_names</tt></pre>
1871
+ </div></div>
1872
+ <p>Returns an array of the table's field names.</p>
1873
+ </div></div>
1874
+ <div class="sidebarblock">
1875
+ <a id="field-types"></a>
1876
+ <div class="sidebar-content">
1877
+ <div class="sidebar-title">KBTable#field_types</div>
1878
+ <div class="listingblock">
1879
+ <div class="content">
1880
+ <pre><tt>plane_tbl.field_types</tt></pre>
1881
+ </div></div>
1882
+ <p>Returns an array of the table's field types (i.e. :String, :Integer, :Float)</p>
1883
+ </div></div>
1884
+ <div class="sidebarblock">
1885
+ <a id="total-recs"></a>
1886
+ <div class="sidebar-content">
1887
+ <div class="sidebar-title">KBTable#total_recs</div>
1888
+ <div class="listingblock">
1889
+ <div class="content">
1890
+ <pre><tt>plane_tbl.total_recs</tt></pre>
1891
+ </div></div>
1892
+ <p>Returns an Integer specifying the total number of records in the table.</p>
1893
+ </div></div>
1894
+ <div class="sidebarblock">
1895
+ <a id="import-csv"></a>
1896
+ <div class="sidebar-content">
1897
+ <div class="sidebar-title">KBTable#import_csv</div>
1898
+ <div class="listingblock">
1899
+ <div class="content">
1900
+ <pre><tt>plane_tbl.import_csv(csv_filename)</tt></pre>
1901
+ </div></div>
1902
+ <p>This method allows you to import a csv file into the current table.
1903
+ KirbyBase will attempt to convert the values in the csv file into their
1904
+ corresponding KirbyBase field types, based upon the field types you
1905
+ designated when you created the table.</p>
1906
+ <p>If you have FasterCSV installed KirbyBase will use it instead of CSV from
1907
+ the standard library.</p>
1908
+ <p>Returns an Integer specifying the total number of records imported.</p>
1909
+ </div></div>
1910
+ <div class="sidebarblock">
1911
+ <a id="add-column"></a>
1912
+ <div class="sidebar-content">
1913
+ <div class="sidebar-title">KBTable#add_column</div>
1914
+ <div class="listingblock">
1915
+ <div class="content">
1916
+ <pre><tt>plane_tbl.add_column(:weight, :Integer, :range)</tt></pre>
1917
+ </div></div>
1918
+ <p>This method allows you to add a column to an existing table. You must
1919
+ specify a column name, and a column type. You can optionally specify a
1920
+ column that you want the new column added after. If this is not specified,
1921
+ KirbyBase will add the column to the end of the table.</p>
1922
+ <div class="admonitionblock">
1923
+ <table><tr>
1924
+ <td class="icon">
1925
+ <img src="./images/important.png" alt="Important" />
1926
+ </td>
1927
+ <td class="content">Because #add_column changes the structure of a table, you can
1928
+ only call this method when connect_type==:local.</td>
1929
+ </tr></table>
1930
+ </div>
1931
+ </div></div>
1932
+ <div class="sidebarblock">
1933
+ <a id="drop-column"></a>
1934
+ <div class="sidebar-content">
1935
+ <div class="sidebar-title">KBTable#drop_column</div>
1936
+ <div class="listingblock">
1937
+ <div class="content">
1938
+ <pre><tt>plane_tbl.drop_column(:speed)</tt></pre>
1939
+ </div></div>
1940
+ <p>This method allows you to remove a column from an existing table. You must
1941
+ specify the column name to be removed.</p>
1942
+ <div class="admonitionblock">
1943
+ <table><tr>
1944
+ <td class="icon">
1945
+ <img src="./images/important.png" alt="Important" />
1946
+ </td>
1947
+ <td class="content">You cannot drop the :recno column.</td>
1948
+ </tr></table>
1949
+ </div>
1950
+ <div class="admonitionblock">
1951
+ <table><tr>
1952
+ <td class="icon">
1953
+ <img src="./images/important.png" alt="Important" />
1954
+ </td>
1955
+ <td class="content">Because #drop_column changes the structure of a table, you can
1956
+ only call this method when connect_type==:local.</td>
1957
+ </tr></table>
1958
+ </div>
1959
+ </div></div>
1960
+ <div class="sidebarblock">
1961
+ <a id="rename-column"></a>
1962
+ <div class="sidebar-content">
1963
+ <div class="sidebar-title">KBTable#rename_column</div>
1964
+ <div class="listingblock">
1965
+ <div class="content">
1966
+ <pre><tt>plane_tbl.rename_column(:speed, :maximum_speed)</tt></pre>
1967
+ </div></div>
1968
+ <p>This method allows you to rename a column in an existing table. You must
1969
+ specify the column to be renamed and a new column name.</p>
1970
+ <div class="admonitionblock">
1971
+ <table><tr>
1972
+ <td class="icon">
1973
+ <img src="./images/important.png" alt="Important" />
1974
+ </td>
1975
+ <td class="content">You cannot rename the :recno column.</td>
1976
+ </tr></table>
1977
+ </div>
1978
+ <div class="admonitionblock">
1979
+ <table><tr>
1980
+ <td class="icon">
1981
+ <img src="./images/important.png" alt="Important" />
1982
+ </td>
1983
+ <td class="content">Because #rename_column changes the structure of a table, you can
1984
+ only call this method when connect_type==:local.</td>
1985
+ </tr></table>
1986
+ </div>
1987
+ </div></div>
1988
+ <div class="sidebarblock">
1989
+ <a id="change-column-type"></a>
1990
+ <div class="sidebar-content">
1991
+ <div class="sidebar-title">KBTable#change_column_type</div>
1992
+ <div class="listingblock">
1993
+ <div class="content">
1994
+ <pre><tt>plane_tbl.change_column_type(:weight, :Float)</tt></pre>
1995
+ </div></div>
1996
+ <p>This method allows you to change a column's type in an existing table. You
1997
+ must specify the column name and a new column type.</p>
1998
+ <div class="admonitionblock">
1999
+ <table><tr>
2000
+ <td class="icon">
2001
+ <img src="./images/important.png" alt="Important" />
2002
+ </td>
2003
+ <td class="content">You cannot change the type of the :recno column.</td>
2004
+ </tr></table>
2005
+ </div>
2006
+ <div class="admonitionblock">
2007
+ <table><tr>
2008
+ <td class="icon">
2009
+ <img src="./images/important.png" alt="Important" />
2010
+ </td>
2011
+ <td class="content">Because #change_column_type changes the structure of a table, you
2012
+ can only call this method when connect_type==:local.</td>
2013
+ </tr></table>
2014
+ </div>
2015
+ </div></div>
2016
+ <div class="sidebarblock">
2017
+ <a id="change-column-default-value"></a>
2018
+ <div class="sidebar-content">
2019
+ <div class="sidebar-title">KBTable#change_column_default_value</div>
2020
+ <div class="listingblock">
2021
+ <div class="content">
2022
+ <pre><tt>plane_tbl.change_column_default_value(:country, 'United States')</tt></pre>
2023
+ </div></div>
2024
+ <p>This method allows you to change a column's default value in an existing
2025
+ table. You must specify the column name and a default value. If the
2026
+ default value is equal to nil, this, in effect will make the column not have
2027
+ a default value any more.</p>
2028
+ <div class="admonitionblock">
2029
+ <table><tr>
2030
+ <td class="icon">
2031
+ <img src="./images/important.png" alt="Important" />
2032
+ </td>
2033
+ <td class="content">Since the :recno column cannot have a default value, you cannot
2034
+ change the default value of the :recno column.</td>
2035
+ </tr></table>
2036
+ </div>
2037
+ <div class="admonitionblock">
2038
+ <table><tr>
2039
+ <td class="icon">
2040
+ <img src="./images/important.png" alt="Important" />
2041
+ </td>
2042
+ <td class="content">Because #change_column_default_value changes the structure of a
2043
+ table, you can only call this method when connect_type==:local.</td>
2044
+ </tr></table>
2045
+ </div>
2046
+ </div></div>
2047
+ <div class="sidebarblock">
2048
+ <a id="change-column-required"></a>
2049
+ <div class="sidebar-content">
2050
+ <div class="sidebar-title">KBTable#change_column_required</div>
2051
+ <div class="listingblock">
2052
+ <div class="content">
2053
+ <pre><tt>plane_tbl.change_column_required(:country, true)</tt></pre>
2054
+ </div></div>
2055
+ <p>This method allows you to change whether a value for a column is required or
2056
+ not. You must specify the column name and either true or false for the
2057
+ required argument.</p>
2058
+ <div class="admonitionblock">
2059
+ <table><tr>
2060
+ <td class="icon">
2061
+ <img src="./images/important.png" alt="Important" />
2062
+ </td>
2063
+ <td class="content">You cannot specify whether the :recno column is required or not.</td>
2064
+ </tr></table>
2065
+ </div>
2066
+ <div class="admonitionblock">
2067
+ <table><tr>
2068
+ <td class="icon">
2069
+ <img src="./images/important.png" alt="Important" />
2070
+ </td>
2071
+ <td class="content">Because #change_column_required changes the structure of a table,
2072
+ you can only call this method when connect_type==:local.</td>
2073
+ </tr></table>
2074
+ </div>
2075
+ </div></div>
2076
+ <div class="sidebarblock">
2077
+ <a id="add-index"></a>
2078
+ <div class="sidebar-content">
2079
+ <div class="sidebar-title">KBTable#add_index</div>
2080
+ <div class="listingblock">
2081
+ <div class="content">
2082
+ <pre><tt>plane_tbl.add_index(:name, :country)</tt></pre>
2083
+ </div></div>
2084
+ <p>This method allows you to add an index to an existing table. This index can
2085
+ consist of one or more columns. You must specify one or more column names
2086
+ that you want to make up the index.</p>
2087
+ <div class="admonitionblock">
2088
+ <table><tr>
2089
+ <td class="icon">
2090
+ <img src="./images/important.png" alt="Important" />
2091
+ </td>
2092
+ <td class="content">Because #add_index changes the structure of a table, you can
2093
+ only call this method when connect_type==:local.</td>
2094
+ </tr></table>
2095
+ </div>
2096
+ </div></div>
2097
+ <div class="sidebarblock">
2098
+ <a id="drop-index"></a>
2099
+ <div class="sidebar-content">
2100
+ <div class="sidebar-title">KBTable#drop_index</div>
2101
+ <div class="listingblock">
2102
+ <div class="content">
2103
+ <pre><tt>plane_tbl.drop_index(:name, :country)</tt></pre>
2104
+ </div></div>
2105
+ <p>This method allows you to drop an index from an existing table. You must
2106
+ specify one or more column names that make up the index that you want to
2107
+ drop.</p>
2108
+ <div class="admonitionblock">
2109
+ <table><tr>
2110
+ <td class="icon">
2111
+ <img src="./images/important.png" alt="Important" />
2112
+ </td>
2113
+ <td class="content">Because #drop_index changes the structure of a table, you can
2114
+ only call this method when connect_type==:local.</td>
2115
+ </tr></table>
2116
+ </div>
2117
+ </div></div>
2118
+ </div>
2119
+ <h2><a id="special-characters-in-data"></a>Special characters in data</h2>
2120
+ <div class="sectionbody">
2121
+ <p>Since KirbyBase tables are just plain-text, newline-delimited files with
2122
+ each field delimited by a <em>|</em>, certain ASCII characters could cause problems
2123
+ when used as input. For example, entering a newline character (\n on Unix,
2124
+ \r\n on Windows) as part of a record's data would cause problems later when
2125
+ KirbyBase attempted to read this record. Likewise, using the <em>|</em> character
2126
+ in your data would also cause problems as KirbyBase uses this character as a
2127
+ field delimiter. Finally, it turns out that Python has problems handling
2128
+ octal code \032 under Windows (possibly because it equates to Ctrl-Z), so
2129
+ to keep compatibility between the Ruby and Python versions of KirbyBase,
2130
+ this issue needs to be handled.</p>
2131
+ <p>To handle the above special characters as data input, KirbyBase checks all
2132
+ :String and :YAML input data and replaces the special characters with
2133
+ encodings that are safe. The following table shows how replacements are
2134
+ done:</p>
2135
+ <div class="tableblock">
2136
+ <table rules="all"
2137
+ frame="border"
2138
+ cellspacing="0" cellpadding="4">
2139
+ <col width="182" />
2140
+ <col width="240" />
2141
+ <thead>
2142
+ <tr>
2143
+ <th align="left">
2144
+ Input Character
2145
+ </th>
2146
+ <th align="left">
2147
+ KirbyBase Replacement
2148
+ </th>
2149
+ </tr>
2150
+ </thead>
2151
+ <tbody valign="top">
2152
+ <tr>
2153
+ <td align="left">
2154
+ \n
2155
+ </td>
2156
+ <td align="left">
2157
+ &amp;amp;linefeed;
2158
+ </td>
2159
+ </tr>
2160
+ <tr>
2161
+ <td align="left">
2162
+ \r
2163
+ </td>
2164
+ <td align="left">
2165
+ &amp;amp;carriage_return;
2166
+ </td>
2167
+ </tr>
2168
+ <tr>
2169
+ <td align="left">
2170
+ \032
2171
+ </td>
2172
+ <td align="left">
2173
+ &amp;amp;substitute;
2174
+ </td>
2175
+ </tr>
2176
+ <tr>
2177
+ <td align="left">
2178
+ |
2179
+ </td>
2180
+ <td align="left">
2181
+ &amp;amp;pipe;
2182
+ </td>
2183
+ </tr>
2184
+ <tr>
2185
+ <td align="left">
2186
+ &amp;
2187
+ </td>
2188
+ <td align="left">
2189
+ &amp;amp;
2190
+ </td>
2191
+ </tr>
2192
+ </tbody>
2193
+ </table>
2194
+ </div>
2195
+ <p>KirbyBase will translate to and from the special characters as data is
2196
+ written to and read from a table. It should all be transparent to the user.
2197
+ The only time you would encounter the replacement words is if you were to
2198
+ open up the physical table file in a text editor or read it in as input
2199
+ outside of KirbyBase.</p>
2200
+ </div>
2201
+ <h2><a id="table-structure"></a>Table Structure</h2>
2202
+ <div class="sectionbody">
2203
+ <p>Every table in KirbyBase is represented by a physical, newline-delimited
2204
+ text-file. Here is an example:</p>
2205
+ <div class="listingblock">
2206
+ <div class="content">
2207
+ <pre><tt>000006|000000|Struct|recno:Integer|name:String|country:String|speed:Integer
2208
+ 1|P-51|USA|403
2209
+ 2|P-51|USA|365
2210
+ 3|Sptitfire|England|345
2211
+ 4|Oscar|Japan|361
2212
+ 5|ME-109|Germany|366
2213
+ 6|Zero|Japan|377</tt></pre>
2214
+ </div></div>
2215
+ <p>The first line is the header rec. Each field is delimited by a "|". The
2216
+ first field in the header is the record counter. It is incremented by
2217
+ KirbyBase to create new record numbers when records are inserted.</p>
2218
+ <p>The second field in the header is the deleted-records counter. Every time a
2219
+ line in the file is blanked-out (see <a href="#pack-method">The pack method</a>), this
2220
+ number is incremented. You can use this field in a maintenance script so
2221
+ that the table is packed whenever the deleted-records counter reaches, say,
2222
+ 5,000 records.</p>
2223
+ <p>The third field in the header is the record_class field. If you specified a
2224
+ class when you created the table, its name will show up here and records
2225
+ returned from a #select will be instances of this class. The default is
2226
+ "Struct".</p>
2227
+ <p>The fourth field in the header is the :recno field. This field is
2228
+ automatically added to the table when it is created. The field name and
2229
+ field type are separated by a ":".</p>
2230
+ <p>The rest of the fields are whatever you specified when you created the
2231
+ table.</p>
2232
+ <p>If there is a Z in the first position of the header rec and the rest of the
2233
+ file is a bunch of random characters, this means that the table is
2234
+ encrypted.</p>
2235
+ <p>Each record after the header record is simply a line of text. Newline
2236
+ characters delimit records.</p>
2237
+ </div>
2238
+ <h2><a id="server-notes"></a>Server Notes</h2>
2239
+ <div class="sectionbody">
2240
+ <p>There is a server script included in the distribution called kbserver.rb.
2241
+ This script uses DRb to turn KirbyBase into a client/server, multi-user
2242
+ DBMS. This DBMS server handles table locking for you so you don't have to
2243
+ worry about it.</p>
2244
+ </div>
2245
+ <h2><a id="tips-on-improving-performance"></a>Tips on improving performance</h2>
2246
+ <div class="sectionbody">
2247
+ <h3>Beware of Date/DateTime</h3>
2248
+ <p>Converting a String (the format in which data is stored in a KirbyBase
2249
+ table) to a Date/DateTime is slow. If you have a large table with a
2250
+ Date/DateTime field, this can result in long query times.</p>
2251
+ <p>To get around this, you can specify the field type as a :String, instead of
2252
+ a :Date/:DateTime. Queries will still work correctly, because Date/DateTime
2253
+ fields that are in String format sort the same way they would if they were
2254
+ in native format. Here's an example. The following two expressions will
2255
+ result in the same result set being returned:</p>
2256
+ <div class="listingblock">
2257
+ <div class="content">
2258
+ <pre><tt>date_field &lt;= Date.new(2005, 05, 11)</tt></pre>
2259
+ </div></div>
2260
+ <p>and</p>
2261
+ <div class="listingblock">
2262
+ <div class="content">
2263
+ <pre><tt>date_field_stored_as_string_field &lt;= "2005-05-11"</tt></pre>
2264
+ </div></div>
2265
+ <h3>Create indexes on large tables</h3>
2266
+ <p>The larger a table becomes, the more sense it makes to create an index on
2267
+ one or more of its fields. Even though you take a hit when KirbyBase first
2268
+ initializes because it has to create the index arrays, you make up for it
2269
+ after that in greatly improved query speeds. I have noticed speed-ups of
2270
+ as much as 10x on large tables.</p>
2271
+ <h3>Create indexes on foreign keys</h3>
2272
+ <p>If you have a Link_many on a table field, you might want to think about
2273
+ creating an index on the field in the child table that is being linked to.
2274
+ When performing a one-to-many link, KirbyBase will automatically take
2275
+ advantage of an index on the link field in the child table.</p>
2276
+ <p>By the way, the same holds true for Lookups.</p>
2277
+ <h3>When possible, always search by :recno</h3>
2278
+ <p>This might be a no-brainer, but, if you have the chance to select by
2279
+ :recno, use the built-in #select_by_recno_index method (or the #[] method).
2280
+ This is even faster than selecting on a regularly indexed field, because the
2281
+ :recno index that KirbyBase creates for each table is actually a Hash, not
2282
+ an Array like all of the regular indexes. So selects are even faster.</p>
2283
+ </div>
2284
+ <h2><a id="single-user-diagram"></a>Single-user memory space diagram</h2>
2285
+ <div class="sectionbody">
2286
+ <div class="imageblock">
2287
+ <div class="content">
2288
+ <img src="images/single_user.png" alt="images/single_user.png"/>
2289
+ </div>
2290
+ <div class="image-title">Figure: Single-user (embedded) mode.</div>
2291
+ </div>
2292
+ </div>
2293
+ <h2><a id="client-server-diagram"></a>Client/Server memory space diagram</h2>
2294
+ <div class="sectionbody">
2295
+ <div class="imageblock">
2296
+ <div class="content">
2297
+ <img src="images/client_server.png" alt="images/client_server.png"/>
2298
+ </div>
2299
+ <div class="image-title">Figure: Client/Server (separate memory spaces) mode.</div>
2300
+ </div>
2301
+ </div>
2302
+ <h2><a id="license"></a>License</h2>
2303
+ <div class="sectionbody">
2304
+ <p>KirbyBase is distributed under the same license terms as Ruby.</p>
2305
+ </div>
2306
+ <h2><a id="credits"></a>Credits</h2>
2307
+ <div class="sectionbody">
2308
+ <div class="admonitionblock">
2309
+ <table><tr>
2310
+ <td class="icon">
2311
+ <img src="./images/note.png" alt="Note" />
2312
+ </td>
2313
+ <td class="content">This manual was produced using the awesome text document formatter,
2314
+ <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>.</td>
2315
+ </tr></table>
2316
+ </div>
2317
+ </div>
2318
+ <div id="footer">
2319
+ <div id="footer-text">
2320
+ Last updated 26-Jun-2006 14:36:38 EDT
2321
+ </div>
2322
+ </div>
2323
+ </body>
2324
+ </html>