{"id":37182924,"url":"https://github.com/timmytune/simpleg","last_synced_at":"2026-01-14T21:06:50.438Z","repository":{"id":57570332,"uuid":"284607958","full_name":"timmytune/simpleg","owner":"timmytune","description":"Simple, lightweight, Activerecord like, embeded graph database written in go.","archived":false,"fork":false,"pushed_at":"2023-02-25T03:29:50.000Z","size":183,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-06-20T10:13:46.299Z","etag":null,"topics":["embedded","golang","graphdatabase"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timmytune.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-03T05:04:24.000Z","updated_at":"2022-08-20T17:30:21.000Z","dependencies_parsed_at":"2024-06-20T09:22:38.085Z","dependency_job_id":"a6551e0b-a288-4b51-bcfa-8c0bcc0a4fbd","html_url":"https://github.com/timmytune/simpleg","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/timmytune/simpleg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timmytune%2Fsimpleg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timmytune%2Fsimpleg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timmytune%2Fsimpleg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timmytune%2Fsimpleg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timmytune","download_url":"https://codeload.github.com/timmytune/simpleg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timmytune%2Fsimpleg/sbom","scorecard":{"id":886300,"data":{"date":"2025-08-11","repo":{"name":"github.com/timmytune/simpleg","commit":"e70e0facb995d9f3b8e7b125e7d7210d83c8f4d3"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"14 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2025-3372 / GHSA-6wxm-mpqj-6jpf","Warn: Project is vulnerable to: GO-2022-0288","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2022-0493 / GHSA-p782-xgp4-8hr8","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T10:11:25.737Z","repository_id":57570332,"created_at":"2025-08-24T10:11:25.737Z","updated_at":"2025-08-24T10:11:25.737Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28434545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T18:57:19.464Z","status":"ssl_error","status_checked_at":"2026-01-14T18:52:48.501Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["embedded","golang","graphdatabase"],"created_at":"2026-01-14T21:06:49.638Z","updated_at":"2026-01-14T21:06:50.415Z","avatar_url":"https://github.com/timmytune.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Simpleg\n\nSimple, lightweight, Activerecord like, embeded graph database written in go.\n\n# Why Simpleg?\nGraph databases are cool (check [here](https://dzone.com/articles/what-are-the-pros-and-cons-of-using-a-graph-databa) to know more) but they are quite expensive to use, Google and Facebook can spin up hundreds of 64GB memory servers to handle their graph database but i doubt if there is anyone out there willing to setup an 8GB memory server to host the database for a pet project. This is where Simpleg comes in removing the overkill features like accepting data over a network, dedicated interaction language and multiple server coordination features to give you a database you can host in your 1GB VPS without any issues while providing all the necessary graph database features. Simpleg uses [Badger](https://github.com/dgraph-io/badger/) as it's internal key value store thereby bringing the power of one of the top key value databases (also used by [Dgraph](https://dgraph.io/) internally) out there. Simpleg is also built with a flexible and easily extensible core giving you the opprtunity to extend with functionalities that suite your needs without modifications to the main codebase!\n\n\n\n# Installation\nAdd Simpleg to your `go.mod` file:\n```\nmodule github.com/x/y\n\ngo 1.14\n\nrequire (\n        github.com/timmytune/simpleg/simpleg latest\n)\n```\n\n\n\n# Initialization \u0026 Configuration\n\nSimpleg is structured like an ORM and like many ORMs you are going to be writing a substantial amount configuration.\n\n## Initializating the DB\n\n```go\nimport (\n\tsimpleg \"github.com/timmytune/simpleg/simpleg\"\n)\n\nfunc main() {\n\t//get the default configuration for simpleg. This configuration is of type simpleg.Options\n\tdbOptions := simpleg.DefaultOptions()\n\t//get a pointer to a new instance of simpleg.DB\n\tdb := simpleg.GetNewDB()\n\t//Initialize DB with options\n\tdb.Init(opt)\n\t...\n```\n## ObjectType \nAn Object in simpleg is the same thing as vertex in other graph databases. An objectType is an abstract representation of a set of objects i.e models in Laravel and Mongoose. ObjectType In simpleg needs to be initialized in order to use. To initialize an objectType you have to provide an instance of simpleg.ObjectTypeOptions. Check below for implementation.\n\n```go\n\nimport (\n\tsimpleg \"github.com/timmytune/simpleg/simpleg\"\n)\n//type of object simpleg will be using. Everytime simpleg wants to return data of the objectType from the db it will come as an instance of this struct \ntype Object struct {\n\t//Mandatory field, instance of the current DB\n\tDB       *DB\n\t//Mandatory field, identifier of the current object\n\tID       uint64\n\t//Optional field that is a part of this object\n\tfield1   string\n\t//Optional field that is a part of this object\n\tfield2   bool\n}\n\n//Function to get Options for the objext we are addding to the DB\nfunc GetObjectOptions() simpleg.ObjectTypeOptions {\n\t//Initialize a new instance of simpleg.ObjectTypeOptions\n\tot := simpleg.ObjectTypeOptions{}\n\t//Set the name the object will use.\n\tot.Name = \"Object\"\n\t//Called everytime there is a request for a new object of this type. \n\tot.New = func(db *simpleg.DB) interface{} {\n\t\treturn Object{DB: db, field1: \"Default value\"}\n\t}\n\t//Called everytime simpleg is converting key value returned from db to object of this type\n\tot.Get = func(m map[KeyValueKey][]byte, db *simpleg.DB) (interface{}, []error) {\n\te := make([]error, 0)\n\tdb.RLock()\n\tdefer db.RUnlock()\n\tu := Object{DB: db}\n\tif id, ok := m[KeyValueKey{Main: \"ID\"}]; ok {\n\t\tf, err := db.FT[\"uint64\"].Get(id)\n\t\tif err != nil {\n\t\t\te = append(e, err)\n\t\t\treturn nil, e\n\t\t}\n\t\tu.ID = f.(uint64)\n\t} else {\n\t\te = append(e, errors.New(\"The Data from the DB has no ID\"))\n\t\treturn nil, e\n\t}\n\tif f, ok := m[KeyValueKey{Main: \"field1\"}]; ok {\n\t\tv, err := db.FT[\"string\"].Get(f)\n\t\tif err != nil {\n\t\t\te = append(e, err)\n\t\t} else {\n\t\t\tu.field1 = v.(string)\n\t\t}\n\t}\n\tif f, ok := m[KeyValueKey{Main: \"field2\"}]; ok {\n\t\tv, err := db.FT[\"bool\"].Get(f)\n\t\tif err != nil {\n\t\t\te = append(e, err)\n\t\t} else {\n\t\t\tu.field2 = v.(bool)\n\t\t}\n\t}\n\treturn u, e\n\t}\n\t//Called everytime simpleg wants to convert object of this type to key/value pair to save to DB\n\tot.Set = func(i interface{}, db *simpleg.DB) (u map[KeyValueKey][]byte, e []error) {\n\tu = make(map[KeyValueKey][]byte)\n\te = make([]error, 0)\n\td := i.(Object)\n\tdb.RLock()\n\tdefer db.RUnlock()\n\tif d.ID \u003e uint64(0) {\n\t\tu[KeyValueKey{Main: \"ID\"}], _ = db.FT[\"uint64\"].Set(d.ID)\n\t}\n\tif d.field1 != \"\" {\n\t\tu[KeyValueKey{Main: \"field1\"}], _ = db.FT[\"string\"].Set(d.firstName)\n\t}\n\tif d.field2 != \"\" {\n\t\tu[KeyValueKey{Main: \"field2\"}], _ = db.FT[\"bool\"].Set(d.firstName)\n\t}\n\treturn\n\t}\n\t//Provide validation \n\tfv :=  simpleg.FieldValidation{}\n\t//Initialize fields\n\tot.Fields = make(map[string]FieldOptions)\n\t//Add the configuration for each individual field\n\tot.Fields[\"field1\"] = FieldOptions{\n\t\t\t\t\t\t\t//set wether this field would be indexed or not\n\t\t\t\t\t\t\tIndexed: true,\n\t\t\t\t\t\t\t//Set if this field is an advanced one one or not\n\t\t\t\t\t\t\tAdvanced: false, \n\t\t\t\t\t\t\t//The fieldtype this field is attached to\n\t\t\t\t\t\t\tFieldType: \"string\", \n\t\t\t\t\t\t\t//Validation function to use when saving this field to DB\n\t\t\t\t\t\t\tValidate: fv.String(\"field1\", 3, 20, true, true, false)}\n\tot.Fields[\"field2\"] = FieldOptions{\n\t\t\t\t\t\t\tIndexed: true, \n\t\t\t\t\t\t\tAdvanced: false, \n\t\t\t\t\t\t\tFieldType: \"bool\"}\n\t//Called everytime an object of this type is about to be saved into the database. it checks if the object is valid and transform its fields if you want them transformed\n\tot.Validate = func(i interface{}, db *simpleg.DB) (interface{}, []error) {\n\te := make([]error, 0)\n\tdb.RLock()\n\tdefer db.RUnlock()\n\td := i.(Object)\n\tx, y, z := db.OT[\"Object\"].Fields[\"field1\"].Validate(d.field1, db)\n\tif !x {\n\t\te = append(e, z)\n\t} else {\n\t\td.field1 = y.(string)\n\t}\n\treturn d, e\n\t}\n\n\treturn ot\n\t}\n\n\t//Register this object type with the DB\n\tdb.AddObjectType(GetObjectOptions())\n```\n\nYou must be wondering this a lot of code and you are right but majority of the code checks for errors. Also Simpleg is structured this way to provide a lot of features without sacrificing performance. Here are some of the things you can achieve  \n-   Setting default values \n-   Virtual fields\n-   Validation \n-   Database field names can be differnt from object field names\n  And many more.   \n\n## LinkTypes\nLinks in simpleg are the same thing as edges in in other graph databases. It signifies a relationship between two Objects. A linkType is an abstract form of a link. All links are a type of Linktype and all links can only be of one linkType. There are three types of links in simpleg.\n-   One to one:- This is the type of link that links two objects of the same type and relationship stil means the same thing if reversed. An example is facebook friends, it has the same meaning from the perspective of both users that are friends. There is only one version of information is stored in the database.\n-   One to another:- This is the type of link that links two objects of separate object types where the relationship cannot be reversed. An example is the relationship between a facbook user and his/her post, a user can make a post but a post cannot make a user.There is only one version of information stored in the database.\n-   One to One with opposite not meaning same thing:- This is the type of link that links two objects of the same type but with the possibility of another relationship between same objects. An example is that of a landlord and a tenant, it is a one way relationship but it is possible for the tenant to own a beach house where landlord can then be the tenant of his own tenant. another example is twitter following, i can follow you but it is possible that you are not following me. This kind of relationship stores two different versions of the relationship in the database.\n  \nWhen it comes to representation and storage in the DB Links and Objects are stored in the same way and both of them can have serveral fields. There are differences though, objects must have fields while fields are not mandatory for links, links too don't have a unique identifier, they rely on the objects they are connecting. below is the configuration required to add a linkType to simpleg, Fields have been ommited but take note they can be added if you want them.\n\n```go\n//link object \ntype Link struct {\n\t//instance of DB (mandatory)\n\tDB   *DB\n\t//FROM id of the object this link is originating from (Mandatory)\n\tFROM uint64\n\t//TO id of the Object this link is linking to (Mandatory)\n\tTO   uint64\n}\n\nfunc GetLinkOptions() simpleg.LinkTypeOptions {\n\t//Initialize the simpleg link option type\n\tfl := simpleg.LinkTypeOptions{}\n\t//Here we specify the link type, \n\t//1 stands for links where both sides of the link are the same and the realationship can only be established once\n\t//2 stands for links where both sides are of different types \n\t//3 stands for links where both sides are of the same type but multiple relationships can be established\n\tfl.Type = 3\n\t//Name of link as stored and retrieved from the DB\n\tfl.Name = \"Link\"\n\t//Type of object this link will be originating from\n\tfl.From = \"Object\"\n\t//Type of object this link will be leading to\n\tfl.To = \"Object\"\n\t//Return a new instance of the link, called internally\n\tfl.New = func(db *DB) interface{} {\n\t\treturn Link{DB: db}\n\t}\n\t//Called everytime simpleg wants to convert data gotten from the DB into an instance of the Link\n\tfl.Get = func(m map[KeyValueKey][]byte, db *DB) (interface{}, []error) {\n\t\te := make([]error, 0)\n\t\tdb.RLock()\n\t\tdefer db.RUnlock()\n\t\tlike := Link{DB: db}\n\t\tif f, ok := m[KeyValueKey{Main: \"FROM\"}]; ok {\n\t\t\tv, err := db.FT[\"uint64\"].Get(f)\n\t\t\tif err != nil {\n\t\t\t\te = append(e, err)\n\t\t\t} else {\n\t\t\t\tlike.FROM = v.(uint64)\n\t\t\t}\n\t\t} else {\n\t\t\te = append(e, errors.New(\"The Data from the DB has no FROM field set\"))\n\t\t\treturn nil, e\n\t\t}\n\t\tif f, ok := m[KeyValueKey{Main: \"TO\"}]; ok {\n\t\t\tv, err := db.FT[\"uint64\"].Get(f)\n\t\t\tif err != nil {\n\t\t\t\te = append(e, err)\n\t\t\t} else {\n\t\t\t\tlike.TO = v.(uint64)\n\t\t\t}\n\t\t} else {\n\t\t\te = append(e, errors.New(\"The Data from the DB has no TO field set\"))\n\t\t\treturn nil, e\n\t\t}\n\t\treturn like, e\n\t}\n\t//Called everytime simpleg wants to convert struct of this linktype to data to be saved in the DB\n\tfl.Set = func(i interface{}, db *DB) (u map[KeyValueKey][]byte, e []error) {\n\t\tu = make(map[KeyValueKey][]byte)\n\t\te = make([]error, 0)\n\t\td, ok := i.(Link)\n\t\tif !ok {\n\t\t\te = append(e, errors.New(\"The Provided struct is not of type Link\"))\n\t\t\treturn nil, e\n\t\t}\n\t\tdb.RLock()\n\t\tdefer db.RUnlock()\n\t\tif d.FROM \u003e 0 {\n\t\t\tu[KeyValueKey{Main: \"FROM\"}], _ = db.FT[\"uint64\"].Set(d.FROM)\n\t\t} else {\n\t\t\te = append(e, errors.New(\"From Field not provided\"))\n\t\t}\n\t\tif d.TO \u003e 0 {\n\t\t\tu[KeyValueKey{Main: \"TO\"}], _ = db.FT[\"uint64\"].Set(d.TO)\n\t\t} else {\n\t\t\te = append(e, errors.New(\"TO Field not provided\"))\n\t\t}\n\t\treturn\n\t}\n\tfl.Validate = func(i interface{}, db *DB) (interface{}, []error) {\n\t\te := make([]error, 0)\n\t\treturn i, e\n\t}\n\tfl.Fields = make(map[string]FieldOptions)\n\treturn fl\n}\n\t//register linkType with DB\n\tdb.AddLinkType(GetLinkOptions())\n\n```\nNow that we can add linkTypes to the DB, it is time to move on to fieldTypes\n\n## FieldTypes\nFieldTypes in simpleg are abstract forms of individual properties of Objects and Links. They are responsible for \n-   Initializing values of the fields\n-   Converting values from their binary form to their actual form and vice varsa\n-   Comparing values of the field type\n-   Getting the comparing instruction for indexed fields\nSimpleg comes with 5 filedtypes and you can create as many as you want, to create your own fieledtype you have to implement the interface simpleg.FieldType, below is an example of uint64 that comes with simpleg\n```go\nimport (\n\t\"encoding/binary\"\n\t\"errors\"\n)\n\ntype FieldTypeUint64 struct {\n}\n//Get options for this fieldtype\nfunc (f *FieldTypeUint64) GetOption() map[string]string {\n\tm := make(map[string]string)\n\t//fieldType name\n\tm[\"Name\"] = \"uint64\"\n\t//wether to allow indexing of fields implementing this fieldType\n\tm[\"AllowIndexing\"] = \"1\"\n\treturn m\n}\n//Return a new Zero version of this fieldType\nfunc (f *FieldTypeUint64) New() interface{} {\n\tvar r uint64 = 0\n\treturn r\n}\n//Convert values of this filedType to an []byte for saving to DB\nfunc (f *FieldTypeUint64) Set(v interface{}) ([]byte, error) {\n\td, ok := v.(uint64)\n\tif !ok {\n\t\treturn nil, errors.New(\"Interface is not of type of uint64\")\n\t}\n\n\tbuf := make([]byte, binary.MaxVarintLen64)\n\tbinary.PutUvarint(buf, d)\n\treturn buf, nil\n}\n//Convert []byte to value of this fieldtype\nfunc (f *FieldTypeUint64) Get(v []byte) (interface{}, error) {\n\ti, err := binary.Uvarint(v)\n\treturn i, err\n}\n//Compare between two []byte of this fieldType\nfunc (f *FieldTypeUint64) Compare(typ string, a []byte, b []byte) (bool, error) {\n\tvar err error\n\tia, _ := binary.Uvarint(a)\n\tib, _ := binary.Uvarint(b)\n\n\tswitch typ {\n\tcase \"==\":\n\t\treturn (ia == ib), err\n\tcase \"!=\":\n\t\treturn (ia != ib), err\n\tcase \"\u003e\":\n\t\treturn (ia \u003e ib), err\n\tcase \"\u003e=\":\n\t\treturn (ia \u003e= ib), err\n\tcase \"\u003c\":\n\t\treturn (ia \u003c ib), err\n\tcase \"\u003c=\":\n\t\treturn (ia \u003c= ib), err\n\tdefault:\n\t\treturn false, errors.New(\"fieldtype uint64 does not support this comparison operator\")\n\t}\n\n}\n//Return strings for index comparison \nfunc (f *FieldTypeUint64) CompareIndexed(typ string, a interface{}) (string, string, error) {\n\tvar err error\n\tg, err := f.Set(a)\n\tif err != nil {\n\t\treturn \"\", \"\", err\n\t}\n\ts := string(g)\n\tswitch typ {\n\tcase \"==\":\n\t\treturn s, \"==\", err\n\tcase \"\u003e\":\n\t\treturn s, \"\u003e\", err\n\tcase \"\u003e=\":\n\t\treturn s, \"\u003e=\", err\n\tcase \"\u003c\":\n\t\treturn s, \"\u003c\", err\n\tdefault:\n\t\treturn \"\", \"\", errors.New(\"fieldtype uint64 does not support this comparison operator for indexed field\")\n\t}\n\n}\n//Register Fieldtype with DB\ndb.AddFieldType(simpleg.FieldTypeOptions{Name: \"uint64\", AllowIndexing: true}, \u0026FieldTypeUint64{})\n```\nSimpleg completely relies on fieldTypes to handle and compare fields and for this reason the fieldtypes are responsible for the types of comparison they allow. The fieldTypes are also responsible for for providing instruction on how indexing is applied, will talk more about that later. Listed below are the comparison operators of the inbuilt fieldtypes in simpleg.\n\n\n\n### FieldType bool: works with the golang bool variable type\n| Compare         | Indexed      | Description  |\n| ------------- |:-------------:| -----:|\n|  ==           |               | Checks if two varaibles are equal |\n|  !=           |               |   Checks if two varaibles are not equal |\n\n\n\n### FieldType date: works with the golang time.Time type\n| Compare         | Indexed      | Description  |\n| ------------- |:-------------:| -----:|\n|  ==           |       ==        | Checks if two varaibles are equal |\n|  !=           |               |   Checks if two varaibles are equal |\n|  \u003e           |        \u003e       |   Checks if one variable is greater than another |\n|  \u003e=           |       \u003e=       |   Checks if one variable is greater than or equal to another |\n|  \u003c           |        \u003c     |   Checks if one variable is less than another |\n|  \u003c=           |       \u003c=        |   Checks if one variable is less than or equal to another |\n\n\n### FieldType int64: works with the golang int64 type\n| Compare         | Indexed      | Description  |\n| ------------- |:-------------:| -----:|\n|  ==           |       ==        | Checks if two varaibles are equal |\n|  !=           |               |   Checks if two varaibles are equal |\n|  \u003e           |        \u003e       |   Checks if one variable is greater than another |\n|  \u003e=           |       \u003e=       |   Checks if one variable is greater than or equal to another |\n|  \u003c           |        \u003c     |   Checks if one variable is less than another |\n|  \u003c=           |       \u003c=        |   Checks if one variable is less than or equal to another |\n\n### FieldType string: works with the golang string type\n| Compare         | Indexed      | Description  |\n| ------------- |:-------------:| -----:|\n|  ==           |       \t    |   Checks if two varaibles are equal |\n|  !=           |               |   Checks if two varaibles are equal |\n|  contains     |               |   Checks if one string variable is contained in another |\n|  NoCaseEqual  |               |   Checks if two strings are equal with case insesitivity |\n|  HasSuffix    |               |   Checks if one string is a suffix of another |\n|  prefix       |    prefix     |   Checks if one string is a prefix of another |\n|  regex        |               |   Checks if strings in this field match provided regex epression |\n\n### FieldType uint64: works with the golang uint64 type\n| Compare         | Indexed      | Description  |\n| ------------- |:-------------:| -----:|\n|  ==           |       ==      | Checks if two varaibles are equal |\n|  !=           |               |   Checks if two varaibles are equal |\n|  \u003e            |        \u003e      |   Checks if one variable is greater than another |\n|  \u003e=           |       \u003e=      |   Checks if one variable is greater than or equal to another |\n|  \u003c            |        \u003c      |   Checks if one variable is less than another |\n|  \u003c=           |       \u003c=      |   Checks if one variable is less than or equal to another |\n\nWe have talked about configuration of fieldTypes, ObjectTypes and LinkTypes, we still have to talk about advanced fieldtypes but with what we  have right now we can use simpleg so we will talk about usage instead.\n\n# Using Simpleg\nSo to complete initialization of simpleg \n\n```go\n...\n\t//Register linkType with DB\n\tdb.AddLinkType(GetLinkOptions())\n\t//Register objectType with DB\n\tdb.AddObjectType(GetObjectOptions())\n\t//Start DB\n\tdb.Start()\n}\n```\n\n## Storing data in simpleg\nTo save objects to the DB we need to get an instance of the object and add data to it\n```go\n\t//Gets a new instance of objecttype Object, returned result is of type simpleg.GetterRet\n\tret := db.Get(\"object.new\", \"Object\")\n\t//errors not checked for simplicity\n\to, _ := ret.Data.(Object)\n\to.field1 = \"Awesome string\"\n\to.field2 = true\n```\nThis saves an instance of an object into the database. \nFirst parameter is the instruction in this case it is  \"save.object\"\nSecond parameter is the name of the objectType about to be saved\nThird parameter is the instance of an Object to be saved\n```go\n\tret2 := db.Set(\"save.object\", \"Object\", o)\n```\nThe function returns an instance of simpleg.SetterRet with the ID of the object saved and an arrays of errors if any. If the ID of the field is not set the DB creates a new instance and assigns the instance a new ID, this ID is then returned. IF the ID is provided the instance with the specified ID is updated in the DB. This is enough to save objects but most times we might just want to update a single field and using this will waste resources. To update an objects field we use the same function with a different instruction.\n```go\n\tret3 := db.Set(\"save.object.field\", \"Object\", ret2.ID, \"field1\", \"Updated string\")\n```\nTo save links into the DB we use the same function with a different instruction.\nThe second parameter is the LinkType name\nThe third parameter is an instance of the linkType about to be saved.\n```go\n\tret := db.Get(\"link.new\", \"Link\")\n\t//errors not checked for simplicity\n\tl, _ := ret.Data.(Link)\n\tl.FROM = uint64(1)\n\tl.TO = uint64(2)\n\tret3 := db.Set(\"save.link\", \"Link\", ret2.ID, l)\n```\nTake note, you have to provide a link with the 'TO' and 'FROM' set to ID of valid objects or else you get an error. If the link already exists it will be updated but if not it will be created. Also if the linktype is of the type 1 and there exists an opposite link, the opposite link will be updated instead. You can also save a link's field with the same function. \nThe third parameter is the 'FROM' field of the link\nThe fourth parameter is the 'TO' field of the link\nThe fifth field is the name of the field to be saved or updated \nThe sixth field is the value the field is updated with\n```go\n\tret3 := db.Set(\"save.link.field\", \"Link\", uint64(1), uint64(2) \"linkField\", \"Updated field value\")\n```\ndb.Set is goroutine safe and can be called from different goroutines at the same time. The function blocks until a result is returned.\n## Getting sigle single object/link in simpleg\nTo get data from simpleg you use the db.Get function. Like db.Set db.Get is goroutine safe and blocks until result is returned. You have already seen it's usage for geting a new link or object so we move to using it to retieve a single instance of an object.\nThe first parameter is the instruction\nThe second parameter is the object type name\nThe third is the uique ID of the object to be returned  \n```go\n\tret := db.Get(\"object.single\", \"Object\", uint64(2))\n\tobj, _ := ret.data.(Object)\n```\nGetting a single instance of a link is done with the same function.\nSecond parameter is the Link Type name \nThird parameter is the direction of the link. Link direction indicates wether the link requested is from field 'FROM' to field 'TO' with '-\u003e' or from Field 'TO' to field 'FROM' with '\u003c-', there is also a third direction '-' that indicates either of the previous links but the third is not supported by this function\nFouth parameter is the ID of the object the link is linking from\nFifth parameter is the ID of the object the link is linking to\n```go\nret := db.Get(\"link.single\", \"Link\", \"-\u003e\", uint64(1), uint64(2))\n\tlnk, _ := ret.data.(Link)\n```\n## Getting multiple object/link from simpleg\nTo get multiple objects/links in simpleg you need a nodequery and a query\n### Nodequery\nA nodequery is used to create instructions for retrieving an array of objects/links that meet a certain critaria based on field comparison. To initialize a nodequery\n```go\n\tn := simpleg.NodeQuery{}\n\t//name given to this nodequery so we can identify it when returning it in a Query\n\tn.Name(\"da\")\n\t//Indicate this nodequery will be used to retieve objects, the parameter in the objectType name\n\tn.Object(\"User\")\n\t//Used to give comparison instruction, \n\t//The first parameter is the field in the object to compare against\n\t//The second parameter is the type of comparison to be done\n\t//The third parameter is the value the comparison will be done against. for instance the below function checks if 'some prefix' is a 'prefix' of values in 'field1'\n\tn.Q(\"field1\", \"prefix\", \"some prefix\")\n\t//Ordering of the returned result,\n\t//First parameter is the field to order by\n\t//Second parameter determines how the ordering is done either assending 'asc' or decending 'dsc'\n\tn.Order(\"field1\", \"dsc\")\n\t//The number of results to return\n\tn.Limit(100)\n\t//The number of results to skip\n\tn.Skip(10)\n\tn.Q(\"field2\", \"==\", true)\n```\n\nThe first n.Q function call of a nodequery determines wether the query will use indexing or not, If the field provided is indexed indexing is used, if there are other indexed field referenced in the query they are ignored. Simpleg works this way for simplicity sake and also to minimize memory usage. Nodequery functions are also chainable so this is valid\n```go\n\tn.Name(\"da\").Object(\"Object\").Q(\"field1\", \"prefix\", \"yes\").Order(\"ID\", \"dsc\").Limit(100)\n```\n To execute the instructions of a nodequery we are going to be discussing another key feature of Simpleg, the Query\n### Query\nQuery in Simpleg is responsible for retieving data and 'db.Get' uses a Query internally for data retrieval. Query retrievies data by executing instructions it is provided. To understand how a Query works we need to walk through a complete example.\n```go\n\t//Initialize a Query\n\tq := db.Query()\n\t//Get a new nodequery\n\tn := simpleg.NodeQuery{}\n\t//initialize Nodequery\n\tn.Name(\"da\").Object(\"Object\").Q(\"field1\", \"prefix\", \"yes\").Order(\"ID\", \"dsc\").Limit(100)\n\t//To add an instruction to a Query \n\t//The first parameter is the instruction name \n\t//The second parameter is the instruction parameter\n\t//The function can take more than one pararameter infact the type is of ...interface{} so you can provide unending amount of parameters.\n\t//This calls the internal function called \"object\" which loads Objects from the database based on the instructions in the node query and stores the result in a variable called \"da\" (as specified in nodequery).  \n\tq.Do(\"object\", n)\n\t//This function returns the result of the Query.\n\t//The first parameter specifies the return type which can only be 'single', 'array', 'map' or 'skip' \n\t//if you use 'single' you will need to provide a third parameter which is the index of an array. \n\t//if you use 'map' you can provide multiple variable names and they will all be returned as a map of type map[string]interface{}\n\t//if you use 'array' the expected result will be of type []interface\n\t//if you use 'skip' then the return funtion is skipped and you have to provide another function that will work in its place, we will talk more about functions later \n\tretGet := q.Return(\"array\", \"da\")\n```\nThe returned result is of the type simpleg.GetterRet, retGet.Data is of type interface{} that holds the returned result and retGet.Errors holds the errors retured if any. To avoid exceptions, you have to check if any error is returned, if it is then retGet.Data will be invalid.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimmytune%2Fsimpleg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimmytune%2Fsimpleg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimmytune%2Fsimpleg/lists"}