使用Perl 6和DBIish的数据访问层

时间:2018-04-02 18:46:39

标签: sql database oop dbi perl6

我正在尝试设计一个"数据访问层"我的Perl 6预算申请。目标是让用户在SQLite数据库中存储各种购买,我的应用程序将生成各种报告,告知用户消费习惯。

然而,我在做一个"正确的"数据访问层。事实上,我想知道它是否值得为这个应用程序。无论如何,我想学习如何正确地设计它"面向对象"。

我理解我希望我的类成为表,并且类的属性对应于表中的行。就目前而言,我的代码根本不使用类属性,但仍然可以正常工作。

有没有理由使用类属性?我有looked up a few resources,其中大部分都是Java语言,我很难翻译成Perl 6.这似乎不必要地复杂,但我怀疑这是因为我不明白这种设计模式的原因

  1 #!/usr/bin/env perl6
  2
  3 use v6;
  4 use DBIish;
  5
  6 constant DB = 'budgetpro.sqlite3';
  7 my $dbh = DBIish.connect('SQLite', database => DB);
  8
  9 $dbh.do('drop table if exists Essential');
 10
 11 sub create-schema {
 12     $dbh.do(qq:to/SCHEMA/);
 13         create table if not exists Essential(
 14             id      integer primary key not null,
 15             name    varchar not null,
 16             price   numeric(5,2) not null,
 17             quant   integer not null,
 18             desc    varchar not null,
 19             date    timestamp default (datetime('now'))
 20         );
 21     SCHEMA
 22 }
 23
 24 create-schema;
 25
 26 class Item {
 27     has $!table = 'Essential';
 28     has $.name is rw;
 29     has $.price is rw;
 30     has $.quant is rw;
 31     has Str $.desc;
 32
 33     method insert($name, $price, $quant, $desc) {
 34         my $sth = $dbh.prepare(qq:to/INSERT/);
 35             insert into $!table (name, price, quant, desc) values (?,?,?,?)
 36         INSERT
 37         $sth.execute($name, $price, $quant, $desc);
 38     }
 39
 40     multi method select-all {
 41         my $sth = $dbh.prepare(qq:to/SELECT/);
 42             select * from $!table
 43         SELECT
 44         $sth.execute;
 45         $sth.allrows(:array-of-hash);
 46     }
 47
 48     multi method select-all($begin, $end) {
 49         my $sth = $dbh.prepare(qq:to/SELECT/);
 50             select * from $!table where date >= ? and date <= ?
 51         SELECT
 52         $sth.execute($begin, $end);
 53         $sth.allrows(:array-of-hash);
 54     }
 55
 56
 57     # Needs accurate implementation
 58     multi method total-cost($table, $begin?, $end?) {
 59         sub total-price {
 60             my $sth = $dbh.prepare(qq:to/SUM/);
 61                 select sum(price) from $table
 62             SUM
 63             $sth.execute;
 64             $sth.allrows[0];
 65         }
 66         sub total-quant {
 67             my $sth = $dbh.prepare(qq:to/SUM/);
 68                 select sum(quant) from $table
 69             SUM
 70             $sth.execute;
 71             $sth.allrows[0];
 72         }
 73         return (total-quant[0] * total-price[0]);
 74     }
 75
 76     multi method total-cost($table, $begin, $end) {
 77         my $sth = $dbh.prepare(qq:to/SUM/);
 78             select sum(price) from $table where date >= ? and date <= ?
 79         SUM
 80         $sth.execute($begin, $end);
 81         $sth.allrows;
 82     }
 83 }
 84
 85 class Essential is Item {}
 86
 87 class Savings is Item {}
 88
 89 class Personal is Item {}

编辑:使用示例 -

 my ($name, $price, $quant, $desc) = 'Apple', 0.99, 2, 'Delicious apple';
 my $item = Essential.new;
 $item.insert($name, $price, $quant, $desc);
 say $item.select-all;

输出: ({date => 2018-04-02 18:59:46, desc => A delicious apple, id => 1, name => Apple, price => 5.99, quant => 2})

2 个答案:

答案 0 :(得分:7)

  

但是,我在做一个“正确的”数据访问层时遇到了麻烦。事实上,我想知道这个应用程序是否值得。

这在很大程度上取决于您的应用程序,以及它触及数据库的位置。

  

我理解我希望我的类成为表,并且类的属性对应于表中的行。

这将是一个非常不寻常的映射。您希望该类表示该表,并且该类的每个实例(对象)都是一行。属性对应于表中的列。

然后你有某种 session 对象封装了数据库句柄,然后你可以编写类似

的东西
my $item = Item.new(id => 42, name => 'something', price => 240.01, quant => 1, ...);
# to add it to the database, do something like:
$session.add($item);

但是,适当的面向对象数据层抽象并不止于此。你怎么查询表?你会如何在多个表上编写查询? SQLAlchemy(一个Python ORM)实现了一个转换为Perl 6的API,如下所示:

my $query = $session.query(Item).join(OtherClass).filter(Item.quantity > 10).filter(OtherClass.id <= 25);
for $query.all -> $item {
    # do something with $item here
}

我不知道Perl 6 ORM可以很好地支持这些事情,所以实现它可能需要做很多工作,而且可能不值得为一个小项目付出努力。

但是如果你想了解一个设计良好的动态语言对象关系映射器(ORM)的样子,我强烈推荐SQLAlchemy(Python)或DBIx :: Class(Perl 5)。

答案 1 :(得分:1)

你可以尝试Quicky,一个仍然有点原始的对象关系管理器,但至少可以省去在代码中插入SQL语句的麻烦。最近同一位作者发布了another ORM, koos,这似乎更加精致。它肯定会加速数据库的开发。