Home

Awesome

This project is at early development phase!

Developed with JetBrains tools:

CLion icon

flexilite

"Smart data structures and dumb code works a lot better than the other way around."

Eric S. Raymond, The Cathedral and The Bazaar.

"Bad programmers worry about the code. Good programmers worry about data structures and their relationships." Linus Torvalds

What is Flexilite?

Flexilite ("F") is a SQLite extension library, written in C/C++ and LuaJIT, which converts ordinary SQLite database into repository of data classes, objects and their relations, with highly dynamic and flexible structure. Flexilite intends to solve typical problems of evolutional design of relational databases. "F" covers most of known db schema refactoring patterns. Not only that, "F" also provides few useful and highly demanded features out of box. We will list them later in this document.

Loading in any SQLite app:

select load_extension('libFlexilite');

Documentation Index

Main idea in few sentences:

Traditional way to design db schema becomes noticeably outdated in the modern ever-changing world. What was good 30 years ago (RDBMS) does not match real life complexity nowadays. When designing new system or maintaining existing one, db schema has to go through many iterations of refactoring.

The goal of this project is to provide proof of concept and at the same time production ready, easy-to-use, feature rich and flexible solution to deal with uncertainties of database schema design. Flexilite is based on SQLite as a storage engine and thus is usable in any type of application where SQLite is a good fit (from embedded systems, to smartphones, to desktop apps, to small-to-medium websites).

We strive to provide ability to organize, store and query data in the most flexible but still structured way. The goal of "F" is to be able to import arbitrary XML file, without necessity to define classes and properties, and create ad-hoc classes during import. Then, be able to migrate data into a meaningful schema, using set of available data refactor patterns. At the end, to convert raw schemaless data into structured object graph, with strict (or not so strict) rules and schema.

Install and Build

Build instructions

Feature Highlights

Still not sure? Here is an example

Let's take a look at this hypothetical flow of database schema migration:

  1. Create DB table Person, with columns: PersonID, Name, Email, Phone, AddressLine1, AddressLine2, City, ProvinceOrState, PostalCode, Country
  2. On next iteration, added columns WorkEmail, WorkPhone and renamed Email to PersonalEmail, Phone - to CellPhone
  3. Create table Phones, with columns: PhoneNumber, PersonID, PhoneType moved value from Phone column in Person table, with assigning PersonID. (setup one-to-many relation)
  4. Do the same for Email column, by creating table called Email, with columns: PersonID, Email, EmailType.
  5. For maintaining database integrity create tables EmailType and PhoneType
  6. In table Person create columns FirstName and LastName, split value of Person.Name into these 2 new columns, drop column Name, created computed column Name = FirstName + ' ' + LastName
  7. Create table Address, with columns AddressID, AddressLine1, AddressLine2, City, ProvinceOrState, PostalCode, Country
  8. Move address info from Person table to Address table, add column AddressID, set it to ID of newly associated Address row, at the end dropped address columns from Person table
  9. Create table CountryID, with columns CountryCode, CountryName
  10. Extracted country data from table Address, replacing Country with CountryCode. Also, apply fuzzy logic to process possible misspelling of country names

Sounds familiar? Have you ever needed to deal with cases like those above? Do you remember how painful every step was? Needless to mention that every step from this list would normally require: a) writing script to migrate database schema b) writing script to move existing data (or reset existing database and start from fresh new, if change happens in the middle of development and data are not worthy to keep).

(We omit here other things that also need to be done after DB schema changes - updating UI forms, and very likely, revisiting UI flow, changing navigation, handling different typical cases and so on. These tasks can be as time and effort consuming as direct DB changes, but we will ignore this class of changes as it goes too far from the library scope).

Data schema evolution patterns

We have went through this pain as well, and eventually come up with the concept of data schema evolution patterns. We analyzed typical practical cases and came up with the list of data schema evolution patterns. Every pattern involves specific modification of schema and existing data. Sequence of such patterned modifications step allow to migrate from one schema to a completely different one, while preserving data and keeping it in a consistent state.

In major percentage of cases database schema in its evolution shifts towards complication, and decomposition. I.e. schema requires new tables/classes to be introduced, new columns/attributes.

Database schema migration patterns described above present just a subset of typical issues that database and application developer needs to address when designing, developing and maintaining real world business software.

Besides, there is whole set of other data related tasks that are not covered by a traditional RDBMS (or NoSQL) systems, and require case-by-case resolving. Short list of such tasks might look as follows:

(Incomplete )List of schema refactoring patterns

-Extract 1 or more fields from existing table to a new table (or merge to existing one) and convert it to reference (with name) -Change reference type from 1-to-1 to 1 -> many, or many -> many -Add property -Remove (or hide) property -Change property type and other attributes (unique, required, length, UI editor type/viewer etc.) -Merge 2 classes, with optional property mapping -Move existing object(s) from one class to another (new or existing) -Set property as indexed (for fast lookup) or full text indexed -Move referenced item in the list up and down -Rename class -Rename property -Change class and property settings

How does Flexilite work?

In order to make schema refactoring smooth, flexible and fast, Flexilite utilizes special database design. In fact, this design is based on Entity-Attribute-Value (EAV) concept, with some improvements to avoid performance degradation associated with traditional EAV implementation. All actual data is stored in the fixed set of tables.

Is it alternative to NoSQL?

Short answer - yes and no. Long answer: Flexilite can definitely be used as a document oriented database ("yes"), but its approach and underlying database engine serve different purpose. It is not designed to replace big guys like Mongo or PostgreSQL ("no"). It is good fit for small to medium size database. And unlike well known NoSQL databases, SQLite supports metadata natively. It means that it combines schema and schemaless types of storage.

Why SQLite?

SQLite is widely used - from smartphones, to moderately used websites, from embedded devices, to rich desktop applications. It is reliable, fast, cross-platform and fun to use. And most importantly, SQLite has all features needed for achieving Flexilite goals. When properly configured, SQLite can be a perfect database storage for small workgroups (8-10 simultaneous users creating new content). By proper configuration we mean: use larger page sizes (8KB is default for Flexilite), memory for temporary storage, WAL for journaling mode, use shared cache and connection pooling. Optimal configuration will be covered in a separate article.

Are other databases supported?

We focus currently on SQLite and also have plans towards supporting BerkeleyDB, via SQLite API, for better writing concurrency, replication and high availability.

Running tests

"F" uses busted for Lua code testing.

cd  ./test_lua
busted --lua=PATH_TO_LUJIT_EXE ./index.lua 

For example:

/torch/luajit/bin/busted  --lua=/torch/luajit/bin/luajit  ./create_class.lua 

(Note that busted needs to run using LuaJit interpreter. POC Lua will fail)