Name
QBit::Application::Model::DBManager - Class for smart working with DB.
GitHub
https://github.com/QBitFramework/QBit-Application-Model-DBManager
Install
cpanm QBit::Application::Model::DBManager
apt-get install libqbit-application-model-dbmanager-perl (http://perlhub.ru/)
For more information. please, see code.
Package methods
init
Initialization model.
It is done:
Init fields
No arguments.
Example:
my $model = Application::Model->new(); # Application::Model based on QBit::Application::Model
# but usually this is used so
package Application;
use base qw(QBit::Application);
__Package__->set_accessors(model => {package => 'Application::Model'});
...
# after
my $model = $app->model;
model_fields
Set model fields. Save into package stash with key __MODEL_FIELDS__
Arguments:
%fields - Fields (type: hash)
Example:
package Sellers;
use base qw(QBit::Application::Model::DBManager);
__PACKAGE__->model_accessors(
db => 'Application::Model::DB', # your DB model, see QBit::Application::Model::DB
items => 'Application::Model::Items', # your model (base from QBit::Application::Model::DBManager)
);
__PACKAGE__->model_fields(
id => {
pk => TRUE, # primary key for this model
db => 'sellers', # this field is from the table
default => TRUE, # this field returns if fields were not requested
},
caption => {
db => 'sellers', # this field is from the table
default => TRUE, # this field returns if fields were not requested
i18n => TRUE, # this field depends on current locale, (in DB this field i18n too)
check_rights => 'sellers_view_field__caption',
# your right for "caption", see check_rights from QBit::Application
# Try not to use this key.
},
id_with_caption => {
depends_on => [qw(id caption)], # this field depends on "id" and "caption"
get => sub {
my $fields = shift; # object QBit::Application::Model::DBManager::_Utils::Fields
# access to model: $fields->model
my $row = shift; # hash from db: {id => 1, caption => 'Happy Milkman'}
return $row->{'id'} . ': ' . $row->{'caption'};
}
},
id_with_caption_db => {
db => 'sellers',
db_expr => {CONCAT => ['id', \': ', 'caption']}, # see QBit::Application::Model::DB::Query
},
name => {
# relation "one to one". Use it if you want use join
db => 'users', # this field is from the table, but the tables are different
},
items => {
# relation "one to one", "one to many" or "many to many"
depends_on => [qw(id)],
get => sub {
my $fields = shift; # object QBit::Application::Model::DBManager::_Utils::Fields
my $row = shift; # hash from db: {id => 1}
# $fields->{'__ITEMS__'} created in pre_process_fields
return $fields->{'__ITEMS__'}{$row->{'id'}} // [];
}
}
);
# returns query (class: QBit::Application::Model::DB::Query)
sub query {
my ($self, %opts) = @_;
my $filter = $self->db->filter($opts{'filter'});
unless ($self->check_rights('sellers_view_all')) {
my $cur_user = $self->cur_user();
$filter->and({user_id => $cur_user->{'id'}};
}
my $query = $self->db->query->select(
table => $self->db->sellers,
fields => $opts{'fields'}->get_db_fields('sellers'), # returns db expression for fields with "db" = 'sellers'
filter => $filter
);
my $users_fields = $opts{'fields'}->get_db_fields('users');
# join users only if needed (field "name" was requested)
$query->join(
table => $self->db->users,
fields => $users_fields,
) if %$users_fields;
return $query;
}
# used for dictionaries
sub pre_process_fields {
my $self = shift; # model
my $fields = shift; # object QBit::Application::Model::DBManager::_Utils::Fields
my $result = shift; # data from db
if ($fields->need('items')) {
# gets items only if needed (field "items" was requested)
my $items = $self->items->get_all(
fields => [qw(id seller_id caption)],
filter => {seller_id => [map {$_->{'id'}} @$result]}, # key "id" exists because fields "items" depends on "id"
);
# create dictionaries {<SELLER_ID> => <ITEM>}
$fields->{'__ITEMS__'} = {map {$_->{'seller_id'} => $_} @$items};
}
}
TRUE;
# in your code
my $sellers = $app->sellers->get_all(fields => [qw(id id_with_caption_db name items)]);
#$sellers = [
# {
# id => 1,
# id_with_caption_db => '1: Happy Milkman',
# name => 'Petr Ivanovich',
# items => [
# {
# id => 1,
# seller_id => 1,
# caption => 'milk'
# },
# {
# id => 2,
# seller_id => 1,
# caption => 'cheese'
# },
# ],
# }
#]
init_fields
Initialization fields. Used after calling model_fields in run time a code
No arguments.
Example:
$model->model_fields(...);
$model->init_fields();
model_filter
Set model filters. Save into package stash with key __DB_FILTER__
Types: namespace (QBit::Application::Model::DBManager::Filter)
boolean
dictionary
multistate
number
subfilter
text
Arguments:
%opts - Options (type: hash)
db_accessor - name db accessor
fields - filter fields
Example:
__PACKAGE__->model_filter(
db_accessor => 'db', # your db accessor
fields => {
id => {type => 'number'},
caption => {type => 'text'},
active => {type => 'boolean'},
product => {
type => 'dictionary',
values => sub {
[
{id => 1, label => gettext('Milk')},
{id => 2, label => gettext('Cheese')},
];
},
}
multistate => {type => 'multistate'},
# you can filtered by field from other model
user => {
type => 'subfilter',
model_accessor => 'users', # accessor related model
field => 'user_id', # field from this model
fk_field => 'id', # field from model "users"
},
},
);
# in your code
my $items = $app->model->get_all(
filter => [
'OR',
[
['id', '=', 1],
['caption', 'LIKE', 'Nike'],
['active', '=', 1],
['product', '=', [1, 2]],
['multistate', '=', 'approved and working'],
['user', 'MATCH', ['login', '=', 'ChuckNorris']] # login is a filter in model "users"
]
]
);
get_model_fields
Returns a model fields.
No arguments.
Return value: $model_fields (type: ref of a hash)
Example:
my $model_fields = $app->model->get_model_fields(); # getter for method "model_fields"
get_all
Returns model items.
Arguments:
%opts - Options (type: hash)
fields
returns "id" and "caption" my $data = $app->model->get_all(fields => [qw(id caption)]); # returns fields with key "default" my $data = $app->model->get_all(); # return all fields my $data = $app->model->get_all(fields => ['*']);
filter - see QBit::Application::Model::DB::Query. Unlike filters from the database, model filters can not use field names and scalars are used without reference.
# mysql: name = caption # db: ['name', '=', 'caption'] # model: no way # mysql: id = 12 # db: ['id', '=', \12] # model: ['id', '=', 12] my $data = $app->model->get_all(filter => {id => 1});
distinct - unique rows from table
my $data = $app->model->get_all(fields => [qw(caption)], distinct => TRUE);
for_update - get lock
# get my $data = $app->model->get_all(fields => [qw(id)], filter => ["caption", "LIKE", "milk"]}, for_update => TRUE); # update $app->db->table->edit($app->db->filter({id => [map {$_->{'id'}} @$data]}), {caption => 'Milk'});
order_by - set order
my $data = $app->model->get_all( fields => [qw(caption)], order_by => [ 'caption', # asc [ 'price', # field 1 # order: 0 - asc, 1 - desc ] ] );
limit
my $data = $app->model->get_all(limit => 100);
offset
my $data = $app->model->get_all(limit => 100, offset => 1000);
calc_rows
my $data = $app->model->get_all(limit => 100, calc_rows => TRUE); my $all_data = $app->model->found_rows(); # 1_000_000
all_locales
my $data = $app->model->get_all(fields => [qw(id caption)], all_locales => TRUE); #$data = [ # { # id => 1, # caption => { # ru => 'Веселый молочник', # en => 'Happy Milkman', # }, # }, # ... #]
Return value: Data (type: ref of a array)
Example:
my $data = $app->model->get_all(
fields => [qw(id caption)],
filter => ['OR', [
['id', '=', 10],
['caption', '=', 'milk']
]],
limit => 100,
offset => 10_000,
order_by => ['caption']
);
found_rows
Returns count of a rows.
No arguments.
Return value: $found_rows (type: scalar or undef)
Example:
my $data = $app->model->get_all(limit => 3, calc_rows => TRUE);
my $found_rows = $app->model->found_rows();
last_fields
Returns a last fields was requested.
No arguments.
Return value: $last_fields (type: scalar or undef)
Example:
my $data = $app->model->get_all(fields => [qw(id caption)]);
my $last_fields = $app->model->last_fields();
# $last_fields = {
# id => '',
# caption => '',
# };
get
Returns row by primary key.
Arguments:
$pk - primary key (type: scalar or hash)
%opts - options (type: hash; see get_all)
Return value: Row (type: ref of a hash or undef)
Example:
my $item = $app->model->get(1, fields => [qw(id caption)]);
# or
my $item = $app->model->get({id => 1}, fields => [qw(id caption)]);
get_pk_fields
Returns primary keys.
No arguments.
Return value: fields (type: ref of a array)
Example:
my $pk = $app->model->get_pk_fields(); # ['id']
pre_process_fields
used for dictionaries.
No arguments.
Return value: undef
Example:
# see method: model_fields
$app->model->pre_process_fields();