Skip to content

SQLite: Booleans become integer columns #375

Closed
@reivilibre

Description

@reivilibre

Description

When using SQLite, boolean data types are converted to integer.

Whilst this is somewhat fair enough (SQLite doesn't have a native boolean type; it expects you to use an integer with 0 and 1), it means that sea-orm-cli generate entity gives you a i32 field rather than a bool field, which is ... sad.

This conflicts a little bit with the 'schema-first' goal of this project, as we lose information by encoding it into the schema and then decoding it again.

See

ColumnType::Boolean => "integer".into(),
.

Steps to Reproduce

  1. Create a schema migration including a boolean type, e.g.:
        manager
            .create_table(
                Table::create()
                    .table(TimelineSegment::Table)
                    .if_not_exists()
                    .col(
                        ColumnDef::new(TimelineSegment::SegmentId)
                            .integer()
                            .not_null()
                            .auto_increment()
                            .primary_key(),
                    )
                    .col(
                        ColumnDef::new(TimelineSegment::PrevGappy)
                            .boolean()
                            .not_null(),
                    )
                    .to_owned(),
            )
            .await?;
  1. Apply the migration
  2. Generate entities using sea-orm-cli generate entity --database-url sqlite://$(realpath ../../../devdb.sqlite3)

Expected Behavior

I should have obtained this entity:

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "timeline_segment")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub segment_id: i32,
    pub prev_gappy: bool,
}

Actual Behavior

I obtained this entity:

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "timeline_segment")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub segment_id: i32,
    pub prev_gappy: i32,  // <---- !!!
}

SQLite's schema shows the reason why quite clearly:

sqlite> .schema
CREATE TABLE IF NOT EXISTS "seaql_migrations" ( "version" text NOT NULL PRIMARY KEY, "applied_at" integer NOT NULL );
CREATE TABLE IF NOT EXISTS "timeline_segment" ( "segment_id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "prev_gappy" integer NOT NULL );

Reproduces How Often

Always

Versions

│   └── sea-orm v0.8.0
│       ├── sea-orm-macros v0.8.0 (proc-macro)
│       ├── sea-query v0.24.6
│       │   ├── sea-query-derive v0.2.0 (proc-macro)
│       │   ├── sea-query-driver v0.1.1 (proc-macro)
│       ├── sea-strum v0.23.0
│       │   └── sea-strum_macros v0.23.0 (proc-macro)
├── sea-orm v0.8.0 (*)
├── sea-query v0.25.2
│   └── sea-query-derive v0.2.0 (proc-macro) (*)

Using SQLite on Ubuntu.

Additional Information

If we think maintaining the integer affinity is important, we could be cheeky and call the type integerboolean or something like that, which the entity generator could recognise to mean boolean.

The algorithm at https://www.sqlite.org/datatype3.html#determination_of_column_affinity suggests that will be absolutely fine as long as the name contains 'int'.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions