Skip to main content

Gerenciador de banco de dados relacional

Project description

KassORM

Gerenciamento de migrations, modelos, seeders e gerador de query

Criado com o intuito de abstratir toda uma modelagem de dados, de forma fácil. Sua criação é baseada na biblioteca Eloquent vista no Laravel, framework PHP. A principio, não há muitos ORMs para python que são intuitivos no uso, inicialemente, neste pacote, era utilizado o SqlAlchemy, mas seu uso e documentação são complicados, com uma curva grande para aprendizado, não desmerecendo ele, sabemos o quão robusto e estável está atualmente, mas precisavamos de algo mais direto e que entendessemos a fundo o uso.

Indice

Migration

Querier

Modelr





Migration

Uso de migrations são importantes para manter o versionamento do banco de dados. Veja abaixo como utilizar.

Criar e executar

Utilize o metodo 'make_file_migration()' informando o nome, diretório, nome da tabela e opcionalmente um comentário. O nome da migration tem como prefixos 'create_' e 'alter_', então gere o nome com eles para que as regras de cada tipo sejam setadas no arquivo gerado.

name_migration = "create_users"
dir_migration = "database"
table = "users"
comment = "criação da tabela de usuários"
Migration().make_file_migration(name_migration, dir_migration, table, comment)

Para executar as migrations informe apenas o local onde elas estão no método "migrate()", este comando também cria uma tabela ( migrations ) para gerenciamento de qual migration já foi executada.

dir_migration = "database"
Migration().migrate(dir_migration)

Drop

Para reiniciar o processo, fazendo o rollback das migrations, use o metodo 'drop_all_migrations()'

dir_migration = "database"
Migration().drop_all_migrations(dir_migration)

Configurando uma migration

O arquivo gerado terá a seguinte aparência:


from KassOrm import Migration

class migrate(Migration): 
  
    __type__ = 'create'  
    __table__ = 'users'
    __comment__ = 'criação da tabela de usuários'
    
    def up(self):
        self.id().add()
        self.datetime('created_at').add()       
        
        
    def down(self): 
        self.dropTableIfExists()        
        

Um valor opcional __ conn __ pode ser passado na classe, para determinar qual conexão usar, essa conexão deverá estar configurada em configs/database. Não informando será usado a conexão padrão.

É aqui que será criado os campos da tabela e seus relacionamentos. o metodo up(), é executado quando a migration é executada para criar, nesse caso, uma tabela, o down(), é o metodo responsavel por fazer o inverso, no caso dropar a tabela.

Lista de tipos de campos e outras propriedades:

# colunas
id()
string(name, qnt)
bigInteger(name)
bigIntegerUnisigned(name)
text(name)
enum(name, values)
integer(name,qnt)
datetime(name)


# propriedades para as colunas
foreign(table, key, local_key)
nullable()
unsigned()
comment(comment)
unique(columns,name)
current_timestamp()
update_timestamp()
addColumn()
dropColumn(name)
after(column)
first(column)
dropTableIfExists()

Relacionamentos

Para relacionar duas tabelas, use foreign() como abaixo:

from KassOrm import Migration

