audrey 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +610 -0
- data/lib/audrey.rb +2503 -0
- metadata +74 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 61cf118da49fbae7bf7dbc82dbf03f1460fe26d9925b135374e97a930039d198
|
4
|
+
data.tar.gz: ffc33814130bfcd6b24f70d3d4aebd5c71aff75922fa1cf9fb090789948d6fc9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b8e4a31b17b175e5c038ba1063bddafca7c9e68e59655a764fade27d6459b43232336fc263d32040e7b8e8f75f7c58066af6a433711b3a020efdffe111f9963f
|
7
|
+
data.tar.gz: 8f015943ce4204efc60ba516bc6e259044d2be8b6b10d73c5873e042eaaecf1165425f5871afa2d251ea71e1deb3939528b9366f99e24ce11b0ec744a30e76a6
|
data/README.md
ADDED
@@ -0,0 +1,610 @@
|
|
1
|
+
# Audrey
|
2
|
+
|
3
|
+
PLEASE NOTE: Audrey is in the very early stages of development. You're welcome
|
4
|
+
to try it out, but it's not ready for prime time yet.
|
5
|
+
|
6
|
+
Audrey is an easy, yet powerful database system. With Audrey you can create your
|
7
|
+
database and start using it in a few lines of code.
|
8
|
+
|
9
|
+
## Install
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
<!-- gem install audrey -->
|
13
|
+
```
|
14
|
+
|
15
|
+
## Basic usage
|
16
|
+
|
17
|
+
By default, Audrey uses SQLite for storage, so the only dependencies are SQLite,
|
18
|
+
which is standard on most Unixish systems, and this gem. To create and start
|
19
|
+
using a Audrey database, all you have to do is open it with `Audrey.connect`,
|
20
|
+
giving a path to a database file and a read/write mode - `'rw'`, `'r'`, or
|
21
|
+
`'w'`. The file doesn't need to already exist; it will be created automatically
|
22
|
+
as needed.
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
require 'audrey'
|
26
|
+
path = '/tmp/my.db'
|
27
|
+
|
28
|
+
Audrey.connect(path, 'rw') do |db|
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
It its simplest use, use the `db` object as a hash to store information:
|
33
|
+
|
34
|
+
```text
|
35
|
+
Audrey.connect(path, 'rw') do |db|
|
36
|
+
db['hero'] = 'Thor'
|
37
|
+
db['antagonist'] = 'Loki'
|
38
|
+
db['score'] = 1.3
|
39
|
+
db['ready'] = true
|
40
|
+
|
41
|
+
db.each do |k, v|
|
42
|
+
puts k + ': ' + v.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
That gives us this output:
|
48
|
+
|
49
|
+
```text
|
50
|
+
hero: Thor
|
51
|
+
antagonist: Loki
|
52
|
+
score: 1.3
|
53
|
+
ready: true
|
54
|
+
```
|
55
|
+
|
56
|
+
Audrey can store complex structures such as nested arrays and hashes.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
Audrey.connect(path, 'rw') do |db|
|
60
|
+
db['people'] = {}
|
61
|
+
people = db['people']
|
62
|
+
|
63
|
+
people['fred'] = {'name'=>'Fred'}
|
64
|
+
people['mary'] = {'name'=>'Mary', 'towns'=>['Blacksburg', 'Seattle']}
|
65
|
+
|
66
|
+
people['mary']['friend'] = people['fred']
|
67
|
+
|
68
|
+
puts db['people']['mary']['name']
|
69
|
+
puts db['people']['mary']['towns'].join(', ')
|
70
|
+
puts db['people']['mary']['friend']['name']
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
Take note of the line that reads
|
75
|
+
`people['mary']['friend'] = people['fred']`. Audrey doesn't use foreign
|
76
|
+
keys. Instead, you simply link objects directly to each other. So in this case,
|
77
|
+
`fred` is an element in the people hash, but it is *also* an element
|
78
|
+
in Mary's hash with the key `friend`. Objects can be linked in this
|
79
|
+
free form manner without the need for setting up lookup tables or defining
|
80
|
+
foreign keys.
|
81
|
+
|
82
|
+
## Custom classes
|
83
|
+
|
84
|
+
Audrey provides a system for defining your own classes. In this way, you can
|
85
|
+
define your own classes, using their properties and methods as usual. Objects of
|
86
|
+
those classes are automatically stored in the Audrey database and can be
|
87
|
+
retrieved, as objects, for use.
|
88
|
+
|
89
|
+
Consider, for example, this simple class:
|
90
|
+
|
91
|
+
```text
|
92
|
+
class Person < Audrey::Object::Custom
|
93
|
+
self.fco = true
|
94
|
+
field 'first'
|
95
|
+
field 'middle'
|
96
|
+
field 'surname'
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
This class inherits `Audrey::Object::Custom`, which almost all of your
|
101
|
+
Audrey classes should do.
|
102
|
+
|
103
|
+
The next line,
|
104
|
+
`self.fco = true`, is important. Every Audrey class must be set at
|
105
|
+
`self.fco = true` or `self.fco = false`. `fco` mean "first class object". When
|
106
|
+
the database is closed, objects that are not first class objects, and are not
|
107
|
+
*descended* from first class objects, are purged. Every custom class must be
|
108
|
+
explicitly set with `fco=true` or `fco=false`. Think of clases with`fco=false`
|
109
|
+
as being "cascade delete".
|
110
|
+
|
111
|
+
The next few lines define fields for a person record, first, middle and surname.
|
112
|
+
|
113
|
+
So we can use our class like this:
|
114
|
+
|
115
|
+
```text
|
116
|
+
Audrey.connect(path, 'rw') do |db|
|
117
|
+
mary = Person.new()
|
118
|
+
mary.first = 'Mary'
|
119
|
+
mary.middle = 'F.'
|
120
|
+
mary.surname = 'Sullivan'
|
121
|
+
|
122
|
+
fred = Person.new()
|
123
|
+
fred.first = 'Fred'
|
124
|
+
fred.middle = 'C.'
|
125
|
+
fred.surname = 'Murray'
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Later we're going to need to find the Person records. The simplest
|
130
|
+
way to get to them is to `each` them with the `Person` class
|
131
|
+
itself:
|
132
|
+
|
133
|
+
```text
|
134
|
+
Audrey.connect(path, 'rw') do |db|
|
135
|
+
Person.each do |person|
|
136
|
+
puts person.first
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
Notice that there is no need to reinstantiate the objects using data from the
|
142
|
+
database. Audrey automatically creates the objects from the stored data, and
|
143
|
+
makes them available for use as they were originally created.
|
144
|
+
|
145
|
+
The example above produces this output:
|
146
|
+
|
147
|
+
```text
|
148
|
+
Fred
|
149
|
+
Mary
|
150
|
+
```
|
151
|
+
|
152
|
+
Under the hood, `each` uses a type of query called q0. Later we'll look at more
|
153
|
+
details about how you can use Q0.
|
154
|
+
|
155
|
+
### Subclassing
|
156
|
+
|
157
|
+
Like any Ruby class, you can subclass your Audrey classes. For example, let's
|
158
|
+
subclass `Person` with `Guest`, and subclass `Guest` with `Preferred`:
|
159
|
+
|
160
|
+
```text
|
161
|
+
class Guest < Person
|
162
|
+
field 'stays'
|
163
|
+
end
|
164
|
+
|
165
|
+
class Preferred < Guest
|
166
|
+
field 'rating'
|
167
|
+
end
|
168
|
+
```
|
169
|
+
|
170
|
+
Notice that we didn't bother to set these subclasses as first class objects --
|
171
|
+
they inherited that property from `Person`. We also added a field to each of
|
172
|
+
our new subclasses. Now we can add `Guest` and `Preferred` objects to the
|
173
|
+
database:
|
174
|
+
|
175
|
+
```text
|
176
|
+
Audrey.connect(path, 'rw') do |db|
|
177
|
+
dan = Guest.new()
|
178
|
+
dan.first = 'Dan'
|
179
|
+
dan.stays = 10
|
180
|
+
|
181
|
+
pete = Preferred.new()
|
182
|
+
pete.first = 'Pete'
|
183
|
+
pete.stays = 12
|
184
|
+
pete.rating = 'gold'
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
Because `Guest` and `Preferred` derive from `Person`, we can iterate through
|
189
|
+
all of the records using `Person`, including objects from its derived classes.
|
190
|
+
|
191
|
+
```text
|
192
|
+
Audrey.connect(path, 'rw') do |db|
|
193
|
+
Person.each do |person|
|
194
|
+
puts person.first
|
195
|
+
end
|
196
|
+
end
|
197
|
+
```
|
198
|
+
|
199
|
+
which produces this output:
|
200
|
+
|
201
|
+
```text
|
202
|
+
Fred
|
203
|
+
Pete
|
204
|
+
Mary
|
205
|
+
Dan
|
206
|
+
```
|
207
|
+
|
208
|
+
|
209
|
+
## Autocommit and transactions
|
210
|
+
|
211
|
+
In all the examples so far, data has been written to the Audrey database
|
212
|
+
automatically as it has been produced. However, you might want to only
|
213
|
+
atomically commit data at specified points. You can do this using the
|
214
|
+
autocommit feature, or transactions.
|
215
|
+
|
216
|
+
### autocommit
|
217
|
+
|
218
|
+
To keep Audrey from automatically writing data, use the `autocommit` option in
|
219
|
+
`connect`, like this:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
Audrey.connect(path, 'rw', 'immediate_commit'=>false) do |db|
|
223
|
+
db['hero'] = 'Thor'
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
227
|
+
In the example above, the data is never committed by the end of the session, so
|
228
|
+
if we try to retrieve the data:
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
Audrey.connect(path, 'rw') do |db|
|
232
|
+
puts 'hero: ', db['hero']
|
233
|
+
end
|
234
|
+
```
|
235
|
+
|
236
|
+
\.\.\. we get this disappointing output:
|
237
|
+
|
238
|
+
```text
|
239
|
+
hero:
|
240
|
+
|
241
|
+
```
|
242
|
+
|
243
|
+
To commit, simply use the `commit` method:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
Audrey.connect(path, 'rw', 'immediate_commit'=>false) do |db|
|
247
|
+
db['hero'] = 'Thor'
|
248
|
+
db.commit
|
249
|
+
end
|
250
|
+
```
|
251
|
+
|
252
|
+
Which will give us more fulfilling results:
|
253
|
+
|
254
|
+
```text
|
255
|
+
hero:
|
256
|
+
Thor
|
257
|
+
```
|
258
|
+
|
259
|
+
Any time during the session you can use `rollback` to rollback to the previous
|
260
|
+
commit or to the state of the database when it was opened. So this code:
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
Audrey.connect(path, 'rw', 'immediate_commit'=>false) do |db|
|
264
|
+
db['antagonist'] = 'Loki'
|
265
|
+
db.rollback
|
266
|
+
puts 'antagonist: ', db['antagonist']
|
267
|
+
end
|
268
|
+
```
|
269
|
+
|
270
|
+
\.\.\. will output without Loki:
|
271
|
+
|
272
|
+
```text
|
273
|
+
antagonist:
|
274
|
+
|
275
|
+
```
|
276
|
+
|
277
|
+
### transaction
|
278
|
+
|
279
|
+
For more fine-grained control of when data is commited, you might prefer to use
|
280
|
+
`transaction`. Any time during a database session you can start a transaction
|
281
|
+
block. Changes to the database inside that block are not committed without an
|
282
|
+
explicit commit command. For example, consider this code::
|
283
|
+
|
284
|
+
```text
|
285
|
+
Audrey.connect(path, 'rw') do |db|
|
286
|
+
db['hero'] = 'Thor'
|
287
|
+
|
288
|
+
db.transaction do |tr|
|
289
|
+
db['antagonist'] = 'Loki'
|
290
|
+
end
|
291
|
+
|
292
|
+
db.each do |k, v|
|
293
|
+
puts k + ': ' + v
|
294
|
+
end
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
The database session is set to automatically commit data as it is created
|
299
|
+
(because `autocommit` defaults to true). However, when we use `db.transaction`
|
300
|
+
to start a transaction block. Within that block, data is not automatically
|
301
|
+
committed. So the output for this code will look like this:
|
302
|
+
|
303
|
+
```text
|
304
|
+
hero: Thor
|
305
|
+
```
|
306
|
+
|
307
|
+
Inside a transaction block, you can commit by calling the transaction's `commit`
|
308
|
+
method:
|
309
|
+
|
310
|
+
```text
|
311
|
+
Audrey.connect(path, 'rw') do |db|
|
312
|
+
db['hero'] = 'Thor'
|
313
|
+
|
314
|
+
db.transaction do |tr|
|
315
|
+
db['antagonist'] = 'Loki'
|
316
|
+
tr.commit
|
317
|
+
end
|
318
|
+
|
319
|
+
db.each do |k, v|
|
320
|
+
puts k + ': ' + v
|
321
|
+
end
|
322
|
+
end
|
323
|
+
```
|
324
|
+
|
325
|
+
That gives us this output:
|
326
|
+
|
327
|
+
```text
|
328
|
+
hero: Thor
|
329
|
+
antagonist: Loki
|
330
|
+
```
|
331
|
+
|
332
|
+
Rollback transactions with the `rollback` method. For example, in this code we
|
333
|
+
use both `rollback` and `commit`:
|
334
|
+
|
335
|
+
```text
|
336
|
+
Audrey.connect(path, 'rw') do |db|
|
337
|
+
db['hero'] = 'Thor'
|
338
|
+
|
339
|
+
db.transaction do |tr|
|
340
|
+
db['antagonist'] = 'Loki'
|
341
|
+
tr.rollback
|
342
|
+
db['ally'] = 'Captain America'
|
343
|
+
tr.commit
|
344
|
+
end
|
345
|
+
|
346
|
+
db.each do |k, v|
|
347
|
+
puts k + ': ' + v
|
348
|
+
end
|
349
|
+
end
|
350
|
+
```
|
351
|
+
|
352
|
+
In that example, we set
|
353
|
+
`db['antagonist'] = 'Loki'`. But in the next line we roll it back. Then in the next two lines we set
|
354
|
+
`db['ally'] = 'Captain America'` and commit it. The result is that `antagonist` is never committed but `ally`
|
355
|
+
is, producing this output:
|
356
|
+
|
357
|
+
```text
|
358
|
+
hero: Thor
|
359
|
+
ally: Captain America
|
360
|
+
```
|
361
|
+
|
362
|
+
Transactions can be nested. For example, in this code, the outer transaction is
|
363
|
+
committed, but not the inner transaction:
|
364
|
+
|
365
|
+
```text
|
366
|
+
Audrey.connect(path, 'rw') do |db|
|
367
|
+
db['hero'] = 'Thor'
|
368
|
+
|
369
|
+
db.transaction do |tr1|
|
370
|
+
db['antagonist'] = 'Loki'
|
371
|
+
|
372
|
+
db.transaction do |tr2|
|
373
|
+
db['ally'] = 'Captain America'
|
374
|
+
end
|
375
|
+
|
376
|
+
tr1.commit
|
377
|
+
end
|
378
|
+
|
379
|
+
db.each do |k, v|
|
380
|
+
puts k + ': ' + v
|
381
|
+
end
|
382
|
+
end
|
383
|
+
```
|
384
|
+
|
385
|
+
That gives us this output
|
386
|
+
|
387
|
+
```text
|
388
|
+
hero: Thor
|
389
|
+
antagonist: Loki
|
390
|
+
```
|
391
|
+
|
392
|
+
If an inner transaction is committed, but not the outer transaction, then
|
393
|
+
nothing in the inner transaction is finally committed. So, for example, consider
|
394
|
+
this code:
|
395
|
+
|
396
|
+
```text
|
397
|
+
Audrey.connect(path, 'rw') do |db|
|
398
|
+
db['hero'] = 'Thor'
|
399
|
+
|
400
|
+
db.transaction do |tr1|
|
401
|
+
db['antagonist'] = 'Loki'
|
402
|
+
|
403
|
+
db.transaction do |tr2|
|
404
|
+
db['ally'] = 'Captain America'
|
405
|
+
tr2.commit
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
db.each do |k, v|
|
410
|
+
puts k + ': ' + v
|
411
|
+
end
|
412
|
+
end
|
413
|
+
```
|
414
|
+
|
415
|
+
In that example we commit `tr2`. But `tr2` is nested inside `tr1`, which is
|
416
|
+
never committed. Therefore everything inside `tr1` is rolled back, giving us
|
417
|
+
this output:
|
418
|
+
|
419
|
+
```text
|
420
|
+
hero: Thor
|
421
|
+
```
|
422
|
+
|
423
|
+
### Exiting database connections and transactions
|
424
|
+
|
425
|
+
You might find that in some situations you don't need to continue a transaction,
|
426
|
+
or even an entire database connection, if certain conditions are met. For example,
|
427
|
+
suppose you want to add a record using web parameters, but only if the surname
|
428
|
+
is given. You might do that like this:
|
429
|
+
|
430
|
+
```ruby
|
431
|
+
Audrey.connect(path, 'rw') do |db|
|
432
|
+
db.transaction do |tr|
|
433
|
+
person = Person.new()
|
434
|
+
person.surname = cgi['surname']
|
435
|
+
|
436
|
+
if not person.surname
|
437
|
+
tr.exit
|
438
|
+
end
|
439
|
+
|
440
|
+
person.first = cgi['first']
|
441
|
+
person.middle= cgi['middle']
|
442
|
+
puts 'commit'
|
443
|
+
tr.commit
|
444
|
+
end
|
445
|
+
end
|
446
|
+
```
|
447
|
+
|
448
|
+
In this example, if no surname is given, the transaction stops when it hits
|
449
|
+
`tr.exit`. Nothing else in the transaction after that line is run.
|
450
|
+
|
451
|
+
You can also exit an entire database session with `db.exit`. So, using the same
|
452
|
+
business rules as above, you might code your database connection like this:
|
453
|
+
|
454
|
+
```ruby
|
455
|
+
Audrey.connect(path, 'rw') do |db|
|
456
|
+
if not cgi['surname']
|
457
|
+
db.exit
|
458
|
+
end
|
459
|
+
|
460
|
+
person = Person.new()
|
461
|
+
person.surname = cgi['surname']
|
462
|
+
person.first = cgi['first']
|
463
|
+
person.middle= cgi['middle']
|
464
|
+
end
|
465
|
+
```
|
466
|
+
|
467
|
+
## Queries with Q0
|
468
|
+
|
469
|
+
Audrey provides a query system called Q0. With Q0 you can perform basic queries
|
470
|
+
on objects, searching for by class and by field value.
|
471
|
+
|
472
|
+
### Q0 will not be the only query language
|
473
|
+
|
474
|
+
Before we go further, though, it's important to understand what Q0 is *not*: it
|
475
|
+
is not the only query language that Audrey will ever have. One of the problems
|
476
|
+
that database systems often have is that their query languages becomes more and
|
477
|
+
more convoluted as needs evolve. SQL is a good example. What started as a simple
|
478
|
+
system with English-like syntax evolved into a bizarre language with all manner
|
479
|
+
of join and function syntaxes. So, instead of assuming that we can invent a query
|
480
|
+
language that will always provide all needs, Audrey is designed to allow for
|
481
|
+
multiple query languages. As needs evolve and Q0 becomes unsuitable for advanced
|
482
|
+
needs, new query languages can be invented and added into the Audrey system.
|
483
|
+
|
484
|
+
Audrey will always have Q0. As long as they don't create problems with backward
|
485
|
+
compatibility, new features can be added to Q0.
|
486
|
+
|
487
|
+
### Search by class
|
488
|
+
|
489
|
+
Let's start with a simple example. In the following code, we create a Q0 object
|
490
|
+
with `db.q0`. We tell the query to look for everything in the `Person` class.
|
491
|
+
Then we `each` through the results:
|
492
|
+
|
493
|
+
```text
|
494
|
+
Audrey.connect(path, 'rw') do |db|
|
495
|
+
query = db.q0
|
496
|
+
query.fclass = Person
|
497
|
+
|
498
|
+
query.each do |person|
|
499
|
+
puts person.surname
|
500
|
+
end
|
501
|
+
end
|
502
|
+
```
|
503
|
+
|
504
|
+
Note that to search by class we use `fclass` (for *Audrey class*), not just
|
505
|
+
`class`. There are several reasons for this. First, the `class` property is
|
506
|
+
already taken. Second, as Audrey grows and is implemented by languages besides
|
507
|
+
Ruby, it will be necessary to distinguish because a Ruby class and a Audrey
|
508
|
+
class. Audrey classes have the same names as Ruby classes, but other languages,
|
509
|
+
such as Python, use a different naming scheme for classes.
|
510
|
+
|
511
|
+
The example above is functionally identical to one of the earlier examples in
|
512
|
+
which we use the `Person` class itself to search for records:
|
513
|
+
|
514
|
+
```text
|
515
|
+
Audrey.connect(path, 'rw') do |db|
|
516
|
+
Person.each do |person|
|
517
|
+
puts person.first
|
518
|
+
end
|
519
|
+
end
|
520
|
+
```
|
521
|
+
|
522
|
+
### Search by field values
|
523
|
+
|
524
|
+
Now we're going to filter by the values of fields. In this example, we set the
|
525
|
+
query to look for records in which the object's `first` field is "Mary".
|
526
|
+
|
527
|
+
```text
|
528
|
+
Audrey.connect(path, 'rw') do |db|
|
529
|
+
query = db.q0
|
530
|
+
query.fclass = Person
|
531
|
+
query.fields['first'] = 'Mary'
|
532
|
+
|
533
|
+
query.each do |person|
|
534
|
+
puts person.surname
|
535
|
+
end
|
536
|
+
end
|
537
|
+
```
|
538
|
+
|
539
|
+
To search for multiple possible values of a field, use an array that contains
|
540
|
+
all possible values:
|
541
|
+
|
542
|
+
```text
|
543
|
+
query.fields['first'] = ['Mary', 'Fred']
|
544
|
+
```
|
545
|
+
|
546
|
+
To search for records in which the field is nil or missing, use `nil`:
|
547
|
+
|
548
|
+
```text
|
549
|
+
query.fields['first'] = nil
|
550
|
+
```
|
551
|
+
|
552
|
+
To search for any value, as long as it is not nil, use the query's `defined`
|
553
|
+
method:
|
554
|
+
|
555
|
+
```text
|
556
|
+
query.fields['first'] = query.defined
|
557
|
+
```
|
558
|
+
|
559
|
+
You can mix and match these options in an array:
|
560
|
+
|
561
|
+
```text
|
562
|
+
query.fields['first'] = ['Mary', nil]
|
563
|
+
```
|
564
|
+
|
565
|
+
### Count
|
566
|
+
|
567
|
+
In addition to looping through query results, you can also get just a count of
|
568
|
+
how many objects are found. Simply use the query's count method:
|
569
|
+
|
570
|
+
```text
|
571
|
+
puts query.count()
|
572
|
+
```
|
573
|
+
|
574
|
+
### Other query filters
|
575
|
+
|
576
|
+
Currently, Q0 only allows you to search by fclass and field values. More filters
|
577
|
+
will be added as Audrey develops.
|
578
|
+
|
579
|
+
## Speed
|
580
|
+
|
581
|
+
I haven't done any benchmark tests on Audrey yet. I would be very interested to
|
582
|
+
see some if anybody would like to contribute in that way.
|
583
|
+
|
584
|
+
That being said, Audrey is probably not currently very fast. Keep in mind,
|
585
|
+
though, that it's worthwhile to balance execution speed against development
|
586
|
+
speed. Audrey, in its current implementation, probably isn't particularly fast
|
587
|
+
in execution, but it allows you go from no project to working project faster
|
588
|
+
than most database systems. Consider the tradeoff.
|
589
|
+
|
590
|
+
|
591
|
+
## The name and logo
|
592
|
+
|
593
|
+
I chose the name *Audrey* because I like it\.\.\. there's no fancy reason beyond
|
594
|
+
that. Apparently in Irish, *Audrey* once meant "vine", so I decided to use the
|
595
|
+
leaf of the
|
596
|
+
[Lonicera periclymenum](https://en.wikipedia.org/wiki/Lonicera_periclymenum),
|
597
|
+
a vine common in Ireland, for the logo. The logo was designed by
|
598
|
+
[Inventicstudios](https://www.fiverr.com/inventicstudios).
|
599
|
+
|
600
|
+
|
601
|
+
## Author
|
602
|
+
|
603
|
+
Mike O'Sullivan
|
604
|
+
mike@idocs.com
|
605
|
+
|
606
|
+
## History
|
607
|
+
|
608
|
+
| version | date | notes |
|
609
|
+
|---------|-------------|--------------------------|
|
610
|
+
| 0.1 | Jan 7, 2020 | Initial upload. |
|