This application provides a simple API for storing your data in your key-value store with history.
Prerequisites:
- PHP 7.4+ with
pdo_mysql
andredis
extensions - Composer
- MariaDB or MySQL server
- Redis server
composer install # Install dependencies
bin/console doctrine:migrations:migrate -n
Note that you may need to update your DB and Redis credentials.
Simply put DATABASE_URL=mysql://admin:[email protected]/object_store
in .env.local
and put your credentials there.
Application offers both Web and CLI interfaces.
The easiest way to run the application is by installing Symfony CLI and run:
symfony serve
Your app should be available at http://localhost:8000.
Use provided Swagger UI documentation to browse the API.
Application offers two CLI commands:
bin/console app:object-store:store <key> <value> # Stores the value in object store
bin/console app:object-store:get <key> [-t TIMESTAMP] # Gets the value from object store at given time
Please note that value
must me JSON-encoded and escaped for your terminal.
For example, if you want to store a string value: test-value
at key test-key
, you have to use following command:
bin/console app:object-store:store test-key \"test-value\"
This is to enable you to store complex data as a value.
Application allows you to easily swap between different implementations of storage drivers.
You can easily create one by implementing App\Infrastructure\ObjectStorage\ObjectStorageAdapter
interface and tagging your service with object_storage.adapter
tag (see example in config/services.yaml
file).
Currently implemented drivers are:
DoctrineObjectStorageAdapter
- stores data in DatabaseRedisObjectStorageAdapter
- stores data in Redis
To change the adapter, simply set STORAGE_ADAPTER
environment variable to redis
or doctrine
:
# /.env.local
STORAGE_ADAPTER=redis
DoctrineObjectStorageAdapter
uses Doctrine ORM to store data as ObjectEntry
entities.
The ObjectEntry
entity is using VARCHAR(255)
column type.
utf8mb4
character set for full Unicode support so you can use keys like 🧅 or 😃.utf8mb4_bin
collation ensures binary comparison of keys soKEY
!==key
andkey
!==kęy
.- Timestamp is stored as
TIMESTAMP
in UTC
Because of MySQL index length limitations, an error may occur when storing bigger keys.
RedisObjectStorageAdapter
uses Redis as storage using sorted sets.
Internally, the sorted set keeps only the change reference as:
KEY | VALUE | SCORE |
---|---|---|
key | SHA512(key):timestamp | timestamp |
Then, the actual value is stored in a hashmap as:
KEY | VALUE |
---|---|
SHA512(key):timestamp | value |
Because sorted sets require values to be unique, this approach allows value1 -> value2 -> value1
transitions to be properly stored.
Since the implementation uses SHA512 as part of the key, some conflicts may occur.
All components are covered by either unit or feature tests.
Running tests is as simple as configuring .env.test.local
variables to match your DB credentials and running:
bin/phpunit
To make sure your tests actually have necessary assertions, CI is running mutation tests using Infection.
Make sure you have Xdebug or PCOV extension enabled as it is required to run:
vendor/bin/infection
This application is being automatically tested using GitHub Actions and deployed on Heroku.