{"id":14155087,"url":"https://github.com/gitrows/gitrows","last_synced_at":"2025-04-04T19:04:15.419Z","repository":{"id":40561970,"uuid":"258530844","full_name":"gitrows/gitrows","owner":"gitrows","description":"A lightweight module for using git as a database","archived":false,"fork":false,"pushed_at":"2024-04-05T16:28:38.000Z","size":874,"stargazers_count":360,"open_issues_count":21,"forks_count":19,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-28T18:11:33.168Z","etag":null,"topics":["browser","csv","database","github","gitlab","js","json","node"],"latest_commit_sha":null,"homepage":"https://gitrows.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gitrows.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-24T14:11:45.000Z","updated_at":"2025-03-25T14:55:03.000Z","dependencies_parsed_at":"2024-06-19T02:07:11.597Z","dependency_job_id":null,"html_url":"https://github.com/gitrows/gitrows","commit_stats":{"total_commits":160,"total_committers":8,"mean_commits":20.0,"dds":"0.17500000000000004","last_synced_commit":"05a8a66030ffaee41931d9d81571502c091a7a3e"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitrows%2Fgitrows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitrows%2Fgitrows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitrows%2Fgitrows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitrows%2Fgitrows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gitrows","download_url":"https://codeload.github.com/gitrows/gitrows/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247234920,"owners_count":20905854,"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":["browser","csv","database","github","gitlab","js","json","node"],"created_at":"2024-08-17T08:01:49.154Z","updated_at":"2025-04-04T19:04:15.395Z","avatar_url":"https://github.com/gitrows.png","language":"JavaScript","readme":"[![@latest](https://img.shields.io/npm/v/gitrows.svg)](https://www.npmjs.com/package/gitrows)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgitrows%2Fgitrows.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgitrows%2Fgitrows?ref=badge_shield)\n\n# Getting Started\n\n## What is GitRows?\n\nGitRows makes it easy to use and store data in GitHub and GitLab repos. You can read data stored in `.csv` and `.json` files from **all public repos** and read, create, update and delete data in **public or private repos** that you have access to, all with the benefit of version control. GitRows also supports basic `.yaml` file operations, mainly for reading and writing [OpenAPI documents](http://spec.openapis.org/oas/v3.0.3).\n\nGitRows works with `node` and in any modern `browser`. Alternatively [learn more](https://gitrows.com/docs/api/getting-started) how to use GitRows' free API to integrate data into your websites/apps.\n\n\n## Installation\n\nAs a package for `node` use npm:\n\n```shell\nnpm i gitrows\n```\n\nYou can use GitRows in the `browser` by including `gitrows.js` or `gitrows.min.js` from the `./dist` folder or using unpkg:\n\n```html\n\u003cscript src=\"https://unpkg.com/gitrows@latest/dist/gitrows.min.js\"\u003e\u003c/script\u003e\n```\n\n## Usage\n\n### Basic\n\n```js\n// If you use GitRows as a module:\nconst Gitrows = require('gitrows');\n\n// Init the GitRows client, you can provide options at this point, later or just run on the defaults\nconst gitrows = new Gitrows();\n\nlet path = '@github/gitrows/data/iris.json';\n\ngitrows.get(path)\n .then( (data) =\u003e {\n  //handle (Array/Object)data\n  console.log(data);\n })\n .catch( (error) =\u003e {\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\n# Options\n\nYou can configure various options to streamline your workflow with GitRows.\n\n## options(*object* params)\nYou can use the `options()` method to set or get the options of the GitRows instance. The available options and their default values are:\n\n```js\n{\n  server: undefined,\n  ns: 'github',\n  owner: undefined,\n  repo: undefined,\n  branch: 'HEAD',\n  path: undefined,\n  user: undefined,\n  token: undefined,\n  message: 'GitRows API Post (https://gitrows.com)',\n  author: { name: 'GitRows', email: 'api@gitrows.com' },\n  csv: { delimiter: ',' },\n  type: undefined,\n  columns: undefined,\n  strict: false,\n  default: null\n}\n```\n## Repo related options\n\nThe following options are data file repository related and may be overwritten by GitRows while parsing an url or API call:\n\n* `server`\tused in connection with `ns:'gitlab'`: You can use GitLab installations on other webservers than gitlab by providing its url, e.g. `gitlab.example.com`\n* `ns`\teither `github` or `gitlab`\n* `owner`\trepository owner\n* `repo`\trepository name\n* `branch` select another than `HEAD`\n* `path`\tdirectory and/or file name with extension\n\nIf you want to alter the contents of the data files you need to provide a username and access token for the selected namespace:\n\n* `user`\ta GitHub or GitLab username (may be omitted for GitLab)\n* `token`\ta GitHub or GitLab token\n\nThe commits are done with a standard message and authored by GitRows by default. Change if needed. This is useful for different GitRows instances committing to the same repo:\n\n* `message`\tcommit message\n* `author`\tan object with the properties `name` and `email` to identify the committer\n\n## Data format related options\n\nYou can set these output options:\n\n* `csv`\tthe option accepts only an object with the property `delimiter`, others might be added in future versions\n* `type`\teither `json` or `csv` - in most cases there is no need to set this as GitRows determines the type by the data file extension and by parsing its content, but might be useful for debugging purposes\n* `columns` either determined by the data file entries or set as an `Array` with the column names - only applied if `strict` is `true`\n* `strict` if set to `true` GitRows will enforce the column scheme found in the data file or set by the columns option for all added data entries\n* `default` the default value used in strict mode for amending entries with missing column data\n\n# Working with Data\n\nGitRows implements a full CRUD interface to you data so you can create, read, update, and delete information in your repository data files.\n\n## get(path[, *object* filter, *string* method = 'fetch' | 'pull')\n\u003e requires `token` for **private repos only**\n\nTo read the complete data set from a `.json` or `.csv` file you pass the file path to the `.get()` method, which has the basic structure of\n\n```\n@namespace/owner/repository:branch/directory/file(.json|.csv)\n```\n\nAlternatively you can copy the file url form your browser and pass this instead. Read more about the path structure and how to troubleshoot in the [Path section](#path) of GitRows' documentation.\n\n```js\nconst path = '@github/gitrows/data/iris.json';\n\ngitrows.get(path)\n .then( (data) =\u003e {\n  //handle (Array/Object)data\n  console.log(data);\n })\n .catch( (error) =\u003e {\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nThe `get` method accepts as a second argument a filter object which can be used with filtering and aggregation operators. Learn more about the possibilities in the [Filters section](#filters).\n\n**For reading a file from a private repo you must set your username and token (see put() for more details). Please note that its impossible to decide from the returned status code if the file is private on GitHub or not, as it will always be 404 by GitHub's policy.**\n\nAs a third parameter you can set the mechanism for retrieving data from the repository server. It defaults to `fetch` which is sufficent for most use cases and avoids rate limit issues. However, as `fetch` uses the html `raw` endpoints, e.g. `https://https://raw.githubusercontent.com/`, this may lead to a caching latency of a few seconds. If your use case requires faster access times, try `pull` instead which queries the GitHub or GitLab content APIs.\n\n## put(path, *object* data)\n\u003e requires `token`\n\nFor adding or updating data (and deleting or creating new data files) you must set your username and an OAuth (personal access) token. Unless you feel particularly adventurous you should **never** do this in a production environment like a website. You can generate a new one in your [GitHub Developer Settings](https://github.com/settings/tokens):\n\n```js\nconst options = {\n username:\"yourUsername\",\n token:\"yourSecretToken\"\n};\n\nconst data = [\n {\n  id:\"0003\",\n  title:\"A New Title\",\n  content:\"Some new content\"\n },\n {\n  id:\"0004\",\n  title:\"Another New Title\"\n }\n];\n\ngitrows.options(options);\n\ngitrows.put(path,data)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:200,description='OK'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nGitRows accepts the data as an `Array` of `Objects` if you want to add one ore more entries (rows) or a single `Object` for appending one entry (row).\n\nTo if you want to enforce consistent data structures set `options({strict:true})`. If true, GitRows will check the columns (keys) used in your datafile and add the missing keys with the default value `NULL` or any other value you set with `options({default:''})`. You can also set the columns as an option with `options({columns:[]})`.\n\n## update(path, *object* data[, *object* filter])\n\u003e requires `token`\n\nTo update an entry from data you must provide it's `id`, which may either be\n\n* the entry's `id property`, if the data consists of an `Array` of `Objects`, e.g. `[{id:'0001', foo:'bar'}]`\n* the `property name`, if the data consists of a single `Object`\n\n**or**\n\na valid filter expession to update more than one entries and an entry of unknown id.\n\n```js\nconst filter = {id:'0001'};\n\nconst data = {\n\tfoo: \"bar\"\n}\n\ngitrows.update(path,data,filter)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:202,description='Accepted'} if successful or (Object){code:304,description='Not modified'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nIf you use the API style you may also append the `id` to the path and omit the second argument:\n\n```\n@namespace/owner/repository:branch/directory/file(.json|.csv)/id\n```\n\n## replace(path, *object* data)\n\u003e requires `token`\n\nTo update a data set that is not representing tabular data but a dictionary, or to swap a complete set, use the replace method\n\n```js\n\nconst data = {\n\tfoo: \"bar\"\n}\n\ngitrows.replace(path,data)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:202,description='Accepted'} if successful or (Object){code:304,description='Not modified'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\n## delete(path[, *object* filter])\n\u003e requires `token`\n\nTo delete an entry from data you must provide it's `id`, which may either be\n\n* the entry's `id property`, if the data consists of an `Array` of `Objects`, e.g. `[{id:'0001', foo:'bar'}]`\n* the `property name`, if the data consists of a single `Object`\n\n**or**\n\na valid filter expession to delete more than one entries.\n\n```js\nconst filter = {id:'0001'};\n\ngitrows.delete(path,filter)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:204,description='No content'} if successful or (Object){code:304,description='Not modified'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nIf you use the API style you may also append the `id` to the path and omit the second argument:\n\n```\n@namespace/owner/repository:branch/directory/file(.json|.csv)/id\n```\n\n## types(path[, *object* {'$limit':'number'}])\n\nReturns the columns and their data types which can be one of `string`, `number`, `integer`, `array` or `object`. The data types are detetced from the data set values. To speed detection up you can optionally pass a filter argument with the number of rows to be processed. If mixed values are found within a column, the following take precedence: `string` over `number` over `integer`.\n\n```js\nconst limit = {'$limit':'10'};\n\ngitrows.types(path,limit)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){columnName:'type'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\n# Working with Files\n\n## create(path[ ,data])\n\u003e requires `token`\n\nTo create a new data file programmatically you can use the the `create()` method, which optionally accepts initial data, that will be added upon creation:\n\n```js\nlet newFilePath = '@github/gitrows/data/another.json';\n\ngitrows.create(newFilePath)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:201,description='Created'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\n## drop(path)\n\u003e requires `token`\n\nTo delete a data file programmatically you can use the the `drop()` method:\n\n```js\ngitrows.drop(path)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){code:200,description='OK'}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\n# Path\n\nTo select the data file you can either paste the GitHub/GitLab file url from the browser, e.g.\n\n```url\nhttps://github.com/gitrows/data/blob/master/iris.json\n```\n\nor use the GitRows API style:\n\n```\n@namespace/owner/repository:branch/directory/file(.json|.csv|.yaml)\n```\n\n`@namespace` and `:branch` are optional and default to `github` and `master`, if you want to access a GitLab repository, use the `gitlab` namespace.\n\n\n## Which notation to use?\n\nAlthough it's easier for a simple query to just paste the url I strongly encourage the use of the API style. After you have initially set the namespace, owner, repository and/or branch either by calling a method with a path or by setting them with the `options()` method you can make subsequent calls by just providing `directory/file`:\n\n```\n./directory/file(.json|.csv|.yaml)\n```\n\nThe API style got it's name from its use with the free GitRows API tool which allows you to query all public repos with a consistent api call:\n\n```\nhttps://api.gitrows.com/@namespace/owner/repository:branch/path/file(.json|.csv|.yaml)\n```\n\nGive it a try with our sample database from the basic use example: `https://api.gitrows.com/@github/gitrows/data/iris.json` If you are unsure about how a file url is translated into API style, you can use GitRow's [Linter and Converter Tool](https://gitrows.com/linter) to check and translate repo and API paths respectively.\n\n## test(path [ ,constraint])\n\nTo check the path (GitRows API or url) and your permissions, GitRows provides a test method. Please note that the `admin|push|pull` permissions will only be visible if you have provided your `token`.\n\n```js\nlet path='@github/gitrows/data/countries.json'\n\ngitrows.test(path)\n .then((response)=\u003e{\n  //handle response, which has the format (Object){...resul}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nThis example would have a response like\n\n```\n{\n  valid: true,\n  ns: 'github',\n  owner: 'gitrows',\n  repo: 'data',\n  branch: undefined,\n  path: 'countries.json',\n  type: 'json',\n  resource: undefined,\n  fragment: false,\n  private: false,\n  admin: false,\n  push: false,\n  pull: true,\n  level: 'file',\n  code: 200,\n  message: { description: 'OK' }\n}\n```\n\nYou can add optional constraints, e.g. to validate push access to the file:\n\n```js\ngitrows.test(path,{push:true})\n .then((response)=\u003e{\n  //handle response, which has the format (Object){...resul}\n })\n .catch((error)=\u003e{\n  //handle error, which has the format (Object){code:http_status_code,description='http_status_description'}\n });\n```\n\nwhich yields:\n\n```\n{\n  valid: false,\n  ns: 'github',\n  owner: 'gitrows',\n  repo: 'data',\n  branch: undefined,\n  path: 'countries.json',\n  type: 'json',\n  resource: undefined,\n  fragment: false,\n  private: false,\n  admin: false,\n  push: false,\n  pull: true,\n  level: 'file',\n  code: 400,\n  message: { description: 'Constraint Violation - push must not be false' }\n}\n```\n\nThe test method also accepts fragments:\n\n- a repo `@github/gitrows/data`\n- a directory `@github/gitrows/data/dir`\n\n# Filters\n\n## Filtering results\n\nFor simple matching if a value is present (e.g. an id) supply the field name and required value. You can also use a number of operators in the value field for comparison:\n\n* `not:`\tequals not\n* `lt:`\t\tless than\n* `lte:`\tless than or equal\n* `gt:`\t\tgreater than\n* `gte:`\tgreater than or equal\n* `^:`\t\tstarts with, alias: `starts:`\n* `*:`\t\tcontains text, alias: `contains:`\n* `$:`\t\tends with, alias: `ends:`\n\nThe string comparison is case insensitive.\n\n```js\ngitrows.get(path,{'some_numerical_field':'gt:10'});\n```\n\nYou can also supply an array of expressions per field name. All expressions will be handled as logical `AND`. This is especially useful for selecting ranges:\n\n```js\ngitrows.get(path,{'some_numerical_field':['gt:10','lt:20']});\n```\n\n## Aggregate Functions\n\nInstead of retrieving data entries you can use aggregate functions that are prefixed with the dollar sign `$` and followed by the column name:\n\n* `'$count':'*'`\tcounts the records in the data set\n* `'$avg':'columnName'`\tcalculates the average of all numeric values in `columnName`\n* `'$sum':'columnName'`\tcalculates the sum of all numeric values in `columnName`\n* `'$min':'columnName'`\treturns the smallest of all numeric values in `columnName`\n* `'$max':'columnName'`\treturns the largest of all numeric values in `columnName`\n\nAll filters are applied before the aggregation, so for example to get the average of all values larger than a certain number you can use `{value:'lt:number','$avg':value}`.\n\n## Selecting Results\n\nTo specify the returned columns you can use `$select` with a comma delimited list of the column names you want to retrieve:\n\n```js\ngitrows.get(path,{'$select':'col1,col3,col5'});\n```\n\n## Sorting Results\n\nYou can order the result with `$order:'columnName:asc` or `$order:'columnName:desc` respectively and `$limit` the entries returned:\n\n```js\ngitrows.get(path,{'$order':'col1:asc','$limit':'0,5'});\n```\n\nGitRows' $limit behaves like MySQL's equivalent: If you supply one number, this will be maximum number of rows returned starting from the entry at index 0, if you give two comma delimited numbers, the first will be the offset and the second the number of rows.\n\n# Contributing to GitRows\nTo contribute, follow these steps:\n\n1. Fork this repository.\n2. Create a branch: `git checkout -b \u003cbranch_name\u003e`.\n3. Make your changes and commit them: `git commit -m '\u003ccommit_message\u003e'`\n4. Push to the original branch: `git push origin \u003cproject_name\u003e/\u003clocation\u003e`\n5. Create the pull request.\n\nAlternatively see the GitHub documentation on [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request).\n\n# Contact\n\nYou can reach me at \u003cnicolas@gitrows.com\u003e\n\n# License\n\nCopyright © 2020, [Nicolas Zimmer](https://github.com/nicolaszimmer).\n[MIT](LICENSE)\n\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgitrows%2Fgitrows.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgitrows%2Fgitrows?ref=badge_large)\n","funding_links":[],"categories":["JavaScript","browser"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitrows%2Fgitrows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgitrows%2Fgitrows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitrows%2Fgitrows/lists"}