class adresses(Migration): 
  
    __type__ = 'create'  
    __table__ = 'adress'
    __comment__ = 'contem endereços'

    def up(self):
        self.id().add()
        self.string('name').add()
        self.string('number).add()

    def down(self): 
        self.dropTableIfExists()    



class migrate(Migration): 
  
    __type__ = 'create'  
    __table__ = 'users'
    __comment__ = 'criação da tabela de usuários'
    
    def up(self):
        self.id().add()
        self.datetime('created_at').add()     
        self.unsignedBigInteger('adress_id').add()     

        self.foreign(table="adress", key="id", local_key="adress_id").add()
        
        
    def down(self): 
        self.dropTableIfExists()        
        





Querier

Criador de querys para maior segurança e abstração de banco de dados.

Querier() recebe como parametro o nome da conexão (Querier('api')) que estará configurado dentro das configurações, caso não seja informada, será usada a conexão padrão (default).

Instanciar a classe e informar a tabela:

query = Querier('api').table("users")

Agora poderá usar a var query para fazer diversas buscas e filtros na mesma tabela.

query.get()
# SELECT * FROM users

query.where({"name":"kass"}).get()
# SELECT * FROM users WHERE (name = "kass")

Select

Selecionando os campos, caso o método select não for chamado, será sempre retornado todos os campos

query.select(["name","login"])

Selecionando os campos e pegando todos os dados, get() finaliza a query

query.select(["name","login"]).get()

Selecionando os campos e pegando somente o primeiro registro, first() finaliza a query

query.select(["name","login"]).first()

Retornando a query a executar, toSql() finaliza a query

query.select(["name","login"]).toSql()

Retornando a query separado dos parametros, toInfo() finaliza a query

query.select(["name","login"]).toInfo()

Limit e offset

query.limit(10).offset(2).get()

Where

Para filtrar os dados podemos usar vários metodos encadeados.

query.where({"name":"admin,"id":1}).get()
# SELECT *  FROM users WHERE ( name = admin AND  id = 1 )

query.where({"name":"admin,"id":1}).orWhere({"id":2}).get()
# SELECT *  FROM users WHERE ( name = admin AND  id = 1 ) OR ( id = 2 )

query.whereIn("name",["admin","kass"]).get()
# SELECT * FROM users WHERE (name  IN ('admin', 'kass'))

query.whereIsNull("admin").get()
# SELECT *  FROM users WHERE ( admin IS  NULL )

query.whereIsNotNull("admin").get()
# SELECT *  FROM users WHERE ( admin IS NOT NULL )

query.whereLike("name","%kass%").get()
# SELECT *  FROM users WHERE ( name LIKE %kass% )

query.whereNotIn("name",["marcos","bee"]).get()
# SELECT *  FROM users WHERE (name NOT IN ('marcos', 'bee'))

Group e Order

Para agrupar basta passar uma string com as colunas:

query.groupBy("name, login").get()

ou uma lista de colunas:

query.groupBy(["name","login"]).get()

Ordenação, pode-se passar uma string:

query.orderBy("name asc, login desc").get()

ou um dicionário informando a coluna e a direção:

query.orderBy({"name":"asc", "login":"desc"}).get()

Insert

Insere um ou mais registros

Querier().table("users").insert({"name":"kass"})

Querier().table("users").insert([{"name":"kass"},{"name":"admin"}])

Update

Atualizando um valor.

Querier().table("users").where({"id":1}).update({"name":"ADMINISTRADOR","login":"ADMIN"})

OBS: Não esqueça de sempre utilizar a clausula *where* quando for atualizar registros.

Delete

Exclua um ou mais registros definitivamente

Querier().table("users").whereIn("id",[1,2]).delete()

SoftDelete

Para trabalhar com softDelete, ou seja, não deletar um registro e sim desativar, você somente precisará configurar a classe Querier() com o parametro softDelete e informar nele qual a coluna que representa a desativação do registro, essa coluna deverá ser do tipo datetime, geralmente a coluna se chama deleted_at.

Querier(softDelete="deleted_at").table("users").where({"id":1}).delete()

O registro é atualizado na coluna determinada com a data e hora do delete.

Com essa configuração o select será afetado, não retornando os registros em que o campo determinado não for nulo.

Querier(softDelete="deleted_at").table("users").get()
# retorna tudo menos o id 1 que esta 'deletado'

Para retornar tudo, inclusive o que foi deletado, use o método withTrashed()

Querier(softDelete="deleted_at").table("users").withTrashed().get()

Utilize o método active(), para ativar um registro anteriormente deletado com softDelete. Este método só tem efeito utilizando o withTrashed().

Querier(softDelete="deleted_at").table("users").withTrashed().active()

OBS: Não esqueça de sempre utilizar a clausula *where* quando for excluir registros.





Modelr

Classe para abstrair a classe Querier() e facilitar o uso dos dados nas tabelas, relacionamentos e informações sobre as queries de forma facilitada.

Veja a estrutura básica de um modelo:

from KassOrm import Modelr

class User(Modelr)

    __conn__ = 'api'
    __table__ = 'users'

Sendo que foi necessário fazer o import da classe Modelr e a injeção do mesmo no modelo. Duas configurações apra o modelo são: qual a conexão (conn) e qual a tabela do banco (table) que o model representa. Se não informar a conexão, ele irá pegar a conexaõ padrão (default) configurada.

Select

Pegando todos os dados

User().get()

Pegando somente o primeiro registro

User().first()

Escolhendo colunas exibir

User().select(['name','login']).get()

Pegando todos os dados filtrados

User().where({"name":"admin,"id":1}).get()

Pegando sql e parametros

# exibe a query executada
User().where({"name":"admin,"id":1}).toSql()

# exibe a query e seus parametros separados
User().where({"name":"admin,"id":1}).toInfo()

Limit e offset

User().where({"name":"admin,"id":1}).limit(10).offset(2).get()

Where

Para filtrar os dados podemos usar vários metodos encadeados.

User().where({"name":"admin,"id":1}).get()
# SELECT *  FROM users WHERE ( name = admin AND  id = 1 )

User().where({"name":"admin,"id":1}).orWhere({"id":2}).get()
# SELECT *  FROM users WHERE ( name = admin AND  id = 1 ) OR ( id = 2 )

User().whereIn("name",["admin","kass"]).get()
# SELECT * FROM users WHERE (name  IN ('admin', 'kass'))

User().whereIsNull("admin").get()
# SELECT *  FROM users WHERE ( admin IS  NULL )

User().whereIsNotNull("admin").get()
# SELECT *  FROM users WHERE ( admin IS NOT NULL )

User().whereLike("name","%kass%").get()
# SELECT *  FROM users WHERE ( name LIKE %kass% )

User().whereNotIn("name",["marcos","bee"]).get()
# SELECT *  FROM users WHERE (name NOT IN ('marcos', 'bee'))


Relacionamentos

1 para 1

Para montar seus relacionamentos, crie métodos dentro do seu modelo como abaixo.

Pensando que cada User (campo id) tem um Phone (campo user_id) (1 para 1):

from KassOrm import Modelr

class Phone(Modelr)
    __conn__ = 'api'
    __table__ = 'phones'


class User(Modelr)
    __conn__ = 'api'
    __table__ = 'users'

    def phone(self):
        return self.hasOne(Phone, "user_id","id")

Usando o relacionamento.

User().related('phone').get()

O método "related()" recebe uma string ou uma lista de strings.

Retorno do relacionamento seria:

[
    {
        "id":1,
        "name":"admin",
        "phone":{
            "id":1,
            "user_id":1,
            "number":"12334567"
        }
    }
]

Onde a chave 'phone' representa os dados do relacionamento de User com Phone.

O método "hasOne" recebe os parametros:

  • Phone => (model) modelo a se relacionar
  • user_id => (model_key) nome do campo dentro de Phone que representa o user
  • id => (local_key) identificador de User

1 para N

Agora vamos exemplificar que cada User tem muitos endereços (Address).

from KassOrm import Modelr

class Phone(Modelr)
    __conn__ = 'api'
    __table__ = 'phones'


class Address(Modelr)
    __conn__ = 'api'
    __table__ = 'addresses'


class User(Modelr)
    __conn__ = 'api'
    __table__ = 'users'

    def phone(self):
        return self.hasOne(Phone, "user_id","id")

    def addresses(self):
        return self.hasMany(Address, "user_id","id")        

Usando o relacionamento.

User().related(['phone','addresses']).get()

O método "related()" recebe uma string ou uma lista de strings. Retorno dos relacionamentos seria:

[
    {
        "id":1,
        "name":"admin",
        "phone":{
            "id":1,
            "user_id":1,
            "number":"12334567"
        },
        "addresses":[
            {
                "id":1,
                "user_id:1,
                "address":"RUA 1"
            },
            {
                "id":2,
                "user_id:1,
                "address":"RUA 2"
            },
        ]
    }
]

Onde a chave 'addresses' representa os dados do relacionamento de User com Address.

O método "hasMany" recebe os parametros:

  • Address => (model) modelo a se relacionar
  • user_id => (model_key) nome do campo dentro de Address que representa o user
  • id => (local_key) identificador de User

N para N

Para casos que há muitos para muitos, devemos usar uma tabela intermediária. Segue como deria um relacionamento de User com Permission (permissões).

from KassOrm import Modelr

class Phone(Modelr)
    __conn__ = 'api'
    __table__ = 'phones'


class Address(Modelr)
    __conn__ = 'api'
    __table__ = 'addresses'


class Permission(Modelr)
    __conn__ = 'api'
    __table__ = 'permissions'    


class User(Modelr)
    __conn__ = 'api'
    __table__ = 'users'

    def phone(self):
        return self.hasOne(Phone, "user_id","id")

    def addresses(self):
        return self.hasMany(Address, "user_id","id")   

    def permissions(self):
        return self.hasManyToMany(Permission, 'id', 'permission_id', 'users_apps_permissions', 'user_id', 'id')                

Usando o relacionamento.

User().related(['phone','addresses','permissions']).get()

O método "related()" recebe uma string ou uma lista de strings.

Retorno dos relacionamentos seria:

[
    {
        "id":1,
        "name":"admin",
        "phone":{
            "id":1,
            "user_id":1,
            "number":"12334567"
        },
        "addresses":[
            {
                "id":1,
                "user_id:1,
                "address":"RUA 1"
            },
            {
                "id":2,
                "user_id:1,
                "address":"RUA 2"
            },
        ],
        "permissions":[
            {
                "id":1,
                "name":"acesso geral"
            },            
            {
                "id":2,
                "name":"acesso a cadastrar"
            },
            {
                "id":3,
                "name":"acesso a excluir"
            }
        ]
    }
]

Onde a chave 'permissions' representa os dados do relacionamento de User com Permission.

O método "hasManyToMany" recebe os parametros:

  • Permission => (model) modelo a se relacionar
  • id => (model_key) identificador de Permission
  • permission_id => (intermediate_model_key) identificador de Permission na tabela intermediária
  • users_apps_permissions => (intermediate_table) nome da tabela intermediária
  • user_id => (intermediate_local_key) identificador de User na tabela intermediária
  • id => (local_key) identificador de User

Pegando dados da tabela intermediária

O metodo "hasManyToMany" ainda pode receber o encadeamento de "withPivot()", que pode receber uma lista de nomes dos campos a exibir da tabela intermediária, se não for passado a lista, será retornado todos os campos da tabela intermediária. Veja o exemplo:

from KassOrm import Modelr

.
.
.

class User(Modelr)
    __conn__ = 'api'
    __table__ = 'users'

    def phone(self):
        return self.hasOne(Phone, "user_id","id")

    def addresses(self):
        return self.hasMany(Address, "user_id","id")   

    def permissions(self):
        return self.hasManyToMany(Permission, 'id', 'permission_id', 'users_apps_permissions', 'user_id', 'id')->withPivot()                

Alterando o retorno da chave permissions para:

[
    {
        .
        .
        .
        "permissions":[
            {
                "id":1,
                "name":"acesso geral",
                "pivot":{
                    "user_id":1,
                    "permission_id":1,
                }
            },            
            {
                "id":2,
                "name":"acesso a cadastrar",
                "pivot":{
                    "user_id":1,
                    "permission_id":2,
                }
            },
            {
                "id":3,
                "name":"acesso a excluir",
                "pivot":{
                    "user_id":1,
                    "permission_id":3,
                }
            }
        ]
    }
]

Passando, "->withPivot(["user_id"])", somente o campo user_id seria exibido

Group e Order

Para agrupar basta passar uma string com as colunas:

User().groupBy("name, login").get()

ou uma lista de colunas:

User().groupBy(["name","login"]).get()

Ordenação, pode-se passar uma string:

User().orderBy("name asc, login desc").get()

ou um dicionário informando a coluna e a direção:

User().orderBy({"name":"asc", "login":"desc"}).get()

Insert

id = User().insert({"name":"kass"})
print(id)

ids = User().insert([{"name":"admin"},{"name":"kass"}])
print(ids)

Update

Atualizando um registro.

User().where({"id":1}).update({"name":"admin"})

OBS: Não esqueça de sempre utilizar a clausula *where* quando for atualizar registros.

Delete

Para excluir um registro utilize o método delete().

User().where({"id":1}).delete()

SoftDelete

Para trabalhar com softDelete, ou seja, não deletar um registro e sim desativar, você somente precisará configurar o seu model com a constante sofDelete e informar nele qual a coluna que representa a desativação do registro, essa coluna deverá ser do tipo datetime, geralmente a coluna se chama deleted_at.

class User(Modelr):    
   
    __sofDelete__="deleted_at"

para excluir use normal o metodo delete.

User().where({"id":1}).delete()

O registro é atualizado na coluna determinada com a data e hora do delete.

Com essa configuração o select será afetado, não retornando os registros em que o campo determinado não for nulo.

User().get()
# retorna tudo menos o registro que esta 'deletado'

Para retornar tudo, inclusive o que foi deletado, use o método withTrashed()

User().withTrashed().get()

Utilize o método active(), para ativar um registro anteriormente deletado com softDelete. Este método só terá efeito utilizando o withTrashed().

User().where({"id":1}).withTrashed().active()

OBS: Não esqueça de sempre utilizar a clausula *where* quando for excluir registros.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kassorm-1.1.5.tar.gz (17.8 kB view details)

Uploaded Source

Built Distribution

kassorm-1.1.5-py3-none-any.whl (20.6 kB view details)

Uploaded Python 3

File details

Details for the file kassorm-1.1.5.tar.gz.

File metadata

  • Download URL: kassorm-1.1.5.tar.gz
  • Upload date:
  • Size: 17.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.4 Windows/10

File hashes

Hashes for kassorm-1.1.5.tar.gz
Algorithm Hash digest
SHA256 82f75b6be43b0b5764ec2ab5cf8e85e193cd03f9ab9101805885d9e8662e8171
MD5 5e29653a23811cb9ed0ac5de958dbfbf
BLAKE2b-256 3ca04746187ec287be3b072553fa8f1cef5c71510c896c9fe06bfb4742085c09

See more details on using hashes here.

File details

Details for the file kassorm-1.1.5-py3-none-any.whl.

File metadata

  • Download URL: kassorm-1.1.5-py3-none-any.whl
  • Upload date:
  • Size: 20.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.7.1 CPython/3.11.4 Windows/10

File hashes

Hashes for kassorm-1.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 8ccef5523eb8906f06a80132d00c714f110b72b02d1cefdc89deaa88e0ff960e
MD5 e754f6f3c55c9469f94a5928d4e9a5af
BLAKE2b-256 add8d2a431282f1ee30d4bb0beb356aa6f3093e74bcd8ec309ea802970cc5b19

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page