CINDI is a Meta-DBMS to support rapid application prototyping.
969
CINDI is a Meta Database Management System which provides a simple way for front-end applications to perform CRUD operations with various back-end stores. CINDI is written in Python 3, and is available in the PyPI Index as a PIP package.
CINDI is a service to translate INDI language statements to either SQL, MongoDB, or Redis. CINDI also caches read queries in memory, so that clients asking for the same thing repetitively do not actually get to hit the backing-stores.
CINDI is intended to be used during the early rapid-prototyping / idea phase, so that developers may focus on the layout, functionality, and usability of a front-end application. Think of CINDI as a temporary substitute, until a proper back-end infrastructure is built. This way, the initial pioneers of a project need only to focus their energy on the front-end(s).
The idea is to forgo the traditional map of API endpoints usually provided by a back-end. Instead, front-end code will submit INDI statements directly to a single endpoint, and receive JSON responses accordingly. The result is, most application logic is shifted into the front-end code, which simplifies the rapid prototyping of applications.
Later, when a minimal-viable-product had been demonstrated to stakeholders, and more developers can be assigned to the project, CINDI would then be replaced with a traditional API back-end.
Users may configure CINDI to use one, some, or all of the currently supported storage systems:
An easy Implementation Neutral Data Intermediate language is provided in order to abstract-away the underlying chosen store(s). The INDI language is similar to SQL, but re-worded to enforce the CRUD mentality.
The INDI language uses four major CRUD keywords: CREATE, READ, UPDATE, and DELETE.
CINDI will cache READ operations in-memory, until it detects those result-sets are stale (due to another CREATE, UPDATE, or DELETE affecting the data).
In order to demonstrate the INDI language, consider the following SQLite3 schema:
CREATE TABLE nonsense (
id INTEGER NOT NULL PRIMARY KEY,
nonsense_a TEXT,
nonsense_b TEXT,
nonsense_c TEXT
);
The above SQL statement would be prepared (manually, by the user) for CINDI before starting. Then, after loading CINDI, the four CRUD operations may be performed by submitting INDI statements to the system.
For example, here is an INDI CREATE statement:
CREATE IN nonsense FIELDS (nonsense_a, nonsense_b, nonsense_c) VALUES ("hekkin big", "skare", "today and now")
There would be no 'result' to the above query, other than the underlying store(s) being modified to reflect the insertion of new data. Client-side, this is what would be received as a response:
[[]]
Next example, here is an INDI READ statement:
READ IN nonsense id 1 FIELDS nonsense_a
The READ has a result, it would be a JSON array looking like this:
[[['hekkin big']]]
Now for a more comprehensive READ:
READ IN nonsense ALL RECORDS FIELDS (id, nonsense_a, nonsense_b, nonsense_c)
This retrieves all records from the nonsense table, including all columns:
[[[1, 'hekkin big', 'skare', 'today and now']]]
It appears that 'skare' is spelled wrong, so to UPDATE that:
UPDATE IN nonsense nonsense_b skare FIELDS (nonsense_b) VALUES (scare)
The literal result is an empty set:
[[]]
Check to see just that column had been updated:
READ IN nonsense id 1 FIELDS nonsense_b
Result:
[[['scare']]]
Finally, to DELETE the record:
DELETE IN nonsense id 1
A subsequent READ would return an empty set. Note the DELETE may have queried by any field, not just the 'id'!
VALUES quotes are optional, unless the string to be stored contains spaces.
See the doc/demo.txt file for the verbose output from the above demo.
The doc folder also contains schema examples for the other supported systems.
The above demonstration may seem trivial, however, consider that CINDI will support managing these INDI statements even if the backing-store is a NoSQL solution, such as MongoDB or Redis. The results are consistent, and if multiple stores are enabled, then any cache-missed READ will query all the stores, and compare the results to ensure consistency across the storage mechanisms.
If clients are submitting the same INDI queries repetitively, then the result from the first time is served from an in-memory Python dictionary. That cached query is discarded when an affecting CREATE, UPDATE, or DELETE occurs.
In the case of the NoSQL solutions, CINDI manages the concept of tables, columns, and primary keys. In particular, the MongoDB setup requires only creating a database, and the Redis setup requires nothing!
CINDI will not automatically initialize SQL / Mongo schemas, this must be done manually prior to runtime. That is why the author has provided a couple Docker demos, read on!
Check cindi_tests.py for more INDI language examples.
Please go here and follow the instructions in order to have Docker Compose orchestrate the setup of ultasun/cindi-lite, which will consume the least resources. Along the way, you'll learn everything there is to know about configuring the CINDI runtime for a minimalist SQLite3-only backing-store.
Please go here and follow the instructions in order to have Docker Compose orchestrate the complete setup and demonstration of ultasun/cindi, which will, by default, consume significantly more resources than ultasun/cindi-lite. Along the way, you'll learn everything there is to know about configuring the CINDI runtime for a full installation with all five supported backing-stores running simultaneously
A Docker image ultasun/cindi-lite is available on Docker Hub, it will use a SQLite3 setup, and provide a similar experience to Installing & Basic Setup on SQLite3.
After start-up, development Flask server will not have SSL enabled.
$ docker run -dp 36963:36963 --rm ultasun/cindi-lite$ docker run -dp 36963:36963 -v cindi-lite-data:/app/data -v cindi-lite-logs:/app/logs ultasun/cindi-litedocker exec -it into the container, and initialize the EXAMPLE data:
$ python>>> import cindi>>> cindi.quick_unit_tests()True, which means all 17 tests passed!http://localhost:36963/evaluate, such as:
READ IN nonsense ALL RECORDS FIELDS (id, nonsense_a, nonsense_b, nonsense_c)>>> cindi.print_2d_list(cindi.EXAMPLE_LIST)
cindi.quick_unit_tests()
Docker is not necessary to utilize CINDI. This installation demo will show manual installation from PyPI, and configuration using only SQLite3, to keep it brief. Please follow the detailed tutorial on cindi-plus to learn about configuring other backing-store systems.
pip install cindiconfig:
$ mkdir configconfig folder, create empty stores.txt and tables.txt files.
$ cd config && touch stores.txt && touch tables.txt && cd ..stores.txt with a text editor -- the file must contain a python dictionary, here is the basic example using only SQLite3:
{'sqlite3': {'db': 'db0', 'sqlite3_file_prefix': ''}}tables.txt with a text editor -- the file must contain a python list (or tuple), here is the basic example:
['nonsense']$ sqlite3 db0.dbsqlite> CREATE TABLE nonsense (id INTEGER NOT NULL PRIMARY KEY, nonsense_a TEXT, nonsense_b TEXT, nonsense_c TEXT);sqlite> .quit$ python3>>> import cindi>>> cindi.quick_unit_tests()
True if all tests succeed.>>> cindi.quick_cindi(cindi.EXAMPLE5)
Since CINDI is in the alpha development stage, every DML statement is logged in the logs/ directory. Whatever data you're submitting, a copy will be saved in that directory.
There is one INDI DML statement per file. Each filename ends with a nano-seconds-since-epoch timestamp. A filename prefixed with indi is a DML expression. At the time of this writing, there are no other files written to the logs/ directory.
There is no simple way to disable this disk logging without modifying the source code. Just re-define def fprint(w, x='', y='', z=''): to do nothing if you must. CINDI is in the alpha development stage, and it is designed to assist in developing apps which are also in the alpha development stage. SSL on the Flask development server is not even enabled, and the development server is 'not for production use' anyway.
CINDI is in the alpha development stage. If you've encountered a problem, then you've probably found a bug in the translation routines, or your backing-stores are not configured correctly.
CINDI will generally exit the Python3 process on most errors ('fail fast'). The logs/ directory is ordred by nanoseconds-since-epoch timestamps, so it should be easy to work-backwards to locate the INDI DML statement which was translated inconsistently across multiple backing-stores. The author can't forsee any other reason for CINDI to crash, besides a backing-store connectivity issue.
When the Python3 process exits, various exit codes are used. This helps frequent users/developers of CINDI quickly identify from the Docker console (or elsewhere) why an exit had occurred.
Here are the exit numbers and error messages which might be produced by CINDI:
Corrupted store, please file a bug. Check the CINDI README.
logs/, and santize your data first if possible. This error is really not the fault of the user (you). The VALUES may not be so important, so a simple script to truncate after the VALUES in each file within the logs/ directory if you can't or won't share the VALUES.
VALUES would be appreciated, because some parts of the translation code might do the wrong action if a value has too many single-or-double-quotes, it's a your-milage-may-vary scenario (at this time).
fprint failed to print to file: ...
fprint failed to write a file.!! ERROR: The quantity of fields detected is not euqal to the number of values detected...
FIELDS and VALUES, or,logs/ should not be necessary, because this error would be isolated to parsing a specific INDI DML statement before any writing to a backing-store occured.VALUES of the offending statement
Redis SET failed.
SET, it failed.config/stores.txt not found, please check the CINDI README.config/tables.txt not found, please check the CINDI README.config/ directory must be in the same directory . as where the Python3 process was launched. This is an elementary user mistake. Please review this README file carefully, or check one of the published Docker images for a proper example of how the Python3 process needs to be launched.config/stores.txt or config/tables.txt files are missing or not named properly.config/stores.txt not a dictionary, check the CINDI README.
config/stores.txt must be a Python3 dictionary. Check the syntax of what is in the file, and try again.config/tables.txt must be a list or tuple, check CINDI README.
config/tables.txt must be a Python3 list or tuple. Check the syntax of what is in the file, and try again.No stores defined in config/stores.txt! Check CINDI README.
config/stores.txt file has an empty dictionary in it.
Failed to initialize XXXXX connection.
config/stores.txt is not available.config/stores.txtconfig/stores.txt exists, permissions are good, and so on....sqlite3 connection, file not found?
High level error: ...
Low level error: ...
If you have multiple CINDI instances running against the same backing-stores, then a cache in one instance will not have a way to know if a DML CREATE/UPDATE/DELETE occured in another instance. Please do not allow multiple clones of CINDI to interact with the same backing-stores concurrently.
/cache-clear endpoint in Flask, orPlease read the LICENSE. This software was written by a single individual. This is alpha-quality software, you are likely to find bugs! Please submit feedback! Thank you for evaluating CINDI!
Content type
Image
Digest
sha256:afa4ee5ce…
Size
426.4 MB
Last updated
about 4 years ago
docker pull ultasun/cindi