{"id":13414047,"url":"https://github.com/FreeLeh/GoFreeDB","last_synced_at":"2025-03-14T20:31:03.815Z","repository":{"id":41864688,"uuid":"508667510","full_name":"FreeLeh/GoFreeDB","owner":"FreeLeh","description":"GoFreeDB is a Golang library that provides common and simple database abstractions on top of Google Sheets.","archived":false,"fork":false,"pushed_at":"2023-11-15T23:31:44.000Z","size":292,"stargazers_count":34,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-07-31T20:53:20.348Z","etag":null,"topics":["database","golang","google-sheets-api","google-sheets-api-v4","key-value-store","orm","row-store"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/FreeLeh/GoFreeDB","language":"Go","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/FreeLeh.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":"2022-06-29T11:42:14.000Z","updated_at":"2024-06-07T01:23:30.000Z","dependencies_parsed_at":"2024-06-19T22:53:35.715Z","dependency_job_id":"25d282d3-aed7-456f-9234-c036e9cca466","html_url":"https://github.com/FreeLeh/GoFreeDB","commit_stats":{"total_commits":40,"total_committers":4,"mean_commits":10.0,"dds":"0.19999999999999996","last_synced_commit":"2ba8e8cbed8f7ffe4e00fbc7e9617867abd1d8e1"},"previous_names":["freeleh/gofreeleh"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreeLeh%2FGoFreeDB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreeLeh%2FGoFreeDB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreeLeh%2FGoFreeDB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FreeLeh%2FGoFreeDB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FreeLeh","download_url":"https://codeload.github.com/FreeLeh/GoFreeDB/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243642080,"owners_count":20323954,"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":["database","golang","google-sheets-api","google-sheets-api-v4","key-value-store","orm","row-store"],"created_at":"2024-07-30T20:01:56.178Z","updated_at":"2025-03-14T20:31:03.807Z","avatar_url":"https://github.com/FreeLeh.png","language":"Go","readme":"# GoFreeDB\n\u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n\t\u003cpicture\u003e\n\t\t\u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/img/logo_dark.png\"\u003e\n\t\t\u003cimg width=200 src=\"docs/img/logo_light.png\"\u003e\n\t\u003c/picture\u003e\n\t\u003ch3\u003e\u003ci\u003eShip Faster with Google Sheets as a Database!\u003c/i\u003e\u003c/h3\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003ccode\u003eGoFreeDB\u003c/code\u003e is a Golang library that provides common and simple database abstractions on top of Google Sheets.\n\u003c/p\u003e\n\n\u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n  ![Unit Test](https://github.com/FreeLeh/GoFreeDB/actions/workflows/unit_test.yml/badge.svg)\n  ![Integration Test](https://github.com/FreeLeh/GoFreeDB/actions/workflows/full_test.yml/badge.svg)\n![Coverage](https://img.shields.io/badge/Coverage-82.8%25-brightgreen)\n  [![Go Report Card](https://goreportcard.com/badge/github.com/FreeLeh/GoFreeDB)](https://goreportcard.com/report/github.com/FreeLeh/GoFreeDB)\n  [![Go Reference](https://pkg.go.dev/badge/github.com/FreeLeh/GoFreeDB.svg)](https://pkg.go.dev/github.com/FreeLeh/GoFreeDB)\n\n\u003c/div\u003e\n\n## Features\n\n1. Provide a straightforward **key-value** and **row based database** interfaces on top of Google Sheets.\n2. Serve your data **without any server setup** (by leveraging Google Sheets infrastructure).\n3. Support **flexible enough query language** to perform various data queries.\n4. **Manually manipulate data** via the familiar Google Sheets UI (no admin page required).\n\n\u003e For more details, please read [our analysis](https://github.com/FreeLeh/docs/blob/main/freedb/alternatives.md#why-should-you-choose-freedb)\n\u003e on other alternatives and how it compares with `FreeDB`.\n\n## Table of Contents\n\n* [Protocols](#protocols)\n* [Getting Started](#getting-started)\n  * [Installation](#installation)\n  * [Pre-requisites](#pre-requisites)\n* [Row Store](#row-store)\n  * [Querying Rows](#querying-rows)\n  * [Counting Rows](#counting-rows)\n  * [Inserting Rows](#inserting-rows)\n  * [Updating Rows](#updating-rows)\n  * [Deleting Rows](#deleting-rows)\n  * [Struct Field to Column Mapping](#struct-field-to-column-mapping)\n* [KV Store](#kv-store)\n  * [Get Value](#get-value)\n  * [Set Key](#set-key)\n  * [Delete Key](#delete-key)\n  * [Supported Modes](#supported-modes)\n* [KV Store V2](#kv-store-v2)\n  * [Get Value](#get-value-v2)\n  * [Set Key](#set-key-v2)\n  * [Delete Key](#delete-key-v2)\n  * [Supported Modes](#supported-modes-v2)\n\n## Protocols\n\nClients are strongly encouraged to read through the **[protocols document](https://github.com/FreeLeh/docs/blob/main/freedb/protocols.md)** to see how things work\nunder the hood and **the limitations**.\n\n## Getting Started\n\n### Installation\n\n```\ngo get github.com/FreeLeh/GoFreeDB\n```\n\n### Pre-requisites\n\n1. Obtain a Google [OAuth2](https://github.com/FreeLeh/docs/blob/main/google/authentication.md#oauth2-flow) or [Service Account](https://github.com/FreeLeh/docs/blob/main/google/authentication.md#service-account-flow) credentials.\n2. Prepare a Google Sheets spreadsheet where the data will be stored.\n\n## Row Store\n\nLet's assume each row in the table is represented by the `Person` struct.\n\n```go\ntype Person struct {\n\tName string `db:\"name\"`\n\tAge  int    `db:\"age\"`\n}\n```\n\nPlease read the [struct field to column mapping](#struct-field-to-column-mapping) section\nto understand the purpose of the `db` struct field tag.\n\n```go\nimport (\n\t\"github.com/FreeLeh/GoFreeDB\"\n\t\"github.com/FreeLeh/GoFreeDB/google/auth\"\n)\n\n// If using Google Service Account.\nauth, err := auth.NewServiceFromFile(\n\t\"\u003cpath_to_service_account_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.ServiceConfig{},\n)\n\n// If using Google OAuth2 Flow.\nauth, err := auth.NewOAuth2FromFile(\n\t\"\u003cpath_to_client_secret_json\u003e\", \n\t\"\u003cpath_to_cached_credentials_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.OAuth2Config{},\n)\n\nstore := freedb.NewGoogleSheetRowStore(\n\tauth, \n\t\"\u003cspreadsheet_id\u003e\", \n\t\"\u003csheet_name\u003e\", \n\tfreedb.GoogleSheetRowStoreConfig{Columns: []string{\"name\", \"age\"}},\n)\ndefer store.Close(context.Background())\n```\n\n### Querying Rows\n\n```go\n// Output variable\nvar output []Person\n\n// Select all columns for all rows\nerr := store.\n\tSelect(\u0026output).\n\tExec(context.Background())\n\n// Select a few columns for all rows (non-selected struct fields will have default value)\nerr := store.\n\tSelect(\u0026output, \"name\").\n\tExec(context.Background())\n\n// Select rows with conditions\nerr := store.\n\tSelect(\u0026output).\n\tWhere(\"name = ? OR age \u003e= ?\", \"freedb\", 10).\n\tExec(context.Background())\n\n// Select rows with sorting/order by\nordering := []freedb.ColumnOrderBy{\n\t{Column: \"name\", OrderBy: freedb.OrderByAsc},\n\t{Column: \"age\", OrderBy: freedb.OrderByDesc},\n}\nerr := store.\n\tSelect(\u0026output).\n\tOrderBy(ordering).\n\tExec(context.Background())\n\n// Select rows with offset and limit\nerr := store.\n\tSelect(\u0026output).\n\tOffset(10).\n\tLimit(20).\n\tExec(context.Background())\n```\n\n### Counting Rows\n\n```go\n// Count all rows\ncount, err := store.\n\tCount().\n\tExec(context.Background())\n\n// Count rows with conditions\ncount, err := store.\n\tCount().\n\tWhere(\"name = ? OR age \u003e= ?\", \"freedb\", 10).\n\tExec(context.Background())\n```\n\n### Inserting Rows\n\n```go\nerr := store.Insert(\n\tPerson{Name: \"no_pointer\", Age: 10}, \n\t\u0026Person{Name: \"with_pointer\", Age: 20},\n).Exec(context.Background())\n```\n\n### Updating Rows\n\n```go\ncolToUpdate := make(map[string]interface{})\ncolToUpdate[\"name\"] = \"new_name\"\ncolToUpdate[\"age\"] = 12\n\n// Update all rows\nerr := store.\n\tUpdate(colToUpdate).\n\tExec(context.Background())\n\n// Update rows with conditions\nerr := store.\n\tUpdate(colToUpdate).\n\tWhere(\"name = ? OR age \u003e= ?\", \"freedb\", 10).\n\tExec(context.Background())\n```\n\n### Deleting Rows\n\n```go\n// Delete all rows\nerr := store.\n\tDelete().\n\tExec(context.Background())\n\n// Delete rows with conditions\nerr := store.\n\tDelete().\n\tWhere(\"name = ? OR age \u003e= ?\", \"freedb\", 10).\n\tExec(context.Background())\n```\n\n### Struct Field to Column Mapping\n\nThe struct field tag `db` can be used for defining the mapping between the struct field and the column name.\nThis works just like the `json` tag from [`encoding/json`](https://pkg.go.dev/encoding/json).\n\nWithout `db` tag, the library will use the field name directly (case-sensitive).\n\n```go\n// This will map to the exact column name of \"Name\" and \"Age\".\ntype NoTagPerson struct {\n\tName string\n\tAge  int\n}\n\n// This will map to the exact column name of \"name\" and \"age\" \ntype WithTagPerson struct {\n\tName string  `db:\"name\"`\n\tAge  int     `db:\"age\"`\n}\n```\n\n## KV Store\n\n\u003e Please use `KV Store V2` as much as possible, especially if you are creating a new storage.\n\n```go\nimport (\n\t\"github.com/FreeLeh/GoFreeDB\"\n\t\"github.com/FreeLeh/GoFreeDB/google/auth\"\n)\n\n// If using Google Service Account.\nauth, err := auth.NewServiceFromFile(\n\t\"\u003cpath_to_service_account_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.ServiceConfig{},\n)\n\n// If using Google OAuth2 Flow.\nauth, err := auth.NewOAuth2FromFile(\n\t\"\u003cpath_to_client_secret_json\u003e\", \n\t\"\u003cpath_to_cached_credentials_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.OAuth2Config{},\n)\n\nkv := freedb.NewGoogleSheetKVStore(\n\tauth, \n\t\"\u003cspreadsheet_id\u003e\", \n\t\"\u003csheet_name\u003e\", \n\tfreedb.GoogleSheetKVStoreConfig{Mode: freedb.KVSetModeAppendOnly},\n)\ndefer kv.Close(context.Background())\n```\n\n### Get Value\n\nIf the key is not found, `freedb.ErrKeyNotFound` will be returned.\n\n```go\nvalue, err := kv.Get(context.Background(), \"k1\")\n```\n\n### Set Key\n\n```go\nerr := kv.Set(context.Background(), \"k1\", []byte(\"some_value\"))\n```\n\n### Delete Key\n\n```go\nerr := kv.Delete(context.Background(), \"k1\")\n```\n\n### Supported Modes\n\n\u003e For more details on how the two modes are different, please read the [protocol document](https://github.com/FreeLeh/docs/blob/main/freedb/protocols.md).\n\nThere are 2 different modes supported:\n\n1. Default mode.\n2. Append only mode.\n\n```go\n// Default mode\nkv := freedb.NewGoogleSheetKVStore(\n\tauth,\n\t\"\u003cspreadsheet_id\u003e\",\n\t\"\u003csheet_name\u003e\",\n\tfreedb.GoogleSheetKVStoreConfig{Mode: freedb.KVModeDefault},\n)\n\n// Append only mode\nkv := freedb.NewGoogleSheetKVStore(\n\tauth,\n\t\"\u003cspreadsheet_id\u003e\",\n\t\"\u003csheet_name\u003e\",\n\tfreedb.GoogleSheetKVStoreConfig{Mode: freedb.KVModeAppendOnly},\n)\n```\n\n## KV Store V2\n\nThe KV Store V2 is implemented internally using the row store.\n\n\u003e The original `KV Store` was created using more complicated formulas, making it less maintainable.\n\u003e You can still use the original `KV Store` implementation, but we strongly suggest using this new `KV Store V2`.\n\nYou cannot use an existing sheet based on `KV Store` with `KV Store V2` as the sheet structure is different. \n- If you want to convert an existing sheet, just add an `_rid` column and insert the first key-value row with `1`\n  and increase it by 1 until the last row.\n- Remove the timestamp column as `KV Store V2` does not depend on it anymore. \n\n```go\nimport (\n\t\"github.com/FreeLeh/GoFreeDB\"\n\t\"github.com/FreeLeh/GoFreeDB/google/auth\"\n)\n\n// If using Google Service Account.\nauth, err := auth.NewServiceFromFile(\n\t\"\u003cpath_to_service_account_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.ServiceConfig{},\n)\n\n// If using Google OAuth2 Flow.\nauth, err := auth.NewOAuth2FromFile(\n\t\"\u003cpath_to_client_secret_json\u003e\", \n\t\"\u003cpath_to_cached_credentials_json\u003e\", \n\tfreedb.FreeDBGoogleAuthScopes, \n\tauth.OAuth2Config{},\n)\n\nkv := freedb.NewGoogleSheetKVStoreV2(\n\tauth, \n\t\"\u003cspreadsheet_id\u003e\", \n\t\"\u003csheet_name\u003e\", \n\tfreedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVSetModeAppendOnly},\n)\ndefer kv.Close(context.Background())\n```\n\n### Get Value V2\n\nIf the key is not found, `freedb.ErrKeyNotFound` will be returned.\n\n```go\nvalue, err := kv.Get(context.Background(), \"k1\")\n```\n\n### Set Key V2\n\n```go\nerr := kv.Set(context.Background(), \"k1\", []byte(\"some_value\"))\n```\n\n### Delete Key V2\n\n```go\nerr := kv.Delete(context.Background(), \"k1\")\n```\n\n### Supported Modes V2\n\n\u003e For more details on how the two modes are different, please read the [protocol document](https://github.com/FreeLeh/docs/blob/main/freedb/protocols.md).\n\nThere are 2 different modes supported:\n\n1. Default mode.\n2. Append only mode.\n\n```go\n// Default mode\nkv := freedb.NewGoogleSheetKVStoreV2(\n\tauth,\n\t\"\u003cspreadsheet_id\u003e\",\n\t\"\u003csheet_name\u003e\",\n\tfreedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVModeDefault},\n)\n\n// Append only mode\nkv := freedb.NewGoogleSheetKVStoreV2(\n\tauth,\n\t\"\u003cspreadsheet_id\u003e\",\n\t\"\u003csheet_name\u003e\",\n\tfreedb.GoogleSheetKVStoreV2Config{Mode: freedb.KVModeAppendOnly},\n)\n```\n\n## License\n\nThis project is [MIT licensed](https://github.com/FreeLeh/GoFreeDB/blob/main/LICENSE).\n","funding_links":[],"categories":["Third-party APIs","第三方api"],"sub_categories":["Utility/Miscellaneous","实用程序/Miscellaneous"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFreeLeh%2FGoFreeDB","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFreeLeh%2FGoFreeDB","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFreeLeh%2FGoFreeDB/lists"}