Skip to content

Commit

Permalink
feat(psl, query-engine, schema-engine): add cuid(2) support, fix `u…
Browse files Browse the repository at this point in the history
…uid(7)` (#5047)

* feat(psl): add cuid(2) support, fix uuid(7) re-introspection

* chore(psl): fix clippy

* chore(psl): fix clippy

* fix(dmmf): [breaking] serialise uuid and cuid with proper args

* test(dmmf): expand functions.json test suite

* chore(query-structure): interpret "cuid()" as "cuid(1)"

* chore: remove leftover

* fix(query-engine): fix "create_uuid_v7_and_retrieve_it_should_work" suite

* test(query-engine): add create_cuid_v2_and_retrieve_it_should_work test

* feat(query-engine): port cuid to workspace, replace Prisma's wasm32-oriented fork with cuid 1.3.3

* feat(query-engine): replace cuid1 with cuid2 for internal transaction IDs

* chore: cargo fmt

* chore: clippy

* fix(psl): keep cuid() default version as 1

* test(query-engine): add "create_cuid_v1_and_retrieve_it_should_work" suite

* chore: address review comments

* test(psl): add validation tests for cuid and uuid

* fix(dmmf): serialise uuid, cuid like nanoid; parse nanoid like uuid, cuid

* chore(psl): revert bad test update to "server_side_functions"

* chore(dmmf): remove unused tuple, simplify "default_value" for generators

* fix(psl): typo in test

* fix(psl): typo in test

* chore(psl): use itertools

* fix(qe): fix broken shebang in query-engine-wasm/build.sh

`#!/bin/bash` is non-portable and only works on some systems which has
bash in that location, which is not actually standard or necessarily
expected.

The only two absolute paths one can rely on in portable scripts are
`#!/bin/sh` (which is a POSIX standard) and `#!/usr/bin/env` (which is
not technically mandated by a formal standard but is de-facto
implemented on all Unix systems).

None of my systems have a usable bash installation in `/bin/bash`.

My Linux system only has bash in `/run/current-system/sw/bin/bash`, so the
script fails with `sh: line 2: ./build.sh: cannot execute: required file
not found`.

My macOS system has an ancient version of bash shipped with the system
installed as `/bin/bash` (which Apple last updated in 2007 and will
never ever update anymore for license reasons since bash 4+ switched to
GPLv3; it's likely to be removed in future macOS versions though as
macOS has long replaced bash with zsh as its shell of choice), and in
some ways it's worse than not having any since modern bash scripts that
assume bash 4 or 5 often fail or produce incorrect results with it. This
specific script accidentally happens to work anyway, but the correct
bash installation to use on this system is still `/opt/homebrew/bin/bash`.

Anything other than `/bin/sh` (be it `bash` or `python` or `node`) can
only be dispatched via `/usr/bin/env` if a script is intended to be used
on more than one machine because it's not possible to predict where the
interpreter is going to be at.

* chore(driver-adapters):: bump wrangler version to 3.88.0

* chore(driver-adapters): bump wasm32-unknown-unknown rust-toolchain to latest version

* fix(query-engine-wasm): replace "cuid" with "prisma/cuid-rust?branch=v1.3.3-wasm32-unknown-unknown"

* chore: revert upgrade to wrangler (from 3.50.0 to 3.88.0) for suspect race condition in newer versions

* chore: remove leftover

---------

Co-authored-by: Alexey Orlenko <[email protected]>
  • Loading branch information
jkomyno and aqrln authored Nov 22, 2024
1 parent 90c6eb3 commit 5e70d19
Show file tree
Hide file tree
Showing 44 changed files with 890 additions and 144 deletions.
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ graph.dot

prisma-schema-wasm/nodejs

# Ignore pnpm-lock.yaml
query-engine/driver-adapters/pnpm-lock.yaml
package-lock.json

# Useful for local wasm32-* development
Expand Down
89 changes: 72 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ chrono = { version = "0.4.38", features = ["serde"] }
derive_more = "0.99.17"
user-facing-errors = { path = "./libs/user-facing-errors" }
uuid = { version = "1", features = ["serde", "v4", "v7", "js"] }
cuid = { git = "https://github.com/prisma/cuid-rust", branch = "v1.3.3-wasm32-unknown-unknown" }
getrandom = { version = "0.2" }

indoc = "2.0.1"
indexmap = { version = "2.2.2", features = ["serde"] }
itertools = "0.12"
Expand All @@ -64,7 +67,6 @@ napi = { version = "2.16.13", default-features = false, features = [
"serde-json",
] }
napi-derive = "2.16.12"
js-sys = { version = "0.3" }
pin-project = "1"
rand = { version = "0.8" }
regex = { version = "1", features = ["std"] }
Expand All @@ -73,6 +75,11 @@ serde-wasm-bindgen = { version = "0.5" }
tracing = { version = "0.1" }
tracing-futures = "0.2"
tsify = { version = "0.4.5" }

# version for `[email protected]`, see:
# https://github.com/rustwasm/wasm-bindgen/pull/4072/
js-sys = { version = "0.3.70" }

wasm-bindgen = { version = "0.2.93" }
wasm-bindgen-futures = { version = "0.4" }
wasm-rs-dbg = { version = "0.1.2", default-features = false, features = ["console-error"] }
Expand Down
2 changes: 1 addition & 1 deletion libs/telemetry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ tracing-futures = "0.2"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
tracing-opentelemetry = "0.17.4"
uuid.workspace = true
cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" }
cuid.workspace = true
crosstarget-utils = { path = "../crosstarget-utils" }
lru = "0.7.7"
enumflags2.workspace = true
Expand Down
1 change: 1 addition & 0 deletions psl/parser-database/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ diagnostics = { path = "../diagnostics" }
schema-ast = { path = "../schema-ast" }
indexmap.workspace = true
enumflags2.workspace = true
itertools.workspace = true
either = "1.6.1"
rustc-hash = "1.1.0"
43 changes: 33 additions & 10 deletions psl/parser-database/src/attributes/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
ast::{self, WithName},
coerce,
context::Context,
generators::{CUID_SUPPORTED_VERSIONS, UUID_SUPPORTED_VERSIONS},
types::{DefaultAttribute, ScalarFieldType, ScalarType},
DatamodelError, ScalarFieldId, StringId,
};
Expand Down Expand Up @@ -197,10 +198,10 @@ fn validate_model_builtin_scalar_type_default(
validate_empty_function_args(funcname, &funcargs.arguments, accept, ctx)
}
(ScalarType::String, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_CUID => {
validate_empty_function_args(funcname, &funcargs.arguments, accept, ctx)
validate_uid_int_args(funcname, &funcargs.arguments, &CUID_SUPPORTED_VERSIONS, accept, ctx)
}
(ScalarType::String, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_UUID => {
validate_uuid_args(&funcargs.arguments, accept, ctx)
validate_uid_int_args(funcname, &funcargs.arguments, &UUID_SUPPORTED_VERSIONS, accept, ctx)
}
(ScalarType::String, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_NANOID => {
validate_nanoid_args(&funcargs.arguments, accept, ctx)
Expand Down Expand Up @@ -244,10 +245,10 @@ fn validate_composite_builtin_scalar_type_default(
match (scalar_type, value) {
// Functions
(ScalarType::String, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_CUID => {
validate_empty_function_args(funcname, &funcargs.arguments, accept, ctx)
validate_uid_int_args(funcname, &funcargs.arguments, &CUID_SUPPORTED_VERSIONS, accept, ctx)
}
(ScalarType::String, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_UUID => {
validate_uuid_args(&funcargs.arguments, accept, ctx)
validate_uid_int_args(funcname, &funcargs.arguments, &UUID_SUPPORTED_VERSIONS, accept, ctx)
}
(ScalarType::DateTime, ast::Expression::Function(funcname, funcargs, _)) if funcname == FN_NOW => {
validate_empty_function_args(FN_NOW, &funcargs.arguments, accept, ctx)
Expand Down Expand Up @@ -381,18 +382,40 @@ fn validate_dbgenerated_args(args: &[ast::Argument], accept: AcceptFn<'_>, ctx:
}
}

fn validate_uuid_args(args: &[ast::Argument], accept: AcceptFn<'_>, ctx: &mut Context<'_>) {
let mut bail = || ctx.push_attribute_validation_error("`uuid()` takes a single Int argument.");
fn format_valid_values<const N: usize>(valid_values: &[u8; N]) -> String {
match valid_values.len() {
0 => String::new(),
1 => valid_values[0].to_string(),
2 => format!("{} or {}", valid_values[0], valid_values[1]),
_ => {
use itertools::Itertools as _;

let (last, rest) = valid_values.split_last().unwrap();
let rest_str = rest.iter().map(|v| v.to_string()).join(", ");
format!("{}, or {}", rest_str, last)
}
}
}

fn validate_uid_int_args<const N: usize>(
fn_name: &str,
args: &[ast::Argument],
valid_values: &[u8; N],
accept: AcceptFn<'_>,
ctx: &mut Context<'_>,
) {
let mut bail = || ctx.push_attribute_validation_error(&format!("`{fn_name}()` takes a single Int argument."));

if args.len() > 1 {
bail()
}

match args.first().map(|arg| &arg.value) {
Some(ast::Expression::NumericValue(val, _)) if ![4u8, 7u8].contains(&val.parse::<u8>().unwrap()) => {
ctx.push_attribute_validation_error(
"`uuid()` takes either no argument, or a single integer argument which is either 4 or 7.",
);
Some(ast::Expression::NumericValue(val, _)) if !valid_values.contains(&val.parse::<u8>().unwrap()) => {
let valid_values_str = format_valid_values(valid_values);
ctx.push_attribute_validation_error(&format!(
"`{fn_name}()` takes either no argument, or a single integer argument which is either {valid_values_str}.",
));
}
None | Some(ast::Expression::NumericValue(_, _)) => accept(ctx),
_ => bail(),
Expand Down
16 changes: 16 additions & 0 deletions psl/parser-database/src/generators.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Convenient access to a ID generator constants, used by Prisma in psl, Query Engine and Schema Engine.
//! Every change to the `DEFAULT_*_VERSION` constants in this module is a breaking change.

/// Version of the `uuid()` ID generator supported by Prisma.
pub const UUID_SUPPORTED_VERSIONS: [u8; 2] = [4, 7];

/// Version of the `cuid()` ID generator supported by Prisma.
pub const CUID_SUPPORTED_VERSIONS: [u8; 2] = [1, 2];

/// Default version of the `uuid()` ID generator.
pub const DEFAULT_UUID_VERSION: u8 = 4;

/// Default version of the `cuid()` ID generator.
// Note: if you change this, you'll likely need to adapt existing tests that rely on `cuid()` sequences being already sorted
// (e.g., `cuid(1)`, the current default, generates monotonically increasing sequences, `cuid(2)` doesn't).
pub const DEFAULT_CUID_VERSION: u8 = 1;
1 change: 1 addition & 0 deletions psl/parser-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ mod attributes;
mod coerce_expression;
mod context;
mod files;
pub mod generators;
mod ids;
mod interner;
mod names;
Expand Down
2 changes: 1 addition & 1 deletion psl/psl-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub use crate::{
reformat::{reformat, reformat_multiple, reformat_validated_schema_into_single},
};
pub use diagnostics;
pub use parser_database::{self, is_reserved_type_name};
pub use parser_database::{self, generators, is_reserved_type_name};
pub use schema_ast;
pub use set_config_dir::set_config_dir;

Expand Down
1 change: 1 addition & 0 deletions psl/psl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub use psl_core::{
builtin_connectors::{can_have_capability, can_support_relation_load_strategy, has_capability},
datamodel_connector,
diagnostics::{self, Diagnostics},
generators,
is_reserved_type_name,
mcf::config_to_mcf_json_value as get_config,
mcf::{generators_to_json, render_sources_to_json}, // for tests
Expand Down
Loading

0 comments on commit 5e70d19

Please sign in to comment.