KirbyBase 2.6 → 2.6.1

Sign up to get free protection for your applications and to get access to all the features.
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>