Database - Alpha Documentation

Skip to content

# Alpha database system

## Automatic structure

Compared to native SqlAlchemy in alpha you only need to instantiate the table model:

    from alphaz.models.database.models import AlphaTable, AlphaColumn
    DB = core.db

    class DuckType(DB.Model, AlphaTable):
        __bind_key__ = DB
        __tablename__= "duck_type"

        type_id = AlphaColumn(INTEGER, primary_key=True, autoincrement=True)
        name = AlphaColumn(TEXT,nullable = False, default = "SuperDuck")

    class DuckMedal(DB.Model, AlphaTable):
        __bind_key__ = DB
        __tablename__= "duck_medal"

        name = AlphaColumn(TEXT,nullable = False, default = "Lucky")
        duck_id       = AlphaColumn(INTEGER, ForeignKey ('duck.duck_id'      ), nullable     = False, default= -1)

    class Duck(DB.Model, AlphaTable):
        __bind_key__ = DB
        __tablename__= "duck"

        duck_id = AlphaColumn(INTEGER, primary_key=True, autoincrement=True, visible=False)
        name = AlphaColumn(TEXT,nullable = False, default = "")

        # Many to one
        duck_type_id = AlphaColumn(INTEGER, ForeignKey ('duck_type.type_id'), nullable = False, default = -1, visible=False)
        duck_type = relationship("DuckType")

        # One to many
        medals = relationship("DuckMedals")

By default a select query on Duck class defined like this:

    master_duck = DuckType(ame="Master Duck")
    DB.add(master_duck)

    ducky = Duck(name="Ducky",duck_type=master_duck)
    DB.add(ducky)

    honnor_medal = DuckMedal(name="Honnor",duck_id=ducky.duck_id)
    lucky_medal = DuckMedal(name="Lucky",duck_id=ducky.duck_id)
    DB.add(ducky)

    ducks = DB.select(Duck, filters=[Duck.name=="Ducky"], first=True)

Will result in this:

    {
      "duck_id": 1,
      "name": "Ducky",
      "duck_type": {
        "type_id": 1,
        "duck_type": "Master Duck"
      },
      "medals": [{ "name": "Honnor" }, { "name": "Lucky" }]
    }

## Schema

Note

The associated Schema is created automatically, with classic and nested fields.

However Marshmallow schema could be defined using the classic way Marshmallow:

- Set visible to False if you dont want the column to appears in the Schema.

Important

Schema must be defined after the Model

    DB = core.db

    class DuckTypeSchema(Schema):
        type_id = fields.Integer()
        name = fields.String()

    class DuckMedalSchema(Schema):
        name = fields.String()

    class DuckSchema(Schema):
        name = fields.String()

        # Many to One
        duck_type = fields.Nested(DuckTypeSchema)

        # One to many
        medals = fields.List(fields.Nested(DuckMedalSchema))

Important

Alpha will automatically detect the schema if the name is defined as `"{ModelName}Schema"` and is located in the same file.

Note

In this mode, Schema could be defined automatically, excepted for nested fields.

### Specific Schema

Schema could be specified for every request:

    DB.select(model  = Duck, schema = DuckSchema)

## Alpha notation

### init

This enable the use of model columns which is not possible using SqlAlchemy:

    attr = {
        Duck.name: name,
        Duck.duck_type_id: duck_type_id,
    }
    duck = Duck()
    duck.init(attr)

or

    duck = Duck()
    duck.init({
        Duck.name: name,
        Duck.duck_type_id: duck_type_id,
    })

Instead of:

    attr = {
        Duck.name: name,
        Duck.duck_type_id: duck_type_id,
    }
    duck = Duck()
    duck.init(**{x.key:y for x,y in attr.items()})

## Update

### Classic SQLAlchemy

#### Select query

        duck = Duck.query.filter_by(name=name).first()
        duck.duck_type_id = duck_type_id
        db.session.commit()

#### Init

        new_duck = Duck("name": name, "duck_type_id": duck_type_id)
        db.session.merge(new_duck)
        db.session.commit()

or

        attr = {
            "name": name,
            "duck_type_id": duck_type_id,
        }
        duck = Duck(**attr)
        db.session.merge(new_duck)
        db.session.commit()

#### Init and update

    new_duck = Duck()
    new_duck.name = name
    new_duck.duck_type_id = duck_type_id
    db.session.merge(new_duck)
    db.session.commit()

### Update

Alphaz include a special update method that simplifies updates via api routes

#### Model as a parameter

Warning

This is not recommanded because you could not specified if a field of Duck is required or not

    @route(
        path='duck',
        methods=["PUT"],
        parameters=[
            Parameter("duck", ptype=Duck, required=True)
        ],
    )
    def update_duck():
        return DB.update(api["duck"])

#### Route parameters to model

    @route(
        path='duck',
        methods=["PUT"],
        parameters=[
            Parameter("name", ptype=str, required=True),
            Parameter("duck_type_id", ptype=int)
        ],
    )
    def update_duck():
        return DB.update(Duck(**api.get_parameters()), not_none=True) # not_none is to set if you dont want None values to update fields

or using a function:

    def update_duck(name:str, duck_type_id:str):
        return DB.update(Duck(**locals()))

    @route(
        path='duck',
        methods=["PUT"],
        parameters=[
            Parameter("name", ptype=str, required=True),
            Parameter("duck_type_id", ptype=int)
        ],
    )
    def update_duck():
        return update_duck(**api.get_parameters())

### Relations

#### Relation filter

        return DB.select(
            Duck,
            filters=[Duck.duck_type.has(DuckType.name.like(name))]
        )

Will produce a query like:

    SELECT * FROM DUCK WHERE EXISTS (SELECT 1 FROM DUCKTYPE where DUCKTYPE.id==DUCK.ducktype_id and DUCKTYPE.name=name)

Doc