--
You received this message because you are subscribed to the Google Groups "Eiffel Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to eiffel-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/d3c7f3df-8b37-4b6b-80a6-04e3a615afa2n%40googlegroups.com.
Is that what is expected? I thought perhaps the application would pause or something?
Trying to go to "localhost" in Safari I get "Safari Can't Connect to the Server"
I am also in the process of trying MAMP to launch Apache server. Is that the right step?Thanks Anders.Yes that might work.I tried to run the simple example, getting this output in the terminal from which I started EiffelStudio:Content-Type: text/htmlContent-Length: 77Hello World! (UTC time is Saturday, 15-May-21 04:14:51 GMT).Your request:Is that what is expected? I thought perhaps the application would pause or something?
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/744cb596-a8c1-4d92-a229-bec9af04cf93n%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/eiffel-users/79c91a1f-35ac-41ed-8b99-ab5c5b0d4570n%40googlegroups.com.
Greetings all,
as a prelude to presenting a proposal for migrating the
Eiffel-Loop libraries to work with the lastest studio compiler, I
have significantly expanded a document describing one of the
"crown jewels" of Eiffel-Loop, an Eiffel orientated database.
As Larry Rix has suggested if I am going to ask for financial
support to do a conversion I should make a case for what he
describes as
.. and what value is there that is not already present in the base Eiffel libraries and GOBO libraries.
So I figured this library is a good place to start with a detailed description.
I recommend reading this document at it's home on the Eiffel-Loop website to get the benefit of hyper-linked class references, and of course you can browse all the source code. But I have also copied and pasted it below, but many relative hyperlinks did not survive the copy/paste.
http://www.eiffel-loop.com/library/Eco-DB.html
Although at 20 classes it might seem like a small library, bear in mind that much of the functionality comes from classes present in the Eiffel-Loop base libraries and elsewhere. EL_QUERYABLE_CHAIN is one such example.
In presenting a proposal at a later date, I am thinking to limit
the scope of the project to a curated list of what I think people
will generally find the most useful. Most likely it will be
defined as Eco-DB
and all it's dependencies in conjunction with Multi-Application
Management and all it's dependencies. This is actually quite
a lot of libraries.
-- Finnian
This library has 20 classes.
ECF: Eco-DB.ecf
Source code: directory list
DEPENDS
INTRODUCTION
Eco-DB is an acronym for Eiffel CHAIN Orientated Database, so called because it allows the extension by inheritance of a container conforming to CHAIN to assume many of the characteristics of a relational database table. Eco-DB leverages many of the facilities of the reflection cluster from the Eiffel-Loop base library, allowing class attributes to be managed as data table fields.
Some of the main features of this database system are as follows:
1. Perform the normal database CRUD operations.
2. Table joins, meaning a field in one CHAIN table can be used to look up a row-item in another using a hash table index. A supporting feature is the ability to generate indexed primary keys in an automated fashion.
3. Option to store data securely using AES encryption.
4. Database fields are defined as class attributes and are managed reflectively, but there is also a manual method for writing and reading.
5. A simple centralised method to specify which fields should maintain a hash index for fast row look-ups by field value. A caveat is it only useful for unique id fields, like email addresses for examples.
6. Powerful Eiffel-orientated query facility that leverages the Eiffel conjunctive, disjunctive and negated keywords. Can also be used with PREDICATE agents.
7. Leverages a feature of the reflection
cluster to link selected fields of an expanded type to a
textual representation, as defined for example by a DATE or EL_ENUMERATION [N -> NUMERIC] object.
This is important when it comes to importing or exporting tables
to/from a human readable form, or for setting the fields
reflectively from a string based source.
8. Contract support to protect database integrity by the inclusion of a CRC check-sum for each CHAIN table. This guards against accidental changes of field type, field order, field name or textual representation.
9. Facility to export a meta-data record of the precise definition of the persistent data structure as a pseudo-Eiffel class. See for example: myching.software-meta-data.tar.gz
10. Fully automated import/export of CHAIN tables in either CSV or Pyxis format (an XML analogue with superior readability). This can be used as a very safe form of backup allowing data to be re-imported even if the field order has changed. The Pyxis format is very compact and readable allowing easy manual inspection of data. The gedit text editor has syntax highlighting for this format. See for example: payment.pyx recording Paypal transactions.
11. Unlike a relational database, the data rows of a CHAIN table do not have to be flat, since class attributes in a store-able item, can themselves be declared to be store-able. For example class EL_UUID (inheriting UUID) can be a storable attribute, which itself is reflectively stored as 5 integer attributes of various types.
12. Application version awareness allows data to be migrated from a data table created by an earlier software version.
13. Has been used in production for an online shop to store details of software subscription sales via Paypal. It is also used very reliably in the My Ching software application to manage a journal of I Ching readings. In fact this application was one of the main drivers for development of this library.
PERSISTENCE
Of course this is the fundamental property of any database. Eco-DB offers 2 kinds of persistence:
1. CHAIN level persistence
This type of persistence involves storing the entire chain to a file in one operation. This is useful for data that is more or less static, like for example the localisation table EL_TRANSLATION_ITEMS_LIST.
See class ECD_CHAIN.
2. item level persistence
Item level, or "incremental persistence" is where the effects of any of the basic CHAIN operations (extend/replace/delete**) are recorded as they happen in a separate editions file. When the chain is loaded during object initialisation, a chain level store is loaded first, and then the stored editions are applied to bring the chain to it's final state.
See class ECD_RECOVERABLE_CHAIN for more details.
TABLE JOINS
Being able to join*** tables via a common field is the essence of a relational database. Eco-DB offers a number of features that support the joining of chains.
1. Field Indexing
For a large number of chain items, performing joins can be slow without the use of field indices. Eco-DB offers an easy way to maintain field indices with very little code via the implementing class ECD_ARRAYED_LIST [EL_STORABLE] which does all the work of maintaining the index. To index selected fields you just need to redefine the function new_index_by found in ECD_ARRAYED_LIST as in this example:
class SUBSCRIPTION_LIST inherit ECD_ARRAYED_LIST [SUBSCRIPTION] rename item as subscription_item redefine new_index_by end feature {NONE} -- Factory new_index_by: TUPLE [machine_id: like new_index_by_string_8; activation_code: like new_index_by_uuid] do create Result Result.machine_id := new_index_by_string_8 (agent machine_id_index) Result.activation_code := new_index_by_uuid (agent {SUBSCRIPTION}.activation_code) end feature {NONE} -- Implementation machine_id_index (subsription: SUBSCRIPTION): STRING do if subsription.is_expired then create Result.make_empty else Result := subsription.machine_id end end
2. Primary Keys
Being able to assign a unique identifier to each item in a chain is essential to creating many kinds of data-joins. Eco-DB offers a convenient way to both generate primary keys and maintain an index for it. This is achieved with the auxiliary class ECD_PRIMARY_KEY_INDEXABLE [EL_KEY_IDENTIFIABLE_STORABLE] when used in conjunction with ECD_ARRAYED_LIST [EL_STORABLE]. The class parameter implies that the storable item must conform to EL_KEY_IDENTIFIABLE_STORABLE. Generation of primary key values is automatic when the list is extended, as is maintenance of the primary key hash-table index.
QUERY LANGUAGE
Of course the Eiffel language itself can be used to query any CHAIN list, but sometimes the meaning of the query is obscured in implementation details. What is needed is a slightly more abstract way of expressing queries that makes the meaning more apparent. This is provided by the class EL_QUERYABLE_CHAIN and it's helper EL_QUERY_CONDITION_FACTORY. The implementing class ECD_ARRAYED_LIST inherits EL_QUERYABLE_CHAIN.
Conditions can be combined using the logical operators: and, or and not as in this example from class COLLATE_SONGS_TASK found in project Eiffel-Loop/example/manage-mp3.
apply -- sort mp3 files into directories according to genre and artist set in Rhythmbox music library Database. -- Playlist locations will be updated to match new locations. local new_mp3_path: EL_FILE_PATH; song: RBOX_SONG; query_result: LIST [RBOX_SONG] do query_result := Database.existing_songs_query (not (song_is_cortina or song_has_normalized_mp3_path)) if query_result.is_empty then lio.put_line ("All songs are normalized") else across query_result as query loop song := query.item .. end end end
The routine existing_songs_query passes a modified form of the query to songs list.
existing_songs_query (condition: EL_QUERY_CONDITION [RBOX_SONG]): like songs.query do Result := songs.query (not song_is_hidden and condition) end songs: EL_QUERYABLE_ARRAYED_LIST [RBOX_SONG]
The query atoms song_is_cortina and song_has_normalized_mp3_path are defined in class SONG_QUERY_CONDITIONS which is defined as follows
class SONG_QUERY_CONDITIONS inherit EL_QUERY_CONDITION_FACTORY [RBOX_SONG] rename any as any_song export {NONE} all end
META-DATA EXPORT
The routine export_meta_data in class ECD_REFLECTIVE_RECOVERABLE_CHAIN stores in a versioned directory the precise specification of the data layout, including the correct order, field types and names. The specification is formatted as pseudo Eiffel code so it can be easily viewed in an editor equipped with Eiffel syntax highlighting.
See for example: myching.software-meta-data.tar.gz (missing the version directory)
IMPORT/EXPORT
It is important to have a way to backup data that offer some degree of independence from the precise binary data structure for the purpose of replacing data with data from another software version, which may have fields stored in a different order, or types etc. Eco-DB supports two export formats:
The relevant class for importing or exporting is ECD_REFLECTIVE_RECOVERABLE_CHAIN
VERSION MANAGEMENT
A record of the software version is stored in each table. By defining procedure read_version from class EL_STORABLE
read_version (a_reader: EL_MEMORY_READER_WRITER; version: NATURAL) deferred end
it is possible to migrate data written by an earlier version of the software. If this is not required, this routine can be renamed to read_default_version in the inheritance section.
A DATABASE ABSTRACTION
There is a work in progress to create an abstraction representing the concept of a database i.e. a collection of related tables. Currently this exists only in the form of an application library for the myching.software shop server. More work is needed to create useful abstractions that can be added to the Eco-DB library.
A preview of classes which will form the basis of reusable abstractions are as follows:
Foot Notes
** delete is a routine from ECD_CHAIN and not from CHAIN.
*** We are using the term join somewhat loosely and mean only that if you have two chains CHAIN [A] and CHAIN [B], you can produce a subchain of CHAIN [B] where each B item has a matching field value with an item from CHAIN [A].
The question of which give better performance can really only be settled by presenting some benchmarks, but that takes quite a bit of time to prepare, so for now I will offer some speculative answers based on deductive reasoning.
The following is a Python example of data insertion using
SQLite
import sqlite3 con = sqlite3.connect('example.db') cur = con.cursor() # Create table cur.execute('''CREATE TABLE stocks (date text, trans text, symbol text, qty real, price real)''') # Insert a row of data cur.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") # Save (commit) the changes con.commit() # We can also close the connection if we are done with it. # Just be sure any changes have been committed or they will be lost. con.close()
Straightaway I can tell you Eco-DB is going to be faster at inserting, as any Eiffel values first needed be rendered as a string in SQLite. With an Eco-DB solution, no string rendering is required. You have a STOCK class with attributes of type DATE, STRING, INTEGER and REAL. You the implement a Eco-DB persistent list STOCK_LIST using ECD_ARRAYED_LIST.
Extending the stock list with a STOCK item uses the `extend' routine. After calling the standard ARRAYED_LIST precursor extend, it then creates a disk transaction by serializing the STOCK item reflectively to a shared reusable instance of MANAGED_POINTER using EL_MEMORY_READER_WRITER a descendant of the standard Eiffel class SED_MEMORY_READER_WRITER. From that point, the memory area is serialized to disk using {FILE}.put_managed_pointer, which I expect offers C like performance.
Here is a Python example of a SQLite query
for row in cur.execute('SELECT * FROM stocks ORDER BY price'): print(row) ('2006-01-05', 'BUY', 'RHAT', 100, 35.14) ('2006-03-28', 'BUY', 'IBM', 1000, 45.0) ('2006-04-06', 'SELL', 'IBM', 500, 53.0) ('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
I expect an Eiffel wrapper works similarly. The data comes back
in some non Eiffel form and you need to reconstruct a STOCK object
from the returned data. This is not necessary with Eco-DB. With
Eco-DB the above is just this (assuming STOCK inherits EL_REFLECTIVELY_SETTABLE_STORABLE)
across stock_list.ordered_by (agent {STOCK}.price, True) as list loop list.item.print_fields (lio) end
This operation is essentially the application of an agent to each
item in the list during the temporary creation of an EL_KEY_SORTABLE_ARRAYED_MAP_LIST
list.
Since you do not need to recreate the STOCK objects, I would wager that Eco-DB is faster.
My trust in Eco-DB is based mainly on my own and a few dozen customers who use the My Ching product. I discovered early on that this product could double as a handy password manger, and I created a Easter egg in the app, a password manager with AES 256 bit encryption, using the same persistent data format. For the last 10 years or so it has reliably managed all my hundreds of passwords split into multiple categories. None of my customers over the years have ever complained of data corruption.
The database structure is admittedly very simple, a single table READING_LIST containing READING objects is all that is required. The storable attributes are as follows
Attribute list for class READING Declared in class Feature EL_WORD_SEARCHABLE word_token_list: EL_WORD_TOKEN_LIST word_table: EL_WORD_TOKEN_TABLE READING question: EL_ZSTRING ANNOTATED_READING notes: EL_ZSTRING_LIST RELATED_READING next_related: READING is_head: BOOLEAN EL_STORABLE is_deleted: BOOLEAN READING id: EL_UUID READING_HEXAGRAM hexagram_bitmap: INTEGER_32 READING date: DATE
Also the My Ching shop with integrated software subscription manager has reliably stored all the subscription activation and sales data. As I was scared to death of anything getting corrupted I went to the trouble of creating a bullet proof system of meta data CRC checks in contract forms, as well as a way to export with zero coding to human readable and very compact Pyxis format. Restores work reliably ! Now I sleep soundly at night.
(IMHO Pyxis is also more compact and readable than JSON)
Eco-DB is a hybrid object-relational database that is 100%
Eiffel. The objects that correspond to table rows just need to
inherit either EL_STORABLE
or EL_REFLECTIVELY_SETTABLE_STORABLE.
These objects to do need to be flat in nature but may have a
recursive structure, i.e. The class inheriting EL_STORABLE
may it self containing attribute conforming to either EL_STORABLE
or COLLECTION [EL_STORABLE]
They may also have attributes of COLLECTON [N] where any is some
storable type: basic expanded type, string, path or date. I am
thinking to add MANAGED_POINTER to this list as well, so blob of
binary data can also be stored. A trivial task in the reflection
system. Storable attributes may also be TUPLE types.
Quite obviously Eco-DB is a lot more convenient than SQLite, because you don't have to spend any time converting Eiffel objects to tables, or clusters of related tables.
When using EL_REFLECTIVELY_SETTABLE_STORABLE
there is a lot of flexibility in defining which attributes you
want to make persistent. There are multiple ways of excluding and
including attributes. (3 to be exact)
Because Eco-DB is essentially an "in-memory" database, the size of the data you can store is limited by the amount of RAM on the platform. This is where SQLite has an advantage, as I believe it is practically only limited by space of the hard drive.
I concede SQLite has an advantage here, as Eco-DB tables are not
portable across machines with different endian characteristics.
This is by no means an exhaustive analysis but I hope sufficient for people to consider that maybe Eco-DB might be a better option at least for some kinds of application, than SQLite.
A quick Google search showed that SQLite has a "BLOB" data type ready for storing binary data...