Repository navigation
Prisma Importer
The Prisma importer (crates/core/src/importer/prisma/, exposing PrismaImporter) turns a
.prisma file into a pivot::Schema. It implements the shared
Importer trait.
| File | Role |
|---|---|
grammar.pest |
The PEG grammar for Prisma Schema Language — defines schema, block (datasource/generator/model/enum/view/type alias), field_decl, attribute syntax (@id, @@map(...)), and value literals. |
ast.rs |
The raw, untyped intermediate structs the parser produces: RawAttr { path, args }, RawArg::{Named, Positional}, RawValue::{Str, Int, Float, Ident, Array, Call}, RawField, RawModel, RawTypeAlias. These are pub(super) — never exposed outside the prisma module. |
parser.rs |
Walks pest::Pairs<Rule> and builds the ast.rs structures. Exposes PrismaParser (the pest-generated parser struct), extract_database_kind, parse_model_block, parse_type_alias, parse_attribute, parse_enum_block. This stage only understands syntax — it has no notion yet of what String or @db.VarChar(255) mean semantically. |
resolver.rs |
Turns the raw AST into pivot types. resolve_models builds Tables (columns, primary keys, indexes, foreign keys, relations, inheritance, behaviors) from RawModels, cross-referencing model and enum names to distinguish scalar fields from relation fields and to detect implicit many-to-many relations. resolve_views does the analogous work for view blocks. Unrecognized attributes are routed into OrmMetadata.unknown_features here (via a shared push_unknown_attrs helper) rather than dropped. |
mappers.rs |
Small, focused translation functions used by resolver.rs: map_scalar_type (Prisma type name → ScalarType), map_db_hint (@db.* attribute → DbHint), map_default_value (@default(...) → DefaultValue), map_index_type, extract_index_columns, parse_referential_action, plus raw_value_to_json/raw_args_to_json used to serialize unrecognized attribute arguments into UnknownFeature.value. |
behaviors.rs |
detect_behaviors — recognizes the conventional createdAt / deletedAt / version columns and turns them into Behaviors. See Behavior detection. |
tests.rs |
Unit tests for the importer (see Testing). |
The entry point tying all three phases together is parse_schema in mod.rs:
pub fn parse_schema(input: &str) -> Result<Schema, ImportError> {
let pairs = PrismaParser::parse(Rule::schema, input)?; // Phase 1
// ...walk top-level blocks, collecting RawModel/RawView/Enum/RawTypeAlias... Phase 2
let tables = resolver::resolve_models(raw_models, &model_names, &enum_names, &type_aliases)?; // Phase 3
let views = resolver::resolve_views(raw_views, &enum_names, &type_aliases)?;
// ...assemble into a Schema
}PrismaImporter::import (the Importer trait impl) just delegates to parse_schema.
Prisma has a dedicated attribute for only one behavior (@updatedAt). The
other three have no Prisma syntax, so the importer infers them from conventional column
patterns:
| Prisma field | Pivot behavior | Rule |
|---|---|---|
x DateTime @updatedAt |
Behavior::UpdatedAt |
Any field carrying @updatedAt (directly or through a type alias), whatever its name. |
createdAt DateTime @default(now()) |
Behavior::CreatedAt |
Name is exactly createdAt, type DateTime, required, not a list, default is now(). |
deletedAt DateTime? |
Behavior::SoftDelete |
Name is exactly deletedAt, type DateTime, optional, not a list. |
version Int |
Behavior::Versioning |
Name is exactly version, type Int, required, not a list. |
The type check uses the type behind a type alias, so createdAt Timestamp @default(now())
with type Timestamp = DateTime is still detected. The column stays in Table.columns as
usual — the behavior only adds the ORM-level meaning on top.
-
Versioningis a name-based heuristic. Prisma has no notion of optimistic locking, so any requiredversion Intfield is detected asBehavior::Versioning, even if it is really a business value (an API version, a document revision number shown to users...). If that is not what you want, rename the field (e.g.apiVersion) and keep the database name with@map("version"). -
Only exact camelCase field names are matched.
created_at,CreatedAt,deleted_at,removedAt,rowVersion... are not detected. This follows Prisma's naming convention: the field name is camelCase and the database name is set with@map. Detection looks at the field name, not the@mapname, so this works:createdAt DateTime @default(now()) @map("created_at") // detected deletedAt DateTime? @map("deleted_at") // detected
whereas a field literally named
created_atis not. -
A wrong shape silently disables detection.
createdAt DateTimewithout@default(now()), a requireddeletedAt DateTime, or aversion BigIntare imported as plain columns with no behavior and no warning. -
No configuration yet. Custom column names cannot be declared as behaviors; this would require a config option on the importer.
-
Type aliases are inlined, not preserved as a separate concept. Prisma's
type Foo = Int @id @default(autoincrement())has no equivalent pivot type —resolver.rsexpands each use ofFooback to its underlyingScalarType+ attributes at resolve time, so the alias is invisible to the rest of the pipeline. -
Unrecognized attributes never cause a hard error. Any
@or@@attribute the resolver doesn't have an explicit case for is captured as anOrmMetadata.unknown_featuresentry (namespaced"prisma.<name>") instead of being dropped or aborting the import — see Pivot IR. This is what lets the importer stay lossless against future Prisma releases without being updated for every new attribute immediately. -
Views are parsed but their SQL definition is not available. Prisma Schema Language's
viewblocks only declare the column list, not the underlyingSELECT— soView.definitionis always an empty string for Prisma-sourced views. -
ImportError::Parsevs.ImportError::Schema.Parsefires automatically via aFrom<pest::error::Error<Rule>>impl whenever the input isn't valid Prisma Schema Language syntax at all (the PEG parse itself fails).Schemacovers content that parses syntactically but is locally invalid — e.g. a numeric literal token that doesn't actually parse as an integer or float. It is not used for semantic issues like a field referencing a model or type that doesn't exist: those degrade gracefully toScalarType::Unsupportedinresolver.rsinstead of raising an error.
|
Manech DUBREIL dmanech@gmail.com |
Timéo TRÉGAROT timeo.tregarot@epitech.eu |
Aymeric JOUANNET-MIMY aymeric.jouannet-mimy@epitech.eu |
Esteban BOUYAULT-MIMY esteban.bouyault-yvanez@epitech.eu |
Arthur DRAHY arthur.drahy@epitech.eu |