Time and IDs

UUID tools

UUIDs beyond the random uuid(): version 7 sorted by time for database keys, versions 5 and 3 that give the same id for the same name, and any UUID read with its version and time.

Version 1.0.0 · 6 functions · 1 crate

#ids#database#import#api

Functions

What use uuid_tools.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use uuid_v7, uuid_v7_at from uuid_tools (Quillo 0.6).

uuid_v7() → str

A new version 7 UUID: its first 48 bits are the time in milliseconds, so ids made later sort after (within one server, even in the same millisecond), and database indexes stay compact.

uuid_v7_at(time_ms: int) → stror an error

A version 7 UUID for a time in milliseconds since 1970 (as now() gives), the rest random: for back-filling old rows, or the lowest id of a time range.

uuid_v5(namespace: str, name: str) → stror an error

The version 5 UUID of name in namespace ("dns", "url", "oid", "x500", or a UUID of your own), by SHA-1: the same name always gives the same id, so an import can find its rows again. uuid_v5("dns", "example.com") is "cfbff0d1-9375-5685-968c-48ce8b15ae17".

uuid_v3(namespace: str, name: str) → stror an error

As uuid_v5, by MD5 (version 3), for systems that use those.

uuid_parse(text: str) → anyor an error

Any UUID read, in any of its forms (with or without dashes, braces or "urn:uuid:"): { uuid, version, variant, time_ms, simple, urn, nil }. time_ms is when versions 1, 6 and 7 were made (else null); uuid the usual lower-case form. An error when it is not a UUID.

uuid_valid(text: str) → bool

Whether text is a UUID in any of its forms.

Get it

$ quillo install uuid_tools               # uuid_tools.qwer into this folder$ quillo install uuid_tools --example     # and its example, uuid_tools.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/uuid_tools.qwer$ curl -O https://quillolang.org/plugins/files/uuid_tools.qwe

Then, in your program, all of it or only what you call:

main.qwe
use uuid_tools.qweruse uuid_v7, uuid_v7_at from uuid_tools      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
uuid = { version = "1", features = ["v3", "v5", "v7", "std"] }

Example

uuid_tools.qwe
// Database keys that sort by time (v7), ids for imported rows that stay the same on every import (v5), and any UUID read back.////   quillo run uuid_tools.qwe      then open http://localhost:8080/keysuse "uuid_tools.qwer"route GET /keys {    let a = uuid_v7()    let b = uuid_v7()    { a, b, sorted: a < b, made: uuid_parse(a)?.version, random: uuid_parse(uuid())?.version }}// The same customer email gives the same id on every import.route GET /import = ["ada@example.com", "grace@example.com", "ada@example.com"] | map((e) => { email: e, id: uuid_v5("6ba7b811-9dad-11d1-80b4-00c04fd430c8", e)? })route GET /read ? { id: str = "{CFBFF0D1-9375-5685-968C-48CE8B15AE17}" } = uuid_parse(id)?route GET /known = { dns: uuid_v5("dns", "example.com")?, old: uuid_parse(uuid_v7_at(1767225600000)?)?.time_ms, valid: [uuid_valid("nope"), uuid_valid(uuid())] }
$ quillo run uuid_tools.qwe$ curl 'localhost:8080/keys'$ curl 'localhost:8080/known'$ curl 'localhost:8080/read'

Source

uuid_tools.qwer
//! UUIDs beyond Quillo's random `uuid()`: version 7 (sorted by time, a good database key), version 5 and 3 (the same name always gives the same id), and any UUID read: its version, variant and time.//! version: 1.0.0//!//! [dependencies]//! uuid = { version = "1", features = ["v3", "v5", "v7", "std"] }use serde_json::{json, Value};use uuid::{NoContext, Timestamp, Uuid};fn namespace(ns: &str) -> Result<Uuid, String> {    Ok(match ns.trim().to_lowercase().as_str() {        "dns" => Uuid::NAMESPACE_DNS,        "url" => Uuid::NAMESPACE_URL,        "oid" => Uuid::NAMESPACE_OID,        "x500" => Uuid::NAMESPACE_X500,        other => Uuid::parse_str(other).map_err(|_| format!("namespace is \"dns\", \"url\", \"oid\", \"x500\" or a UUID, not {:?}", ns))?,    })}/// A new version 7 UUID: its first 48 bits are the time in milliseconds, so ids made later sort after (within one server, even in the same millisecond), and database indexes stay compact.pub fn uuid_v7() -> String {    Uuid::now_v7().to_string()}/// A version 7 UUID for a time in milliseconds since 1970 (as `now()` gives), the rest random: for back-filling old rows, or the lowest id of a time range.pub fn uuid_v7_at(time_ms: i64) -> Result<String, String> {    if time_ms < 0 {        return Err("times from 1970".into());    }    Ok(Uuid::new_v7(Timestamp::from_unix(NoContext, (time_ms / 1000) as u64, ((time_ms % 1000) * 1_000_000) as u32)).to_string())}/// The version 5 UUID of `name` in `namespace` ("dns", "url", "oid", "x500", or a UUID of your own), by SHA-1: the same name always gives the same id, so an import can find its rows again. `uuid_v5("dns", "example.com")` is "cfbff0d1-9375-5685-968c-48ce8b15ae17".pub fn uuid_v5(namespace: &str, name: &str) -> Result<String, String> {    Ok(Uuid::new_v5(&self::namespace(namespace)?, name.as_bytes()).to_string())}/// As `uuid_v5`, by MD5 (version 3), for systems that use those.pub fn uuid_v3(namespace: &str, name: &str) -> Result<String, String> {    Ok(Uuid::new_v3(&self::namespace(namespace)?, name.as_bytes()).to_string())}/// Any UUID read, in any of its forms (with or without dashes, braces or "urn:uuid:"): `{ uuid, version, variant, time_ms, simple, urn, nil }`. `time_ms` is when versions 1, 6 and 7 were made (else null); `uuid` the usual lower-case form. An error when it is not a UUID.pub fn uuid_parse(text: &str) -> Result<Value, String> {    let u = Uuid::parse_str(text.trim()).map_err(|e| format!("{:?} is not a UUID: {}", text, e))?;    let time_ms = u.get_timestamp().map(|t| { let (s, n) = t.to_unix(); s as i64 * 1000 + (n / 1_000_000) as i64 });    Ok(json!({        "uuid": u.hyphenated().to_string(),        "version": u.get_version_num(),        "variant": format!("{:?}", u.get_variant()),        "time_ms": time_ms,        "simple": u.simple().to_string(),        "urn": u.urn().to_string(),        "nil": u.is_nil(),    }))}/// Whether `text` is a UUID in any of its forms.pub fn uuid_valid(text: &str) -> bool {    Uuid::parse_str(text.trim()).is_ok()}
Thread
76Useful? Like it, or add to its thread below.

Thread 0 posts

On UUID tools: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.