Giter VIP home page Giter VIP logo

typeid-sql's Introduction

TypeID SQL

A SQL implementation of TypeID using PostgresSQL.

License: Apache 2.0

TypeIDs are a modern, type-safe, globally unique identifier based on the upcoming UUIDv7 standard. They provide a ton of nice properties that make them a great choice as the primary identifiers for your data in a database, APIs, and distributed systems. Read more about TypeIDs in their spec.

This particular implementation demonstrates how to use TypeIDs in a postgres database.

Installation

To use typeids in your Postgres instance, you'll need define all the appropriate types and functions by running the SQL scripts in this repo.

We recommend copying the SQL scripts into your migrations directory and using the migration tool of your choice. For example, Flyway, or Liquibase.

Note that this repo is using Supabase as a way to easily start a Postgres instance for development and testing, but you do not need to use Supabase for this implementation to work โ€“ simply use the Postgres instance of your choice.

Usage

Once you've installed the TypeID types and functions in your Postgres instance, you can use it as follows.

To define a new type of typeid with a specific prefix use the `typeid_

-- Define a `users` table that uses `user_id` as its primary key.
-- We use the `typeid_generate` function to randomly generate a new typeid of the
-- correct type for each user.
CREATE TABLE users (
    "id" user_id not null default typeid_generate('user'),
    "name" text,
    "email" text
);

-- Now we can insert new uses and have the `id` column automatically generated.
INSERT INTO users ("name", "email") VALUES ('Alice P. Hacker', '[email protected]');

Or

You can use the typeid_generate_text function to generate a new typeid as a string, and not use the typeid type

-- Define a `users` table that uses `user_id` as its primary key.
-- We use the `typeid_generate_text` function to randomly generate a new typeid of the
-- correct type for each user.
-- You will need to manually add the check constraint to the column
CREATE TABLE users (
    "id" text not null default typeid_generate_text('user') CHECK (typeid_check_text(id, 'user')),
    "name" text,
    "email" text
);

-- Now we can insert new uses and have the `id` column automatically generated.
INSERT INTO users ("name", "email") VALUES ('Alice P. Hacker', '[email protected]');
SELECT id FROM users;
-- Result:
-- "user_01hfs6amkdfem8sb6b1xmg7tq7"

Note that the database internally encodes typeids as a (prefix, uuid) tuple. Because this is different than the standard string representation of typeids in other libraries, we provide a typeid_parse and a typeid_print function that can be used to write queries with the standard string representation of typeids:

-- Insert a user with a specific typeid that might have been generated elsewhere:
INSERT INTO users ("id", "name", "email")
VALUES (typeid_parse('user_01h455vb4pex5vsknk084sn02q'), 'Ben Bitdiddle', '[email protected]');

-- To retrieve the ids as encoded strings, use the `typeid_print` function:
SELECT typeid_print(id) AS id, "name", "email" FROM users;

-- You can also use `typeid_parse` in a WHERE clause to filter by typeid:
SELECT typeid_print(id) AS id, "name", "email" FROM users
WHERE id = typeid_parse('user_01h455vb4pex5vsknk084sn02q');

or for the text variant

-- Insert a user with a specific typeid that might have been generated elsewhere:
INSERT INTO users ("id", "name", "email")
VALUES ('user_01h455vb4pex5vsknk084sn02q', 'Ben Bitdiddle', '[email protected]');

-- To retrieve the ids as encoded strings, just use the column:
SELECT id AS id, "name", "email" FROM users;

-- You can also use filter in a WHERE clause to filter by typeid:
SELECT typeid_print(id) AS id, "name", "email" FROM users
WHERE id = 'user_01h455vb4pex5vsknk084sn02q';

(Optional) Operator overload

If you'd like to be able to do the following:

-- Query directly from the DB with a serialized typeid
SELECT * FROM users u WHERE u.id = 'user_01h455vb4pex5vsknk084sn02q';

-- Result:
-- "(user,018962e7-3a6d-7290-b088-5c4e3bdf918c)",Ben Bitdiddle,[email protected]

Then you can add in the operator overload function for typeids:

Future work (contributions welcome)

  • Include examples not just for Postgres, but for other databases like MySQL as well.
  • Consider rewriting this library as a postgres extension. It would make it possible to use the standard typeid string representation without the need of extra functions.

typeid-sql's People

Contributors

isplasher avatar jasonyao avatar loreto avatar lucilleh avatar mikeland73 avatar spa5k avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

typeid-sql's Issues

Rails/ActiveRecord/Postgres

Has anyone managed to get typeid-sql working with rails/activerecord/postgres?

Despite hours and hours of trying, I cannot get past this error:

PG::UndefinedFunction: ERROR:  operator is only a shell: character varying = typeid
LINE 1: ...rnal_metadata" WHERE "ar_internal_metadata"."key" = $1 LIMIT...

Querying Example?

I'm curious if you have any examples of how you would query from the database using this setup:

https://github.com/jetpack-io/typeid-sql/blob/main/example/example.sql#L1

As I allude to here (jetify-com/typeid#1), I typically generate my IDs in my service layer instead of having my DB generate them.

One of the things I've been struggling with when using my type IDs is whether to insert as postgres' native UUID type - if I insert as the decoded UUID, this leads to a mismatch when e.g. my service's request logs contain the encoded/typed IDs, and then I have to decode them before, say, looking up the records in my DB. Does this custom type allow me to query postgres with the encoded string ID?

No way to SELECT on uuid column types with operator overloaded

After adding the optional operator overload, it seems impossible to select on the native uuid type. The following scenario occurs:

CREATE TABLE mytable (val UUID);

SELECT * FROM mytable WHERE val = 'c67a7925-e109-4abe-9d50-8c2a96a55483'::uuid;

Error:

typeid prefix must match the regular expression [a-z]{0,63}
CONTEXT:  PL/pgSQL function typeid_print(typeid) line 9 at RAISE

I suspect it's due to postgresql's operator type resolution, but I have no clue why typeid_print is being called.

Any ideas?

Any note on performance implications? type-id vs. text

Thank you for this!

I was just curious whether I should just go with having the primary key as text or use the scripts to have a type_id in SQL? The text approach seems simpler, but wondering how it impacts Postgresql performance.

Also, the docs in the #Usage section put the type of the "id" field as user_id. Is it supposed to be type_id? Is that a typo?

Supabase db diff fails

When adding the equality operator in a supabase migration:

CREATE OR REPLACE FUNCTION compare_type_id_equality(lhs_id typeid, rhs_id VARCHAR)
    RETURNS BOOLEAN AS $$
SELECT lhs_id = typeid_parse(rhs_id);
$$ LANGUAGE SQL IMMUTABLE;

Applying migration as db reset is successful. However, all subsequent supabase db diff fails with the following error:

Traceback (most recent call last):
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1770, in _execute_context
    self.dialect.do_execute(
  File "/usr/local/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 717, in do_execute
    cursor.execute(statement, parameters)
psycopg2.errors.UndefinedFunction: operator is only a shell: character varying = typeid
LINE 188:             case when p.data_type = 'USER-DEFINED' then
                                            ^

Should we compare the uuid part and the prefix part separately as strings?

`typeid_generate` Casting Error

Hey there. I just added the three functions (typeid_generate, typeid_check, uuid_generate_v7) to the database and ran

select typeid_generate('test');

But was greeted with this error output:

Query 1 ERROR: ERROR:  returned record type does not match expected record type
DETAIL:  Returned type uuid does not match expected type text in column 1.
CONTEXT:  PL/pgSQL function typeid_generate(text) while casting return value to function's return type

Running select uuid_generate_v7(); works fine for what it's worth.

Not sure if there's a postgres version mismatch but we're on PostgreSQL 15.1 on aarch64-unknown-linux-gnu, compiled by gcc (Ubuntu 10.3.0-1ubuntu1~20.04) 10.3.0, 64-bit

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.