{"id":15011377,"url":"https://github.com/brainlesslabs/bun","last_synced_at":"2025-04-12T03:31:02.561Z","repository":{"id":44425342,"uuid":"57435716","full_name":"BrainlessLabs/bun","owner":"BrainlessLabs","description":"Bun is a simple to use C++ Object Database, Object Relational Mapper (ORM) and key-value library","archived":false,"fork":false,"pushed_at":"2019-11-08T16:12:20.000Z","size":4000,"stargazers_count":108,"open_issues_count":9,"forks_count":16,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-25T23:22:17.403Z","etag":null,"topics":["bun","cplusplus","cplusplus-11","databases","header-only","json","key-value","key-value-store","msgpack","mysql","objectmapper","orm","orm-framework","orm-library","postgresql","sqlite3"],"latest_commit_sha":null,"homepage":"http://www.codeproject.com/Articles/1100449/Cplusplus-Object-Relational-Mapping-ORM-Eating-the","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BrainlessLabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-04-30T09:34:17.000Z","updated_at":"2025-01-14T23:08:13.000Z","dependencies_parsed_at":"2022-09-03T01:52:08.844Z","dependency_job_id":null,"html_url":"https://github.com/BrainlessLabs/bun","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainlessLabs%2Fbun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainlessLabs%2Fbun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainlessLabs%2Fbun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BrainlessLabs%2Fbun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BrainlessLabs","download_url":"https://codeload.github.com/BrainlessLabs/bun/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248512497,"owners_count":21116613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bun","cplusplus","cplusplus-11","databases","header-only","json","key-value","key-value-store","msgpack","mysql","objectmapper","orm","orm-framework","orm-library","postgresql","sqlite3"],"created_at":"2024-09-24T19:40:59.967Z","updated_at":"2025-04-12T03:30:57.549Z","avatar_url":"https://github.com/BrainlessLabs.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bun\n## Description\nBun is a simple to use C++ Object Relational Mapper (ORM) library and much more (key/value store, JSON conversion and Message Pack conversion). Following is the features of bun:\n* **Easy** to use\n* **Object persistence** - You can persist **C++ objects directly**.\n* **Non-intrusive** - You do not need to modify your classes to make them persistent\n* **Constraint** Specification in plain C++\n* Persist **Nested Objects**\n* **C++ EDSL** Object Query Language (No SQL Query needed)\n* **Compile time** EDSL syntax check for type safety - Catch bugs before the execution starts\n* Multiple database support - SQLite, Postgres, MySQL\n* Easy to use **embedded key/value store**\n* Convert C++ objects to **JSON** and create C++ objects from JSON.\n* Convert C++ objects to **Message Pack** and create C++ objects from Message Pack.\n* **Lazy iteration** over the objects in the database using range based for loop in C++\n\n[Bun Page](http://brainlesslabs.github.io/bun/)\n\n[![OpenHub](https://www.openhub.net/p/brainlesslabs_bun/widgets/project_thin_badge.gif)](https://www.openhub.net/p/brainlesslabs_bun)\n\n[![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges)\n\n## Whats new\n* **Bun 1.4.0** Has support for converting objects to JSON and create objects from JSON. It has the capability to convert objects to Message Pack and construct objects from Message Pack.\n* **Bun 1.3** Has support for lazy iteration and ranges based for loop support of objects. The same is supported for the key/value store too.\n* **Bun 1.2** has support for embedded key/value stores. But default, the key/value store is based on Unqlite.\n\n# Articles\n\n## Introduction to bun\n\n[CodeProject Article](http://www.codeproject.com/Tips/1100449/Cplusplus-Object-Relational-Mapping-ORM-Eating-the)\n\n# Usage\n\n## Object Persistence\n\nWith Bun you can persist C++ objects (POD) directly. The magic happens by registring the C++ structure/class with Bun and you are good to go.\n\n```C++\n#include \"blib/bun/bun.hpp\"\n\nnamespace test {\n  // Class that needs to be persisted\n  struct Person {\n    std::string name;\n    std::string uname;\n    int age;\n    float height;\n  };\n}\n\n/// @class Child \nstruct Child {\n    int cf1;\n    Child(const int cf = -1) : cf1(cf) {}\n    Child\u0026 operator=(const int i) {\n        cf1 = i;\n        return *this;\n    }\n};\n\n/// @class Parent\nstruct Parent {\n    int f1;\n    std::string f2;\n    // Nested object\n    Child f3;\n    Parent() :f1(-1), f2(\"-1\"), f3(-1) {}\n};\n\n// Both should be persistable\nSPECIALIZE_BUN_HELPER((Child, cf1));\nSPECIALIZE_BUN_HELPER((Parent, f1, f2, f3));\n\n/////////////////////////////////////////////////\n/// Generate the database bindings at compile time.\n/////////////////////////////////////////////////\nSPECIALIZE_BUN_HELPER( (test::Person, name, uname, age, height) );\n\nint main() {\n  namespace bun = blib::bun;\n  namespace query = blib::bun::query;\n\n  // Connect the db. If the db is not there it will be created.\n  // It should include the whole path\n  // For SQLite\n  //bun::connect( \"objects.db\" );\n  // For PostGres\n  bun::connect(\"postgresql://localhost/postgres?user=postgres\u0026password=postgres\");\n  // Get the fields of the Person. This will be useful in specifying constraints and also\n  // querying the object.\n  using PersonFields = query::F\u003ctest::Person\u003e;\n\n  // Generate the configuration. By default it does nothing.\n  bun::Configuration\u003ctest::Person\u003e person_config;\n  // This is a unique key constraint that is applied.\n  // Constraint are applied globally. They need to be set before the\n  // execution of the create schema statement\n  // The syntax is Field name = Constraint\n  // We can club multiple constraints in the same statement as shown below.\n  // There is no need for multiple set's to be called. This is how\n  // We can chain different constraints in the same statement.\n  person_config.set(PersonFields::name = bun::unique_constraint)\n                   (PersonFields::uname = bun::unique_constraint);\n  \n  // Create the schema. We can create the schema multiple times.\n  // If it already exists it will be safely ignored.\n  // The constraints are applied to the table.\n  // Adding constraints doesn't have an effect if the table already exists.\n  bun::createSchema\u003ctest::Person\u003e();\n  \n  // Start transaction\n  bun::Transaction t;\n\n  // Create some entries in the database\n  for (int i = 1; i \u003c 1000; ++i) {\n    // PRef is a reference to the persistent object.\n    // PRef keeps the ownership of the memory and releases the memory when it is destroyed.\n    // Internally it holds the object in a unique_ptr\n    // PRef also has an oid associated with the object\n    bun::PRef\u003ctest::Person\u003e p = new test::Person{};\n\n    // Assign the members values\n    p-\u003eage = i + 10;\n    p-\u003eheight = 5.6;\n    p-\u003ename = fmt::format( \"Brainless_{}\", i );\n\n    // Persist the object and get an oid for the persisted object.\n    const bun::SimpleOID oid = p.persist();\n\n    //Getting the object from db using oid.\n    bun::PRef\u003ctest::Person\u003e p1( oid );\n  }\n\n  // Commit the transaction\n  t.commit();\n\n  // To get all the object oids of a particular object.\n  // person_oids is a vector of type std::vector\u003cbun::SimpleOID\u003ctest::Person\u003e\u003e\n  const auto person_oids = bun::getAllOids\u003ctest::Person\u003e();\n\n  // To get the objects of a particular type\n  // std::vector\u003cbun::Pref\u003ctest::Person\u003e\u003e\n  const auto person_objs = bun::getAllObjects\u003ctest::Person\u003e();\n\n  // EDSL QUERY LANGUAGE ----------------------\n  // Powerful EDSL object query syntax that is checked for syntax at compile time.\n  // The compilation fails at the compile time with a message \"Syntax error in Bun Query\"\n  using FromPerson = query::From\u003ctest::Person\u003e;\n  FromPerson fromPerson;\n  // Grammar is checked for validity of syntax directly at compile time.\n  // Currently only \u0026\u0026, ||, \u003c, \u003c=, \u003e, \u003e=, ==, != are supported.\n  // They have their respective meaning.\n\n  // Below is a valid query grammar:\n  auto valid_query = PersonFields::age \u003e 10 \u0026\u0026 PersonFields::name != \"Brainless_0\";\n  std::cout \u003c\u003c \"Valid Grammar?: \" \u003c\u003c query::IsValidQuery\u003cdecltype(valid_query)\u003e::value \u003c\u003c std::endl;\n\n  // Oops + is not a valid grammar\n  auto invalid_query = PersonFields::age + 10 \u0026\u0026 \n  PersonFields::name != \"Brainless_0\";\n  std::cout \u003c\u003c \"Valid Grammar?: \" \u003c\u003c \n  query::IsValidQuery\u003cdecltype(invalid_query)\u003e::value \u003c\u003c std::endl;\n\n  // Now let us execute the query.\n  // The where function also checks for the validity of the query, and fails at compile time\n  const auto objs = fromPerson.where( valid_query ).where( valid_query ).objects();\n  // Can even use following way of query\n  // As you see we can join queries \n  const auto q = PersonFields::age \u003e 21 \u0026\u0026 PersonFields::name == \"test\";\n  const auto objs_again = FromPerson().where( q ).objects();\n  const auto objs_again_q = FromPerson().where(\n    PersonFields::age \u003e 21 \u0026\u0026 PersonFields::name == \"test\"\n  ).objects()\n\n  // Not going to compile if you enable the below line. \n  // Will get the \"Syntax error in Bun Query\" compile time message.\n  // const auto objs1 = FromPerson.where( invalid_query ).objects();\n\n  // Check the query generated. It does not give the sql query.\n  std::cout \u003c\u003c fromPerson.query() \u003c\u003c std::endl;\n\n  // Support for Nested object persistence and retrieval\n  bun::createSchema\u003cChild\u003e();\n  bun::createSchema\u003cParent\u003e();\n\n  std::cout \u003c\u003c \"How many objects to insert?\" \u003c\u003c std::endl;\n  int count = 0;\n  std::cin \u003e\u003e count;\n\n  for (int i = 0; i \u003c count; ++i) {\n    bun::l().info(\"===============Start===================\");\n    bun::PRef\u003cParent\u003e p = new Parent{};\n\n    p-\u003ef1 = i;\n    p-\u003ef2 = i % 2 ? \"Delete Me\" : \"Do not Delete Me\";\n    p-\u003ef3 = 10 * i;\n\n    // Persists the Parent and the Nested Child\n    p.persist();\n    std::cout \u003c\u003c \"Added to db: \\n\" \u003c\u003c p.toJson() \u003c\u003c std::endl;\n    bun::l().info(\"===============End===================\\n\");\n  }\n\n  std::cout \u003c\u003c \"Get all objects and show\" \u003c\u003c std::endl;\n  auto parents = bun::getAllObjects\u003cParent\u003e();\n\n  // Iterate and delete the Parent and the nested Child\n  // Here p is a PRef type. We can modify the object and persist \n  // the changes if needed.\n  for (auto p : parents) {\n    std::cout \u003c\u003c p.toJson() \u003c\u003c std::endl;\n    p.del();\n  }\n\n  return 0;\n}\n```\n### Range based iteration and Lazy iteration\nIts easy to retrieve values from database and iterate over them. The iteration is lazy, which means that the values are not retrieved all at once but paginated.\n\n```C++\n    // Iterate the parent with range based for loop\n    using FromParents = query::From\u003cParent\u003e;\n    using ParentFields = query::F\u003cParent\u003e;\n    FromParents from_parents;\n\n    // Select the query which you want to execute\n    auto parents_where = from_parents.where(ParentFields::f2 == \"Delete Me\");\n\n    // Fetch all the objects satisfying the query. This is a lazy fetch. It will be fetched\n    // only when it is called. And not all the objects are fetched.\n    // Here v is a PRef so it can be used to modify and persist the object.\n    for(auto v : parents_where) {\n        std::cout \u003c\u003c v.toJson() \u003c\u003c std::endl;\n    }\n```\n\n## Object conversion to JSON \u0026 from JSON and Object conversion to Message Pack \u0026 from Message Pack\n\nWith Bun you can do the following too:\n* Convert an C++ object to JSON\n* Create an C++ object from JSON\n* Convert and C++ object to Message Pack\n* Create an C++ object from Message Pack\n\nThe following code demonstrates that:\n\n```C++\n#include \"blib/bun/bun.hpp\"\n\nnamespace dbg {\n    struct C1 {\n        int c1;\n        C1() : c1(2) {}\n    };\n\n    struct C {\n        int c;\n        C1 c1;\n        C(const int i = 1) : c(i) {}\n    };\n\n    struct P {\n        std::string p;\n        C c;\n        P() : p(\"s1\"), c(1) {}\n    };\n}\n\nSPECIALIZE_BUN_HELPER((dbg::C1, c1));\nSPECIALIZE_BUN_HELPER((dbg::C, c, c1));\nSPECIALIZE_BUN_HELPER((dbg::P, p, c));\n\nint jsonTest() {\n    namespace bun = blib::bun;\n\n    bun::PRef\u003cdbg::P\u003e p = new dbg::P{};\n    p-\u003ep = \"s11\";\n    p-\u003ec.c = 10;\n\n    p-\u003ec.c1.c1 = 12;\n\n    bun::PRef\u003cdbg::C\u003e c = new dbg::C;\n    c-\u003ec = 666;\n\n    // Convert the object to JSON\n    const std::string json_string = p.toJson();\n\n    // Construct the new object out of JSON\n    bun::PRef\u003cdbg::P\u003e p1;\n    p1.fromJson(json_string);\n    const auto msgpack = p1.toMesssagepack();\n\n    // Construct another object out of messagepack\n    bun::PRef\u003cdbg::P\u003e p2;\n    p2.fromMessagepack(p1.toMesssagepack());\n\n    // messagepack to string\n    std::string msgpack_string;\n    for (auto c : msgpack) {\n        msgpack_string.push_back(c);\n    }\n    std::cout \u003c\u003c \"1. Original object Object:\" \u003c\u003c json_string \u003c\u003c std::endl;\n    std::cout \u003c\u003c \"2. Object from JSON      :\" \u003c\u003c p1.toJson() \u003c\u003c std::endl;\n    std::cout \u003c\u003c \"3. Object to Messagepack :\" \u003c\u003c msgpack_string \u003c\u003c std::endl;\n    std::cout \u003c\u003c \"4. Object from Messagepck:\" \u003c\u003c p2.toJson() \u003c\u003c std::endl;\n    return 1;\n}\n```\n\n## Key/value store\nBun has a key/value store. Currently the key/value store supported is Unqlite. Following example explains how to use it:\n\n```C++\n#include \"blib/bun/bun.hpp\"\n\n/// @fn kvTest\n/// @brief A test program for using the key/value store\nint kvTest() {\n    /// @var db\n    /// @brief Create the database.\n    /// If the database already exists it opens the database.\n    bun::KVDb\u003c\u003e db(\"kv.db\");\n\n    /// @brief put a value in database.\n    db.put(\"test\", \"test\");\n    std::string val;\n\n    /// @brief get the value. We need to pass a variable by reference to get the value.\n    db.get(\"test\", val);\n    std::cout \u003c\u003c val \u003c\u003c std::endl;\n    \n    const int size = 10000;\n    for (int i = 0; i \u003c size; ++i) {\n        const std::string s = fmt::format(\"Value: {}\", i);\n        db.put(i, s);\n    }\n\n    for (int i = 0; i \u003c size; ++i) {\n        std::string val;\n        db.get(i, val);\n        std::cout \u003c\u003c val \u003c\u003c std::endl;\n    }\n    \n    return 1;\n}\n```\n# Help Wanted\nConsidering the work needed to take this library further I will be needing any help available.\nHelp is needed in the following areas.\n\n1. Enhancements\n2. Fix bugs.\n3. Restructure and cleanup code.\n4. Enhance documentation.\n5. Constructive criticism and feature suggestions.\n6. Write tests.\n7. Use Bun\n\n# History\n### Alpha 1 (16th May 2016)\n* Initial version of the library\n\n### Alpha 2 (2nd July 2016)\nImplementing the Bun EDSL\n\n### Alpha 3 (14th March 2018):\n* Integrated SOCI as the database abstraction layer. This makes the library able to use any SQL database like SQLite, Postgres, MySQL. It mostly supports other databases that SOCI also supports but that's not tested yet.\n* Use of Boost Fusion. The code is much cleaner, fewer preprocessor macros. The code is more debuggable.\n* Support for transaction handling using the Transaction class\n* Better error handling and error logging\n* Added a lot of comments to help users\n\n### Alpha 4 (5th March 2018)\n* Support for nested objects\n* SimpleOID now uses boost UUID to generate a unique identifier\n* Additional comments\n* Small performance enhancements\n\n### Alpha 5 (19th May 2018)\n* Support for constraint before table creation\n\n### Alpha 6 (18th July 2018):\n* Adding key/value functionality to bun\n\n### Alpha 7 (11 August 2018):\n* Added range based for loop support for object iteration.\n* Added range based for loop support for key-value store iteration.\n* Both the iterations are lazy iterations.\n\n### Alpha 8 (19 October 2018)\n* Added support to create C++ object from JSON string\n* Added support to create Message Pack from C++ object\n* Added support to create C++ object from Message Pack\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrainlesslabs%2Fbun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrainlesslabs%2Fbun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrainlesslabs%2Fbun/lists"}