{"id":19370034,"url":"https://github.com/bustle/nemesis-db","last_synced_at":"2025-04-23T15:31:48.205Z","repository":{"id":33882648,"uuid":"142727055","full_name":"bustle/nemesis-db","owner":"bustle","description":"An Open Source Port of the Gradius API Storage Engine","archived":false,"fork":false,"pushed_at":"2022-12-07T21:55:19.000Z","size":355,"stargazers_count":22,"open_issues_count":10,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-19T05:24:49.537Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bustle.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":"2018-07-29T03:16:59.000Z","updated_at":"2023-09-08T01:40:31.000Z","dependencies_parsed_at":"2023-01-15T03:08:38.016Z","dependency_job_id":null,"html_url":"https://github.com/bustle/nemesis-db","commit_stats":null,"previous_names":["reconbot/nemesis-db"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bustle%2Fnemesis-db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bustle%2Fnemesis-db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bustle%2Fnemesis-db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bustle%2Fnemesis-db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bustle","download_url":"https://codeload.github.com/bustle/nemesis-db/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250460471,"owners_count":21434253,"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":[],"created_at":"2024-11-10T08:14:02.526Z","updated_at":"2025-04-23T15:31:47.928Z","avatar_url":"https://github.com/bustle.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Nemesis DB\n[![Build Status](https://travis-ci.org/reconbot/nemesis-db.svg?branch=master)](https://travis-ci.org/reconbot/nemesis-db)\n[![codecov](https://codecov.io/gh/reconbot/nemesis-db/branch/master/graph/badge.svg)](https://codecov.io/gh/reconbot/nemesis-db)\n\n\n[Nemesis DB](https://www.arcade-museum.com/game_detail.php?game_id=8842) is an open source port of Bustle's Gradius graph database.\n\n![](nemesis.jpg)\n\n\n## Intro\n\nThis is a simple adjacency graph database with only a few features. It has been designed for very fast reads. While it handles writes with ease whenever a tradeoff favors reads, that tradeoff will be taken.\n\n## Features\n- [x] 32 bit GUID\n- [x] Schemaless Nodes\n- [x] Weighted Edges\n- [x] Compression\n\n## Future Features\n- Node Schemas, types and Interfaces\n- filtering edges based upon weight\n- Deleting\n- Edge Schemas\n- Field Validations\n- Edge Validations\n- Edge scanning\n- Node scanning\n- Named Edges\n- Field Indexing\n- Binary packing\n\n## Examples\n\n```js\nimport { Graph } from 'nememis-db'\n\nconst graph = new Graph('redis://localhost/1')\n\nconst book = await graph.createNode({ title: 'foo', pages: 24 })\nassert.deepEqual(book, { id: 1, title: 'foo', pages: 24 })\n\n// update the data of an existing node\nconst updatedBook = await graph.updateNode({ id: book.id, title: 'bar' })\nassert.deepEqual(updatedBook, { id: 1, title: 'bar', pages: 24 })\n\n// replace the data of an existing node\nconst replacedBook = await graph.putNode({ id: book.id, title: 'foo' })\nassert.deepEqual(replacedBook, { id: 1, title: 'foo' })\n\nconst author = await graph.createNode({ name: 'james' })\nassert.deepEqual(author, { id: 2, name: 'james' })\n\n// connect the book and it's author\nconst edge = await graph.createEdge({ subject: book.id, predicate: 'BookHasAuthor', object: author.id })\nassert.deepEqual(edge, { subject: 1, predicate: 'BookHasAuthor', object: 2, weight: 0 })\n\nconst authors = await graph.findEdges({ subject: book.id, predicate: 'BookHasAuthor' })\nassert.deepEqual(authors, [{ subject: 1, predicate: 'BookHasAuthor', object: 2, weight: 0 }])\nconst object = await graph.findNode(authors[0].object)\nassert.deepEqual(object, { id: 2, name: 'james' })\n\n// Get an async iterator of all the nodes\nfor await (node of graph.allNodes()) {\n  console.log(node)\n}\n// { id: 1, title: 'foo' }\n// { id: 2, name: 'james' }\n\n// use streaming-iterables to make an array of the async iterator\nconst allNodes = await collect(graph.allNodes())\nassert.deepEqual(allNodes, [{ id: 1, title: 'foo' }, { id: 2, name: 'james' }])\n```\n\n## API Type Defs\n\n```ts\nexport declare class Graph {\n    readonly config: GraphConfig;\n    readonly messagePack: messagePack.MessagePack;\n    readonly redis: Redis.Redis;\n    constructor(redisUrl: string, config?: GraphConfigInput);\n    allNodes({ batchSize }?: NodeScanOptions): AsyncIterableIterator\u003cNode\u003e;\n    createEdge({ subject, predicate, object, weight }: EdgeInput): Promise\u003cEdge\u003e;\n    createNode(attributes: any): Promise\u003cNode\u003e;\n    disconnect(): void;\n    findEdges(edge: SubjectEdgeSearch | ObjectEdgeSearch): Promise\u003cReadonlyArray\u003cEdge\u003e\u003e;\n    findNode(id: number): Promise\u003cNode | null\u003e;\n    nodeExists(id: number): Promise\u003cboolean\u003e;\n    putNode(node: Node): Promise\u003cNode\u003e;\n    updateNode(node: Node): Promise\u003cNode\u003e;\n    private evalCommands;\n    private evalCreateEdge;\n    private getNextId;\n    private nodeKey;\n}\n\nexport interface Node {\n    readonly id: number;\n    readonly [key: string]: any;\n}\nexport interface GraphConfigInput {\n    readonly compressors?: ReadonlyArray\u003cCompressor\u003e\n    readonly edgePrefix?: string;\n    readonly guidKey?: string;\n    readonly nodeIndexKey?: string;\n    readonly nodeKeyPrefix?: string;\n}\nexport interface GraphConfig {\n    readonly edgePrefix: string;\n    readonly guidKey: string;\n    readonly nodeIndexKey: string;\n    readonly nodeKeyPrefix: string;\n}\nexport interface EdgeInput {\n    readonly object: number;\n    readonly predicate: string;\n    readonly subject: number;\n    readonly weight?: number;\n}\nexport interface Edge {\n    readonly object: number;\n    readonly predicate: string;\n    readonly subject: number;\n    readonly weight: number;\n}\nexport interface SubjectEdgeSearch {\n    readonly limit?: number;\n    readonly offset?: number;\n    readonly predicate: string;\n    readonly subject: number;\n}\nexport interface ObjectEdgeSearch {\n    readonly limit?: number;\n    readonly object: number;\n    readonly offset?: number;\n    readonly predicate: string;\n}\nexport interface NodeScanOptions {\n    readonly batchSize?: number;\n}\nexport interface Compressor {\n    readonly compress: (Buffer: any) =\u003e Buffer | Promise\u003cBuffer\u003e;\n    readonly decompress: (Buffer: any) =\u003e Buffer | Promise\u003cBuffer\u003e;\n    readonly name: string;\n}\n```\n\n## Developing\n\nTests use your local redis db 2 by default and are destructive. To use another DB submit a patch to make this configurable.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbustle%2Fnemesis-db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbustle%2Fnemesis-db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbustle%2Fnemesis-db/lists"}